Source Code Cross Referenced for CodeContext.java in  » Scripting » jacl » org » codehaus » janino » 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 » Scripting » jacl » org.codehaus.janino 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Janino - An embedded Java[TM] compiler
003:         *
004:         * Copyright (c) 2006, Arno Unkrig
005:         * All rights reserved.
006:         *
007:         * Redistribution and use in source and binary forms, with or without
008:         * modification, are permitted provided that the following conditions
009:         * are met:
010:         *
011:         *    1. Redistributions of source code must retain the above copyright
012:         *       notice, this list of conditions and the following disclaimer.
013:         *    2. Redistributions in binary form must reproduce the above
014:         *       copyright notice, this list of conditions and the following
015:         *       disclaimer in the documentation and/or other materials
016:         *       provided with the distribution.
017:         *    3. The name of the author may not be used to endorse or promote
018:         *       products derived from this software without specific prior
019:         *       written permission.
020:         *
021:         * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
022:         * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
023:         * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
024:         * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
025:         * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
026:         * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
027:         * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
028:         * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
029:         * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
030:         * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
031:         * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
032:         */
033:
034:        package org.codehaus.janino;
035:
036:        import java.io.*;
037:        import java.util.*;
038:
039:        import org.codehaus.janino.util.ClassFile;
040:
041:        /**
042:         * The context of the compilation of a function (constructor or method). Manages generation of
043:         * byte code, the exception table, generation of line number tables, allocation of local variables,
044:         * determining of stack size and local variable table size and flow analysis.
045:         */
046:        public class CodeContext {
047:            private static final boolean DEBUG = false;
048:
049:            private static final int INITIAL_SIZE = 100;
050:            private static final int SIZE_INCREMENT = 128;
051:
052:            private/*final*/ClassFile classFile;
053:
054:            private short maxStack;
055:            private short maxLocals;
056:            private byte[] code;
057:            private/*final*/Offset beginning;
058:            private/*final*/Inserter end;
059:            private Inserter currentInserter;
060:            private/*final*/List exceptionTableEntries; // ExceptionTableEntry
061:
062:            /**
063:             * Create an empty "Code" attribute.
064:             */
065:            public CodeContext(ClassFile classFile) {
066:                this .classFile = classFile;
067:
068:                this .maxStack = 0;
069:                this .maxLocals = 0;
070:                this .code = new byte[CodeContext.INITIAL_SIZE];
071:                this .beginning = new Offset();
072:                this .end = new Inserter();
073:                this .currentInserter = this .end;
074:                this .exceptionTableEntries = new ArrayList();
075:
076:                this .beginning.offset = 0;
077:                this .end.offset = 0;
078:                this .beginning.next = this .end;
079:                this .end.prev = this .beginning;
080:            }
081:
082:            public ClassFile getClassFile() {
083:                return this .classFile;
084:            }
085:
086:            /**
087:             * Allocate space for a local variable of the given size (1 or 2)
088:             * on the local variable array.
089:             *
090:             * As a side effect, the "max_locals" field of the "Code" attribute
091:             * is updated.
092:             *
093:             * The only way to deallocate local variables is to
094:             * {@link #saveLocalVariables()} and later {@link
095:             * #restoreLocalVariables()}.
096:             */
097:            public short allocateLocalVariable(short size // 1 or 2
098:            ) {
099:                short res = this .localVariableArrayLength;
100:                this .localVariableArrayLength += size;
101:                if (this .localVariableArrayLength > this .maxLocals) {
102:                    this .maxLocals = this .localVariableArrayLength;
103:                }
104:
105:                return res;
106:            }
107:
108:            /**
109:             * Remember the current size of the local variables array.
110:             */
111:            public void saveLocalVariables() {
112:                this .savedLocalVariableArrayLengths.push(new Short(
113:                        this .localVariableArrayLength));
114:            }
115:
116:            /**
117:             * Restore the previous size of the local variables array.
118:             */
119:            public void restoreLocalVariables() {
120:                this .localVariableArrayLength = ((Short) this .savedLocalVariableArrayLengths
121:                        .pop()).shortValue();
122:            }
123:
124:            private static final byte UNEXAMINED = -1;
125:            private static final byte INVALID_OFFSET = -2;
126:
127:            /**
128:             * 
129:             * @param dos
130:             * @param lineNumberTableAttributeNameIndex 0 == don't generate a "LineNumberTable" attribute
131:             * @throws IOException
132:             */
133:            protected void storeCodeAttributeBody(DataOutputStream dos,
134:                    short lineNumberTableAttributeNameIndex) throws IOException {
135:                dos.writeShort(this .maxStack); // max_stack
136:                dos.writeShort(this .maxLocals); // max_locals
137:                dos.writeInt(0xffff & this .end.offset); // code_length
138:                dos.write(this .code, 0, 0xffff & this .end.offset); // code
139:                dos.writeShort(this .exceptionTableEntries.size()); // exception_table_length
140:                for (int i = 0; i < this .exceptionTableEntries.size(); ++i) { // exception_table
141:                    ExceptionTableEntry exceptionTableEntry = (ExceptionTableEntry) this .exceptionTableEntries
142:                            .get(i);
143:                    dos.writeShort(exceptionTableEntry.startPC.offset);
144:                    dos.writeShort(exceptionTableEntry.endPC.offset);
145:                    dos.writeShort(exceptionTableEntry.handlerPC.offset);
146:                    dos.writeShort(exceptionTableEntry.catchType);
147:                }
148:
149:                List attributes = new ArrayList(); // ClassFile.AttributeInfo
150:
151:                // Add "LineNumberTable" attribute.
152:                if (lineNumberTableAttributeNameIndex != 0) {
153:                    List lnt = new ArrayList();
154:                    for (Offset o = this .beginning; o != null; o = o.next) {
155:                        if (o instanceof  LineNumberOffset) {
156:                            lnt
157:                                    .add(new ClassFile.LineNumberTableAttribute.Entry(
158:                                            o.offset,
159:                                            ((LineNumberOffset) o).lineNumber));
160:                        }
161:                    }
162:                    ClassFile.LineNumberTableAttribute.Entry[] lnte = (ClassFile.LineNumberTableAttribute.Entry[]) lnt
163:                            .toArray(new ClassFile.LineNumberTableAttribute.Entry[lnt
164:                                    .size()]);
165:                    attributes.add(new ClassFile.LineNumberTableAttribute(
166:                            lineNumberTableAttributeNameIndex, // attributeNameIndex
167:                            lnte // lineNumberTableEntries
168:                            ));
169:                }
170:
171:                dos.writeShort(attributes.size()); // attributes_count
172:                for (Iterator it = attributes.iterator(); it.hasNext();) { // attributes;
173:                    ClassFile.AttributeInfo attribute = (ClassFile.AttributeInfo) it
174:                            .next();
175:                    attribute.store(dos);
176:                }
177:            }
178:
179:            /**
180:             * Checks the code for consistency; updates the "maxStack" member.
181:             *
182:             * Notice: On inconsistencies, a "RuntimeException" is thrown (KLUDGE).
183:             */
184:            public void flowAnalysis(String functionName) {
185:                byte[] stackSizes = new byte[0xffff & this .end.offset];
186:                Arrays.fill(stackSizes, CodeContext.UNEXAMINED);
187:
188:                // Analyze flow from offset zero.
189:                this .flowAnalysis(functionName, this .code, // code
190:                        0xffff & this .end.offset, // codeSize
191:                        0, // offset
192:                        0, // stackSize
193:                        stackSizes // stackSizes
194:                        );
195:
196:                // Analyze flow from exception handler entry points.
197:                int analyzedExceptionHandlers = 0;
198:                while (analyzedExceptionHandlers != this .exceptionTableEntries
199:                        .size()) {
200:                    for (int i = 0; i < this .exceptionTableEntries.size(); ++i) {
201:                        ExceptionTableEntry exceptionTableEntry = (ExceptionTableEntry) this .exceptionTableEntries
202:                                .get(i);
203:                        if (stackSizes[0xffff & exceptionTableEntry.startPC.offset] != CodeContext.UNEXAMINED) {
204:                            this 
205:                                    .flowAnalysis(
206:                                            functionName,
207:                                            this .code, // code
208:                                            0xffff & this .end.offset, // codeSize
209:                                            0xffff & exceptionTableEntry.handlerPC.offset, // offset
210:                                            stackSizes[0xffff & exceptionTableEntry.startPC.offset] + 1, // stackSize
211:                                            stackSizes // stackSizes
212:                                    );
213:                            ++analyzedExceptionHandlers;
214:                        }
215:                    }
216:                }
217:
218:                // Check results and determine maximum stack size.
219:                this .maxStack = 0;
220:                for (int i = 0; i < stackSizes.length; ++i) {
221:                    byte ss = stackSizes[i];
222:                    if (ss == CodeContext.UNEXAMINED) {
223:                        if (CodeContext.DEBUG) {
224:                            System.out.println(functionName
225:                                    + ": Unexamined code at offset " + i);
226:                            return;
227:                        } else {
228:                            throw new RuntimeException(functionName
229:                                    + ": Unexamined code at offset " + i);
230:                        }
231:                    }
232:                    if (ss > this .maxStack)
233:                        this .maxStack = ss;
234:                }
235:            }
236:
237:            private void flowAnalysis(String functionName, byte[] code, // Bytecode
238:                    int codeSize, // Size
239:                    int offset, // Current PC
240:                    int stackSize, // Stack size on entry
241:                    byte[] stackSizes // Stack sizes in code
242:            ) {
243:                for (;;) {
244:                    if (CodeContext.DEBUG)
245:                        System.out.println("Offset = " + offset
246:                                + ", stack size = " + stackSize);
247:
248:                    // Check current bytecode offset.
249:                    if (offset < 0 || offset >= codeSize)
250:                        throw new RuntimeException(functionName
251:                                + ": Offset out of range");
252:
253:                    // Have we hit an area that has already been analyzed?
254:                    byte css = stackSizes[offset];
255:                    if (css == stackSize)
256:                        return; // OK.
257:                    if (css == CodeContext.INVALID_OFFSET)
258:                        throw new RuntimeException(functionName
259:                                + ": Invalid offset");
260:                    if (css != CodeContext.UNEXAMINED) {
261:                        if (CodeContext.DEBUG) {
262:                            System.err.println(functionName
263:                                    + ": Operand stack inconsistent at offset "
264:                                    + offset + ": Previous size " + css
265:                                    + ", now " + stackSize);
266:                            return;
267:                        } else {
268:                            throw new RuntimeException(functionName
269:                                    + ": Operand stack inconsistent at offset "
270:                                    + offset + ": Previous size " + css
271:                                    + ", now " + stackSize);
272:                        }
273:                    }
274:                    stackSizes[offset] = (byte) stackSize;
275:
276:                    // Analyze current opcode.
277:                    byte opcode = code[offset];
278:                    int operandOffset = offset + 1;
279:                    short props;
280:                    if (opcode == Opcode.WIDE) {
281:                        opcode = code[operandOffset++];
282:                        props = Opcode.WIDE_OPCODE_PROPERTIES[0xff & opcode];
283:                    } else {
284:                        props = Opcode.OPCODE_PROPERTIES[0xff & opcode];
285:                    }
286:                    if (props == Opcode.INVALID_OPCODE)
287:                        throw new RuntimeException(functionName
288:                                + ": Invalid opcode " + (0xff & opcode)
289:                                + " at offset " + offset);
290:
291:                    switch (props & Opcode.SD_MASK) {
292:
293:                    case Opcode.SD_M4:
294:                    case Opcode.SD_M3:
295:                    case Opcode.SD_M2:
296:                    case Opcode.SD_M1:
297:                    case Opcode.SD_P0:
298:                    case Opcode.SD_P1:
299:                    case Opcode.SD_P2:
300:                        stackSize += (props & Opcode.SD_MASK) - Opcode.SD_P0;
301:                        break;
302:
303:                    case Opcode.SD_0:
304:                        stackSize = 0;
305:                        break;
306:
307:                    case Opcode.SD_GETFIELD:
308:                        --stackSize;
309:                        /* FALL THROUGH */
310:                    case Opcode.SD_GETSTATIC:
311:                        stackSize += this 
312:                                .determineFieldSize((short) ((code[operandOffset] << 8) + (0xff & code[operandOffset + 1])));
313:                        break;
314:
315:                    case Opcode.SD_PUTFIELD:
316:                        --stackSize;
317:                        /* FALL THROUGH */
318:                    case Opcode.SD_PUTSTATIC:
319:                        stackSize -= this 
320:                                .determineFieldSize((short) ((code[operandOffset] << 8) + (0xff & code[operandOffset + 1])));
321:                        break;
322:
323:                    case Opcode.SD_INVOKEVIRTUAL:
324:                    case Opcode.SD_INVOKESPECIAL:
325:                    case Opcode.SD_INVOKEINTERFACE:
326:                        --stackSize;
327:                        /* FALL THROUGH */
328:                    case Opcode.SD_INVOKESTATIC:
329:                        stackSize -= this 
330:                                .determineArgumentsSize((short) ((code[operandOffset] << 8) + (0xff & code[operandOffset + 1])));
331:                        break;
332:
333:                    case Opcode.SD_MULTIANEWARRAY:
334:                        stackSize -= code[operandOffset + 2] - 1;
335:                        break;
336:
337:                    default:
338:                        throw new RuntimeException(functionName
339:                                + ": Invalid stack delta");
340:                    }
341:
342:                    if (stackSize < 0) {
343:                        String msg = this .classFile.getThisClassName() + '.'
344:                                + functionName
345:                                + ": Operand stack underrun at offset "
346:                                + offset;
347:                        if (CodeContext.DEBUG) {
348:                            System.err.println(msg);
349:                            return;
350:                        } else {
351:                            throw new RuntimeException(msg);
352:                        }
353:                    }
354:
355:                    if (stackSize > Byte.MAX_VALUE) {
356:                        String msg = this .classFile.getThisClassName() + '.'
357:                                + functionName
358:                                + ": Operand stack overflow at offset "
359:                                + offset;
360:                        if (CodeContext.DEBUG) {
361:                            System.err.println(msg);
362:                            return;
363:                        } else {
364:                            throw new RuntimeException(msg);
365:                        }
366:                    }
367:
368:                    switch (props & Opcode.OP1_MASK) {
369:
370:                    case 0:
371:                        ;
372:                        break;
373:
374:                    case Opcode.OP1_SB:
375:                    case Opcode.OP1_UB:
376:                    case Opcode.OP1_CP1:
377:                    case Opcode.OP1_LV1:
378:                        ++operandOffset;
379:                        break;
380:
381:                    case Opcode.OP1_SS:
382:                    case Opcode.OP1_CP2:
383:                    case Opcode.OP1_LV2:
384:                        operandOffset += 2;
385:                        break;
386:
387:                    case Opcode.OP1_BO2:
388:                        if (CodeContext.DEBUG) {
389:                            System.out.println("Offset = " + offset);
390:                            System.out.println("Operand offset = "
391:                                    + operandOffset);
392:                            System.out.println(code[operandOffset]);
393:                            System.out.println(code[operandOffset + 1]);
394:                        }
395:                        this 
396:                                .flowAnalysis(
397:                                        functionName,
398:                                        code,
399:                                        codeSize,
400:                                        offset
401:                                                + (((code[operandOffset++]) << 8) + ((0xff & code[operandOffset++]))),
402:                                        stackSize, stackSizes);
403:                        break;
404:
405:                    case Opcode.OP1_JSR:
406:                        if (CodeContext.DEBUG) {
407:                            System.out.println("Offset = " + offset);
408:                            System.out.println("Operand offset = "
409:                                    + operandOffset);
410:                            System.out.println(code[operandOffset]);
411:                            System.out.println(code[operandOffset + 1]);
412:                        }
413:                        int targetOffset = offset
414:                                + (((code[operandOffset++]) << 8) + ((0xff & code[operandOffset++])));
415:                        if (stackSizes[targetOffset] == CodeContext.UNEXAMINED) {
416:                            this .flowAnalysis(functionName, code, codeSize,
417:                                    targetOffset, stackSize + 1, stackSizes);
418:                        }
419:                        break;
420:
421:                    case Opcode.OP1_BO4:
422:                        this 
423:                                .flowAnalysis(
424:                                        functionName,
425:                                        code,
426:                                        codeSize,
427:                                        offset
428:                                                + (((code[operandOffset++]) << 24)
429:                                                        + ((0xff & code[operandOffset++]) << 16)
430:                                                        + ((0xff & code[operandOffset++]) << 8) + ((0xff & code[operandOffset++]))),
431:                                        stackSize, stackSizes);
432:                        break;
433:
434:                    case Opcode.OP1_LOOKUPSWITCH:
435:                        while ((operandOffset & 3) != 0)
436:                            ++operandOffset;
437:                        this 
438:                                .flowAnalysis(
439:                                        functionName,
440:                                        code,
441:                                        codeSize,
442:                                        offset
443:                                                + (((code[operandOffset++]) << 24)
444:                                                        + ((0xff & code[operandOffset++]) << 16)
445:                                                        + ((0xff & code[operandOffset++]) << 8) + ((0xff & code[operandOffset++]))),
446:                                        stackSize, stackSizes);
447:                        int npairs = (((code[operandOffset++]) << 24)
448:                                + ((0xff & code[operandOffset++]) << 16)
449:                                + ((0xff & code[operandOffset++]) << 8) + ((0xff & code[operandOffset++])));
450:                        for (int i = 0; i < npairs; ++i) {
451:                            operandOffset += 4;
452:                            this 
453:                                    .flowAnalysis(
454:                                            functionName,
455:                                            code,
456:                                            codeSize,
457:                                            offset
458:                                                    + (((code[operandOffset++]) << 24)
459:                                                            + ((0xff & code[operandOffset++]) << 16)
460:                                                            + ((0xff & code[operandOffset++]) << 8) + ((0xff & code[operandOffset++]))),
461:                                            stackSize, stackSizes);
462:                        }
463:                        break;
464:
465:                    case Opcode.OP1_TABLESWITCH:
466:                        while ((operandOffset & 3) != 0)
467:                            ++operandOffset;
468:                        this 
469:                                .flowAnalysis(
470:                                        functionName,
471:                                        code,
472:                                        codeSize,
473:                                        offset
474:                                                + (((code[operandOffset++]) << 24)
475:                                                        + ((0xff & code[operandOffset++]) << 16)
476:                                                        + ((0xff & code[operandOffset++]) << 8) + ((0xff & code[operandOffset++]))),
477:                                        stackSize, stackSizes);
478:                        int low = (((code[operandOffset++]) << 24)
479:                                + ((0xff & code[operandOffset++]) << 16)
480:                                + ((0xff & code[operandOffset++]) << 8) + ((0xff & code[operandOffset++])));
481:                        int hi = (((code[operandOffset++]) << 24)
482:                                + ((0xff & code[operandOffset++]) << 16)
483:                                + ((0xff & code[operandOffset++]) << 8) + ((0xff & code[operandOffset++])));
484:                        for (int i = low; i <= hi; ++i) {
485:                            this 
486:                                    .flowAnalysis(
487:                                            functionName,
488:                                            code,
489:                                            codeSize,
490:                                            offset
491:                                                    + (((code[operandOffset++]) << 24)
492:                                                            + ((0xff & code[operandOffset++]) << 16)
493:                                                            + ((0xff & code[operandOffset++]) << 8) + ((0xff & code[operandOffset++]))),
494:                                            stackSize, stackSizes);
495:                        }
496:                        break;
497:
498:                    default:
499:                        throw new RuntimeException(functionName
500:                                + ": Invalid OP1");
501:                    }
502:
503:                    switch (props & Opcode.OP2_MASK) {
504:
505:                    case 0:
506:                        ;
507:                        break;
508:
509:                    case Opcode.OP2_SB:
510:                        ++operandOffset;
511:                        break;
512:
513:                    case Opcode.OP2_SS:
514:                        operandOffset += 2;
515:                        break;
516:
517:                    default:
518:                        throw new RuntimeException(functionName
519:                                + ": Invalid OP2");
520:                    }
521:
522:                    switch (props & Opcode.OP3_MASK) {
523:
524:                    case 0:
525:                        ;
526:                        break;
527:
528:                    case Opcode.OP3_SB:
529:                        ++operandOffset;
530:                        break;
531:
532:                    default:
533:                        throw new RuntimeException(functionName
534:                                + ": Invalid OP3");
535:                    }
536:
537:                    Arrays.fill(stackSizes, offset + 1, operandOffset,
538:                            CodeContext.INVALID_OFFSET);
539:
540:                    if ((props & Opcode.NO_FALLTHROUGH) != 0)
541:                        return;
542:                    offset = operandOffset;
543:                }
544:            }
545:
546:            /**
547:             * Fix up all offsets.
548:             */
549:            public void fixUp() {
550:                for (Offset o = this .beginning; o != this .end; o = o.next) {
551:                    if (o instanceof  FixUp)
552:                        ((FixUp) o).fixUp();
553:                }
554:            }
555:
556:            public void relocate() {
557:                for (int i = 0; i < this .relocatables.size(); ++i) {
558:                    ((Relocatable) this .relocatables.get(i)).relocate();
559:                }
560:            }
561:
562:            /**
563:             * Analyse the descriptor of the Fieldref and return its size.
564:             */
565:            private int determineFieldSize(short idx) {
566:                ClassFile.ConstantFieldrefInfo cfi = (ClassFile.ConstantFieldrefInfo) this .classFile
567:                        .getConstantPoolInfo(idx);
568:                ClassFile.ConstantNameAndTypeInfo cnati = (ClassFile.ConstantNameAndTypeInfo) this .classFile
569:                        .getConstantPoolInfo(cfi.getNameAndTypeIndex());
570:                ClassFile.ConstantUtf8Info cui = (ClassFile.ConstantUtf8Info) this .classFile
571:                        .getConstantPoolInfo(cnati.getDescriptorIndex());
572:                return Descriptor.size(cui.getString());
573:            }
574:
575:            /**
576:             * Analyse the descriptor of the Methodref and return the sum of the
577:             * arguments' sizes minus the return value's size.
578:             */
579:            private int determineArgumentsSize(short idx) {
580:                ClassFile.ConstantPoolInfo cpi = this .classFile
581:                        .getConstantPoolInfo(idx);
582:                ClassFile.ConstantNameAndTypeInfo nat = (ClassFile.ConstantNameAndTypeInfo) this .classFile
583:                        .getConstantPoolInfo(cpi instanceof  ClassFile.ConstantInterfaceMethodrefInfo ? ((ClassFile.ConstantInterfaceMethodrefInfo) cpi)
584:                                .getNameAndTypeIndex()
585:                                : ((ClassFile.ConstantMethodrefInfo) cpi)
586:                                        .getNameAndTypeIndex());
587:                ClassFile.ConstantUtf8Info cui = (ClassFile.ConstantUtf8Info) this .classFile
588:                        .getConstantPoolInfo(nat.getDescriptorIndex());
589:                String desc = cui.getString();
590:
591:                if (desc.charAt(0) != '(')
592:                    throw new RuntimeException(
593:                            "Method descriptor does not start with \"(\"");
594:                int i = 1;
595:                int res = 0;
596:                for (;;) {
597:                    switch (desc.charAt(i++)) {
598:                    case ')':
599:                        return res - Descriptor.size(desc.substring(i));
600:                    case 'B':
601:                    case 'C':
602:                    case 'F':
603:                    case 'I':
604:                    case 'S':
605:                    case 'Z':
606:                        res += 1;
607:                        break;
608:                    case 'D':
609:                    case 'J':
610:                        res += 2;
611:                        break;
612:                    case '[':
613:                        res += 1;
614:                        while (desc.charAt(i) == '[')
615:                            ++i;
616:                        if ("BCFISZDJ".indexOf(desc.charAt(i)) != -1) {
617:                            ++i;
618:                            break;
619:                        }
620:                        if (desc.charAt(i) != 'L')
621:                            throw new RuntimeException(
622:                                    "Invalid char after \"[\"");
623:                        ++i;
624:                        while (desc.charAt(i++) != ';')
625:                            ;
626:                        break;
627:                    case 'L':
628:                        res += 1;
629:                        while (desc.charAt(i++) != ';')
630:                            ;
631:                        break;
632:                    default:
633:                        throw new RuntimeException("Invalid method descriptor");
634:                    }
635:                }
636:            }
637:
638:            /**
639:             * Inserts a sequence of bytes at the current insertion position. Creates
640:             * {@link LineNumberOffset}s as necessary.
641:             * 
642:             * @param lineNumber The line number that corresponds to the byte code, or -1
643:             * @param b
644:             */
645:            public void write(short lineNumber, byte[] b) {
646:                if (b.length == 0)
647:                    return;
648:
649:                INSERT_LINE_NUMBER_OFFSET: if (lineNumber != -1) {
650:                    Offset o;
651:                    for (o = this .currentInserter.prev; o != this .beginning; o = o.prev) {
652:                        if (o instanceof  LineNumberOffset) {
653:                            if (((LineNumberOffset) o).lineNumber == lineNumber)
654:                                break INSERT_LINE_NUMBER_OFFSET;
655:                            break;
656:                        }
657:                    }
658:                    LineNumberOffset lno = new LineNumberOffset(
659:                            this .currentInserter.offset, lineNumber);
660:                    lno.prev = this .currentInserter.prev;
661:                    lno.next = this .currentInserter;
662:                    this .currentInserter.prev.next = lno;
663:                    this .currentInserter.prev = lno;
664:                }
665:
666:                int ico = 0xffff & this .currentInserter.offset;
667:                if ((0xffff & this .end.offset) + b.length <= this .code.length) {
668:                    System.arraycopy(this .code, ico, this .code, ico + b.length,
669:                            (0xffff & this .end.offset) - ico);
670:                } else {
671:                    byte[] oldCode = this .code;
672:                    this .code = new byte[this .code.length
673:                            + CodeContext.SIZE_INCREMENT];
674:                    if (this .code.length >= 0xffff)
675:                        throw new RuntimeException("Code attribute in class \""
676:                                + this .classFile.getThisClassName()
677:                                + "\" grows beyond 64 KB");
678:                    System.arraycopy(oldCode, 0, this .code, 0, ico);
679:                    System.arraycopy(oldCode, ico, this .code, ico + b.length,
680:                            (0xffff & this .end.offset) - ico);
681:                }
682:                System.arraycopy(b, 0, this .code, ico, b.length);
683:                for (Offset o = this .currentInserter; o != null; o = o.next)
684:                    o.offset += b.length;
685:            }
686:
687:            public void writeShort(short lineNumber, int v) {
688:                this 
689:                        .write(lineNumber, new byte[] { (byte) (v >> 8),
690:                                (byte) v });
691:            }
692:
693:            public void writeBranch(short lineNumber, int opcode,
694:                    final Offset dst) {
695:                this .relocatables.add(new Branch(this .newOffset(), dst));
696:                this .write(lineNumber, new byte[] { (byte) opcode, -1, -1 });
697:            }
698:
699:            private class Branch extends Relocatable {
700:                public Branch(Offset source, Offset destination) {
701:                    this .source = source;
702:                    this .destination = destination;
703:                }
704:
705:                public void relocate() {
706:                    if (this .destination.offset == Offset.UNSET)
707:                        throw new RuntimeException(
708:                                "Cannot relocate branch to unset destination offset");
709:                    int offset = this .destination.offset - this .source.offset;
710:                    if (offset > Short.MAX_VALUE || offset < Short.MIN_VALUE)
711:                        throw new RuntimeException("Branch offset out of range");
712:                    byte[] ba = new byte[] { (byte) (offset >> 8),
713:                            (byte) offset };
714:                    System.arraycopy(ba, 0, CodeContext.this .code,
715:                            (0xffff & this .source.offset) + 1, 2);
716:                }
717:
718:                private final Offset source;
719:                private final Offset destination;
720:            }
721:
722:            public void writeOffset(short lineNumber, Offset src,
723:                    final Offset dst) {
724:                this .relocatables.add(new OffsetBranch(this .newOffset(), src,
725:                        dst));
726:                this .write(lineNumber, new byte[] { -1, -1, -1, -1 });
727:            }
728:
729:            private class OffsetBranch extends Relocatable {
730:                public OffsetBranch(Offset where, Offset source,
731:                        Offset destination) {
732:                    this .where = where;
733:                    this .source = source;
734:                    this .destination = destination;
735:                }
736:
737:                public void relocate() {
738:                    if (this .source.offset == Offset.UNSET
739:                            || this .destination.offset == Offset.UNSET)
740:                        throw new RuntimeException(
741:                                "Cannot relocate offset branch to unset destination offset");
742:                    int offset = this .destination.offset - this .source.offset;
743:                    byte[] ba = new byte[] { (byte) (offset >> 24),
744:                            (byte) (offset >> 16), (byte) (offset >> 8),
745:                            (byte) offset };
746:                    System.arraycopy(ba, 0, CodeContext.this .code,
747:                            0xffff & this .where.offset, 4);
748:                }
749:
750:                private final Offset where, source, destination;
751:            }
752:
753:            public Offset newOffset() {
754:                Offset o = new Offset();
755:                o.set();
756:                return o;
757:            }
758:
759:            /**
760:             * Allocate an {@link Inserter}, set it to the current offset, and
761:             * insert it before the current offset.
762:             *
763:             * In clear text, this means that you can continue writing to the
764:             * "Code" attribute, then {@link #pushInserter(CodeContext.Inserter)} the
765:             * {@link Inserter}, then write again (which inserts bytes into the
766:             * "Code" attribute at the previously remembered position), and then
767:             * {@link #popInserter()}.
768:             */
769:            public Inserter newInserter() {
770:                Inserter i = new Inserter();
771:                i.set();
772:                return i;
773:            }
774:
775:            /**
776:             * Remember the current {@link Inserter}, then replace it with the
777:             * new one.
778:             */
779:            public void pushInserter(Inserter ins) {
780:                if (ins.nextInserter != null)
781:                    throw new RuntimeException(
782:                            "An Inserter can only be pushed once at a time");
783:                ins.nextInserter = this .currentInserter;
784:                this .currentInserter = ins;
785:            }
786:
787:            /**
788:             * Replace the current {@link Inserter} with the remembered one (see
789:             * {@link #pushInserter(CodeContext.Inserter)}).
790:             */
791:            public void popInserter() {
792:                Inserter ni = this .currentInserter.nextInserter;
793:                if (ni == null)
794:                    throw new RuntimeException("Code inserter stack underflow");
795:                this .currentInserter.nextInserter = null; // Mark it as "unpushed".
796:                this .currentInserter = ni;
797:            }
798:
799:            /**
800:             * A class that represents an offset within a "Code" attribute.
801:             *
802:             * The concept of an "offset" is that if one writes into the middle of
803:             * a "Code" attribute, all offsets behind the insertion point are
804:             * automatically shifted.
805:             */
806:            public class Offset {
807:                short offset = Offset.UNSET;
808:                Offset prev = null, next = null;
809:                final static short UNSET = -1;
810:
811:                /**
812:                 * Set this "Offset" to the offset of the current inserter; insert
813:                 * this "Offset" before the current inserter.
814:                 */
815:                public void set() {
816:                    if (this .offset != Offset.UNSET)
817:                        throw new RuntimeException(
818:                                "Cannot \"set()\" Offset more than once");
819:
820:                    this .offset = CodeContext.this .currentInserter.offset;
821:                    this .prev = CodeContext.this .currentInserter.prev;
822:                    this .next = CodeContext.this .currentInserter;
823:
824:                    this .prev.next = this ;
825:                    this .next.prev = this ;
826:                }
827:
828:                public final CodeContext getCodeContext() {
829:                    return CodeContext.this ;
830:                }
831:
832:                public String toString() {
833:                    return CodeContext.this .classFile.getThisClassName() + ": "
834:                            + (0xffff & this .offset);
835:                }
836:            }
837:
838:            /**
839:             * Add another entry to the "exception_table" of this code attribute (see JVMS 4.7.3).
840:             * @param startPC
841:             * @param endPC
842:             * @param handlerPC
843:             * @param catchTypeFD
844:             */
845:            public void addExceptionTableEntry(Offset startPC, Offset endPC,
846:                    Offset handlerPC, String catchTypeFD // null == "finally" clause
847:            ) {
848:                this .exceptionTableEntries.add(new ExceptionTableEntry(startPC,
849:                        endPC, handlerPC, catchTypeFD == null ? (short) 0
850:                                : this .classFile
851:                                        .addConstantClassInfo(catchTypeFD)));
852:            }
853:
854:            /**
855:             * Representation of an entry in the "exception_table" of a "Code" attribute (see JVMS
856:             * 4.7.3).
857:             */
858:            private static class ExceptionTableEntry {
859:                public ExceptionTableEntry(Offset startPC, Offset endPC,
860:                        Offset handlerPC, short catchType) {
861:                    this .startPC = startPC;
862:                    this .endPC = endPC;
863:                    this .handlerPC = handlerPC;
864:                    this .catchType = catchType;
865:                }
866:
867:                private final Offset startPC, endPC, handlerPC;
868:                private final short catchType; // 0 == "finally" clause
869:            }
870:
871:            /**
872:             * A class that implements an insertion point into a "Code"
873:             * attribute.
874:             */
875:            public class Inserter extends Offset {
876:                private Inserter nextInserter = null; // null == not in "currentInserter" stack
877:            }
878:
879:            public class LineNumberOffset extends Offset {
880:                private final short lineNumber;
881:
882:                public LineNumberOffset(short offset, short lineNumber) {
883:                    this .lineNumber = lineNumber;
884:                    this .offset = offset;
885:                }
886:            }
887:
888:            private abstract class Relocatable {
889:                public abstract void relocate();
890:            }
891:
892:            private short localVariableArrayLength = 0;
893:            private final Stack savedLocalVariableArrayLengths = new Stack();
894:            private final List relocatables = new ArrayList();
895:
896:            /**
897:             * A throw-in interface that marks {@link CodeContext.Offset}s
898:             * as "fix-ups": During the execution of
899:             * {@link CodeContext#fixUp}, all "fix-ups" are invoked and
900:             * can do last touches to the code attribute.
901:             * <p>
902:             * This is currently used for inserting the "padding bytes" into the
903:             * TABLESWITCH and LOOKUPSWITCH instructions.
904:             */
905:            public interface FixUp {
906:                void fixUp();
907:            }
908:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.