Source Code Cross Referenced for Injector.java in  » IDE-Netbeans » cvsclient » org » netbeans » lib » profiler » instrumentation » 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 » IDE Netbeans » cvsclient » org.netbeans.lib.profiler.instrumentation 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003:         *
004:         * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005:         *
006:         * The contents of this file are subject to the terms of either the GNU
007:         * General Public License Version 2 only ("GPL") or the Common
008:         * Development and Distribution License("CDDL") (collectively, the
009:         * "License"). You may not use this file except in compliance with the
010:         * License. You can obtain a copy of the License at
011:         * http://www.netbeans.org/cddl-gplv2.html
012:         * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013:         * specific language governing permissions and limitations under the
014:         * License.  When distributing the software, include this License Header
015:         * Notice in each file and include the License file at
016:         * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
017:         * particular file as subject to the "Classpath" exception as provided
018:         * by Sun in the GPL Version 2 section of the License file that
019:         * accompanied this code. If applicable, add the following below the
020:         * License Header, with the fields enclosed by brackets [] replaced by
021:         * your own identifying information:
022:         * "Portions Copyrighted [year] [name of copyright owner]"
023:         *
024:         * Contributor(s):
025:         * The Original Software is NetBeans. The Initial Developer of the Original
026:         * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
027:         * Microsystems, Inc. All Rights Reserved.
028:         *
029:         * If you wish your version of this file to be governed by only the CDDL
030:         * or only the GPL Version 2, indicate your decision by adding
031:         * "[Contributor] elects to include this software in this distribution
032:         * under the [CDDL or GPL Version 2] license." If you do not indicate a
033:         * single choice of license, a recipient has the option to distribute
034:         * your version of this file under either the CDDL, the GPL Version 2 or
035:         * to extend the choice of license to its licensees as provided above.
036:         * However, if you add GPL Version 2 code and therefore, elected the GPL
037:         * Version 2 license, then the option applies only if the new code is
038:         * made subject to such option by the copyright holder.
039:         */
040:
041:        package org.netbeans.lib.profiler.instrumentation;
042:
043:        import org.netbeans.lib.profiler.classfile.ClassInfo;
044:        import org.netbeans.lib.profiler.client.RuntimeProfilingPoint;
045:        import java.util.Stack;
046:
047:        /**
048:         * Base class for a number of classes performing concrete method instrumentation injections. Contains core functionality
049:         * for injection of arbitrary bytecodes at a given location in a method and subsequent rewriting of bytecodes. Also
050:         * supports appending bytecodes to the existing bytecodes, and extending the method's exception table.
051:         *
052:         * @author Misha Dmitriev
053:         */
054:        public abstract class Injector extends SingleMethodScaner {
055:            //~ Inner Classes ------------------------------------------------------------------------------------------------------------
056:
057:            //-------------------------------------- Helper classes ------------------------------------------
058:            private abstract static class ChangeItem {
059:                //~ Instance fields ------------------------------------------------------------------------------------------------------
060:
061:                int bci;
062:
063:                //~ Constructors ---------------------------------------------------------------------------------------------------------
064:
065:                ChangeItem(int bci) {
066:                    this .bci = bci;
067:                }
068:
069:                //~ Methods --------------------------------------------------------------------------------------------------------------
070:
071:                abstract void handleCodeChange(Injector r);
072:
073:                void relocate(int breakBCI, int delta) {
074:                    if (bci > breakBCI) {
075:                        bci += delta;
076:                    }
077:                }
078:            }
079:
080:            private static class ChangeJumpWiden extends ChangeItem {
081:                //~ Instance fields ------------------------------------------------------------------------------------------------------
082:
083:                int delta; // New length of instruction at bci
084:
085:                //~ Constructors ---------------------------------------------------------------------------------------------------------
086:
087:                ChangeJumpWiden(int bci, int delta) {
088:                    super (bci);
089:                    this .delta = delta;
090:                }
091:
092:                //~ Methods --------------------------------------------------------------------------------------------------------------
093:
094:                // Callback to do instruction
095:                void handleCodeChange(Injector r) {
096:                    r.handleJumpWiden(bci, delta);
097:                }
098:            }
099:
100:            private static class ChangeSwitchPadding extends ChangeItem {
101:                //~ Instance fields ------------------------------------------------------------------------------------------------------
102:
103:                boolean isLookupSwitch;
104:                int padding;
105:
106:                //~ Constructors ---------------------------------------------------------------------------------------------------------
107:
108:                ChangeSwitchPadding(int bci, int padding, boolean isLookupSwitch) {
109:                    super (bci);
110:                    this .padding = padding;
111:                    this .isLookupSwitch = isLookupSwitch;
112:                }
113:
114:                //~ Methods --------------------------------------------------------------------------------------------------------------
115:
116:                // Callback to do instruction
117:                void handleCodeChange(Injector r) {
118:                    r.handleSwitchPadding(bci, padding, isLookupSwitch);
119:                }
120:            }
121:
122:            //~ Static fields/initializers -----------------------------------------------------------------------------------------------
123:
124:            private static final int MAX_SHORT = ((1 << 15) - 1);
125:            private static final int MIN_SHORT = (-(1 << 15));
126:
127:            // Increment to possible stack depth -- two instrumentation arguments
128:            private static final int STACK_INCREMENT = 2;
129:            private static Stack changes = new Stack(); // Stack of additional changes to bytecodes that may be caused by our main injection change
130:            private static byte[] _overwrite = new byte[3]; // Stores overwritten bytes for shrunken instructions
131:
132:            // The following array is re-used,to avoid excessive object allocations - which means that the class is not multi thread safe
133:            private static byte[] reusableExcTable = new byte[100];
134:
135:            // ProfilerRuntime.profilePointHit instrumentation
136:            private static final byte[] injProfilePointHitCode = new byte[] {
137:                    opc_sipush, 0, 0, (byte) opc_invokestatic, 0, 0, 0, 0 };
138:            private static final int injProfilePointHitIDCodeIdx = 1;
139:            private static final int injProfilePointHitMethodIdx = 4;
140:
141:            //~ Instance fields ----------------------------------------------------------------------------------------------------------
142:
143:            protected byte[] exceptionTable; // Current updateable copy of exception table (what is in MethodInfo Code attribute after exception_table_length)
144:            protected int baseCPoolCount; // The "base" constant pool index, after which the set of entries containing the calls that
145:            // we inject, plus supporting entries, are located.
146:            protected int excTableEntryCount;
147:            protected int maxLocals;
148:            protected int maxStack;
149:            protected int origBytecodesLength;
150:            protected int origExcTableEntryCount;
151:            private boolean changeTypeIsInjectNewInstr;
152:            private boolean injectionBindsToFollowingInstruction;
153:
154:            //~ Constructors -------------------------------------------------------------------------------------------------------------
155:
156:            // ---------------------------------------- Protected methods -------------------------------------------------
157:            protected Injector() {
158:            }
159:
160:            /**
161:             * Creates a new Injector for the specified method. Subsequently one can call injectCodeAndRewrite() and other
162:             * methods below as many times as needed.
163:             */
164:            protected Injector(ClassInfo clazz, int methodIdx) {
165:                super (clazz, methodIdx);
166:                origBytecodesLength = bytecodesLength;
167:                maxStack = getU2(origMethodInfo, bytecodesStartIdx - 8);
168:                maxLocals = getU2(origMethodInfo, bytecodesStartIdx - 6);
169:                initExceptionTable();
170:                origExcTableEntryCount = excTableEntryCount;
171:            }
172:
173:            //~ Methods ------------------------------------------------------------------------------------------------------------------
174:
175:            // ------------------------------------ Public abstract interface ---------------------------------------------
176:
177:            /** In concrete subclasses, should do all the real work on method instrumentation and return the updated packed methodInfo */
178:            public abstract byte[] instrumentMethod();
179:
180:            protected void addExceptionTableEntry(int startPC, int endPC,
181:                    int handlerPC, int typeCPIndex) {
182:                int pos = excTableEntryCount * 8;
183:                putU2(exceptionTable, pos, startPC);
184:                putU2(exceptionTable, pos + 2, endPC);
185:                putU2(exceptionTable, pos + 4, handlerPC);
186:                putU2(exceptionTable, pos + 6, typeCPIndex);
187:                excTableEntryCount++;
188:            }
189:
190:            protected void appendCode(byte[] appendedBytes,
191:                    int appendedBytesCount) {
192:                System.arraycopy(appendedBytes, 0, bytecodes, bytecodesLength,
193:                        appendedBytesCount);
194:                bytecodesLength += appendedBytesCount;
195:            }
196:
197:            protected byte[] createPackedMethodInfo() {
198:                int diff = (bytecodesLength - origBytecodesLength)
199:                        + ((excTableEntryCount - origExcTableEntryCount) * 8);
200:                byte[] ret = new byte[origMethodInfo.length + diff];
201:                System.arraycopy(origMethodInfo, 0, ret, 0, bytecodesStartIdx);
202:                System.arraycopy(bytecodes, 0, ret, bytecodesStartIdx,
203:                        bytecodesLength);
204:
205:                int attrLength = getU4(origMethodInfo, bytecodesStartIdx - 12);
206:                attrLength += diff;
207:                putU4(ret, bytecodesStartIdx - 12, attrLength); // Patch the attribute_length in Code attribute
208:                putU4(ret, bytecodesStartIdx - 4, bytecodesLength); // Patch the code_length in Code attribute
209:                System.arraycopy(origMethodInfo, bytecodesStartIdx
210:                        + origBytecodesLength, ret, bytecodesStartIdx
211:                        + bytecodesLength, origMethodInfo.length
212:                        - bytecodesStartIdx - origBytecodesLength);
213:
214:                int excTableOldStart = clazz
215:                        .getExceptionTableStartOffsetInMethodInfo(methodIdx);
216:                int excTableNewStart = excTableOldStart
217:                        + (bytecodesLength - origBytecodesLength);
218:                int excTableOldLen = origExcTableEntryCount * 8;
219:                int excTableNewLen = excTableEntryCount * 8;
220:
221:                if (excTableOldLen != excTableNewLen) {
222:                    System.arraycopy(ret, excTableNewStart + excTableOldLen,
223:                            ret, excTableNewStart + excTableNewLen,
224:                            origMethodInfo.length - excTableOldStart
225:                                    - excTableOldLen);
226:                    putU2(ret, excTableNewStart, excTableEntryCount);
227:                }
228:
229:                System.arraycopy(exceptionTable, 0, ret, excTableNewStart + 2,
230:                        excTableNewLen);
231:
232:                // FIXME: need to update linenumber table and localvariable table as well
233:                putU2(ret, bytecodesStartIdx - 8, maxStack + STACK_INCREMENT);
234:                putU2(ret, bytecodesStartIdx - 6, maxLocals);
235:
236:                return ret;
237:            }
238:
239:            /**
240:             * Injects the specified raw bytes array at the specified location.
241:             * The last parameter indicates whether the injected code should be bound to the following (if true) or previous (if false) bytecode
242:             * instruction. When binding to the following instruction, all jumps that target that instruction will target the injected code after
243:             * rewriting. When binding to the previous instruction x, all jumps that target the instruction x+1 will still target that instruction
244:             * after rewriting (i.e. not target our injected code, as in the first case).
245:             */
246:            protected void injectCodeAndRewrite(byte[] injectedBytes,
247:                    int injectedBytesCount, int injectionPos,
248:                    boolean injectionBindsToFollowingInstruction) {
249:                this .injectionBindsToFollowingInstruction = injectionBindsToFollowingInstruction;
250:                relocateCode(injectionPos, 0, injectedBytesCount, true);
251:                // Copy the bytecodes to inject into the method
252:                System.arraycopy(injectedBytes, 0, bytecodes, injectionPos,
253:                        injectedBytesCount);
254:                // Now handle the additional changes that could be caused by the injection
255:                handleCodeChanges();
256:            }
257:
258:            /**
259:             * Profiling points MUST BE already SORTED by BCI in ascending order and only relevant to this method.
260:             *
261:             * @param points sorted array of Profiling points
262:             * @param ppHitCPMethodIdx
263:             */
264:            protected void insertProfilingPoints(
265:                    RuntimeProfilingPoint[] points, int ppHitCPMethodIdx) {
266:                for (int i = 0; i < points.length; i++) {
267:                    RuntimeProfilingPoint point = points[i];
268:                    assert (i == 0)
269:                            || (point.getBci() >= points[i - 1].getBci());
270:
271:                    int ppbci = point.getBci()
272:                            + (i * injProfilePointHitCode.length);
273:                    injectProfilePointHit(point, ppbci, ppHitCPMethodIdx);
274:                    maxStack = Math.max(maxStack, 4);
275:                }
276:            }
277:
278:            /** Called by the ChangeJumpWiden class */
279:            void handleJumpWiden(int bci, int delta) {
280:                int ilen = rcInstrLen(bci);
281:
282:                if (ilen != 3) {
283:                    return; // Request already handled
284:                    //Above: assert(code_at(bci) == Bytecodes::_goto_w || code_at(bci) == Bytecodes::_jsr_w, "sanity check");
285:                }
286:
287:                //assert(ilen == 3, "check length");
288:                relocateCode(bci, 3, 2, false);
289:
290:                int bc = bytecodes[bci] & 0xff;
291:
292:                switch (bc) {
293:                case opc_goto:
294:                    bytecodes[bci] = (byte) opc_goto_w;
295:
296:                    break;
297:                case opc_jsr:
298:                    bytecodes[bci] = (byte) opc_jsr_w;
299:
300:                    break;
301:                default:
302:                    System.err
303:                            .println("*** Profiler Engine: error - should not reach here in handleJumpWiden!"); // NOI18N
304:                }
305:
306:                // If it's a forward jump, add 2 for the widening.
307:                if (delta > 0) {
308:                    delta += 2;
309:                }
310:
311:                putInt(bci + 1, delta);
312:            }
313:
314:            /** If a change item is recorded for bci, with the same is_lookup_switch flag value, returns the associated padding, else -1. */
315:            private int getOrigSwitchPadding(int bci, boolean isLookupSwitch) {
316:                for (int k = 0; k < changes.size(); k++) {
317:                    ChangeItem ci = (ChangeItem) changes.elementAt(k);
318:
319:                    if (ci instanceof  ChangeSwitchPadding) {
320:                        ChangeSwitchPadding csp = (ChangeSwitchPadding) ci;
321:
322:                        if ((csp.isLookupSwitch == isLookupSwitch)
323:                                && (csp.bci == bci)) {
324:                            return csp.padding;
325:                        }
326:                    }
327:                }
328:
329:                return -1;
330:            }
331:
332:            /**
333:             * The current instruction at bci is a jump; one of its offsets starts at "offset" and is a short if isShort is true,
334:             * and an integer otherwise.  If the jump crosses breakBCI, change the span of the jump by delta.
335:             */
336:            private void changeJump(int bci, int offset, boolean isShort,
337:                    int breakBCI, int delta) {
338:                int bciDelta = (isShort) ? getShort(offset) : getInt(offset);
339:                int targ = bci + bciDelta;
340:
341:                boolean doRewrite = false;
342:
343:                // Injection of a completely new instruction and widening of an existing instruction should be handled differently
344:                if (changeTypeIsInjectNewInstr) {
345:                    if (breakBCI == 0) {
346:                        return; // No jump to the code injected at offset 0 can be made in the rewrited code
347:                        // The most reliable way to verify the correctness of the statements below, is to draw a picture, something like
348:                        // 1 a
349:                        //     <--- breakBCI = 2
350:                        // 2 b
351:                        //     <--- breakBCI = 3
352:                        // 3 goto
353:                        //     <--- breakBCI = 4
354:                        // 4 c
355:                        // 5 d
356:                        //
357:                        // and then consider all the combinations of bci = 3 with breakBCI = 2, 3, 4 and targ = 1,2,4,5 - what should happen in each case.
358:                        // For example:
359:                        // bci = 3, breakBCI = 2, injectionBindsToFollowingInstruction = true
360:                        // targ = 1 - should rewrite jump argument
361:                        // targ = 2 - should rewrite jump argument (because we will need to jump to the injected code, rather than old instruction at b at 2)
362:                        // targ = 4, 5 - don't need to rewrite jump argument
363:                        // ... and so on
364:                    }
365:
366:                    if (injectionBindsToFollowingInstruction) {
367:                        if (((bci < breakBCI) && (targ > breakBCI))
368:                                || ((bci >= breakBCI) && (targ <= breakBCI))) {
369:                            doRewrite = true;
370:                        }
371:                    } else { // Injected code binds to previous instruction, e.g. the traceObjAlloc() call that follows a constructor call
372:
373:                        if (((bci < breakBCI) && (targ >= breakBCI))
374:                                || ((bci >= breakBCI) && (targ < breakBCI))) {
375:                            doRewrite = true;
376:                        }
377:                    }
378:                } else {
379:                    if (((bci <= breakBCI) && (targ > breakBCI))
380:                            || ((bci >= breakBCI) && (targ < breakBCI))) {
381:                        doRewrite = true;
382:                    }
383:                }
384:
385:                if (doRewrite) {
386:                    int newDelta = (bciDelta > 0) ? (bciDelta + delta)
387:                            : (bciDelta - delta);
388:
389:                    if (isShort
390:                            && ((newDelta > MAX_SHORT) || (newDelta < MIN_SHORT))) {
391:                        changes.push(new ChangeJumpWiden(bci, newDelta));
392:                    } else if (isShort) {
393:                        putShort(offset, (short) newDelta);
394:                    } else {
395:                        putInt(offset, newDelta);
396:                    }
397:                }
398:            }
399:
400:            /** Changes all jumps crossing breakBCI by delta.  May enqueue things on the changes stack */
401:            private void changeJumps(int breakBCI, int delta) {
402:                int bci = 0;
403:                int bc;
404:
405:                // Now, adjust any affected instructions.
406:                while (bci < bytecodesLength) {
407:                    bc = (bytecodes[bci] & 0xFF);
408:
409:                    if (((bc >= opc_ifeq) && (bc <= opc_if_acmpne))
410:                            || (bc == opc_ifnull) || (bc == opc_ifnonnull)
411:                            || (bc == opc_goto) || (bc == opc_jsr)) {
412:                        changeJump(bci, bci + 1, true, breakBCI, delta);
413:                    } else {
414:                        switch (bc) {
415:                        case opc_goto_w:
416:                        case opc_jsr_w:
417:                            changeJump(bci, bci + 1, false, breakBCI, delta);
418:
419:                            break;
420:                        case opc_tableswitch:
421:                        case opc_lookupswitch: {
422:                            int recPad = getOrigSwitchPadding(bci,
423:                                    (bc != opc_tableswitch));
424:                            int oldPad = (recPad != -1) ? recPad
425:                                    : (align(bci + 1) - (bci + 1));
426:
427:                            if (bci > breakBCI) {
428:                                int new_bci = bci + delta;
429:                                int newPad = align(new_bci + 1) - (new_bci + 1);
430:
431:                                // Do we need to check the padding?
432:                                if (newPad != oldPad) {
433:                                    if (recPad == -1) {
434:                                        changes.push(new ChangeSwitchPadding(
435:                                                bci, oldPad,
436:                                                (bc != opc_tableswitch)));
437:                                    }
438:                                }
439:                            }
440:
441:                            // Then the rest, which depends on the kind of switch.
442:                            if (bc == opc_tableswitch) {
443:                                changeJump(bci, bci + 1 + oldPad, false,
444:                                        breakBCI, delta);
445:
446:                                // We cannot use the Bytecode_tableswitch abstraction, since the padding might not be correct.
447:                                int lo = getInt(bci + 1 + oldPad + (4 * 1));
448:                                int hi = getInt(bci + 1 + oldPad + (4 * 2));
449:                                int n = hi - lo + 1;
450:
451:                                for (int k = 0; k < n; k++) {
452:                                    changeJump(bci, bci + 1 + oldPad
453:                                            + (4 * (k + 3)), false, breakBCI,
454:                                            delta);
455:                                }
456:
457:                                // Special next-bci calculation here...
458:                                bci += (1 + oldPad + ((n + 3) * 4));
459:
460:                                continue;
461:                            } else {
462:                                changeJump(bci, bci + 1 + oldPad, false,
463:                                        breakBCI, delta);
464:
465:                                // We cannot use the Bytecode_lookupswitch abstraction, since the padding might not be correct.
466:                                int npairs = getInt(bci + 1 + oldPad + (4 * 1));
467:
468:                                for (int k = 0; k < npairs; k++) {
469:                                    changeJump(bci, bci + 1 + oldPad
470:                                            + (4 * (2 + (2 * k) + 1)), false,
471:                                            breakBCI, delta);
472:                                }
473:
474:                                // Special next-bci calculation here...
475:                                bci += (1 + oldPad + ((2 + (npairs * 2)) * 4));
476:
477:                                continue;
478:                            }
479:                        }
480:                        default:
481:                            break;
482:                        }
483:                    }
484:
485:                    bci += opcodeLength(bci);
486:                }
487:            }
488:
489:            //--------------------------------------- Private implementation -------------------------------------------
490:            private void handleCodeChanges() {
491:                while (!changes.empty()) {
492:                    // Inv: everything is aligned.
493:                    ChangeItem ci = (ChangeItem) changes.pop();
494:                    ci.handleCodeChange(this );
495:                }
496:            }
497:
498:            /** Handle lookup/table switch instructions.  Called be ChangeSwitchPad class */
499:            private void handleSwitchPadding(int bci, int oldPad,
500:                    boolean isLookupSwitch) {
501:                int ilen = rcInstrLen(bci);
502:                int newPad = align(bci + 1) - (bci + 1);
503:                int padDelta = newPad - oldPad;
504:
505:                if (padDelta != 0) {
506:                    int len;
507:
508:                    if (!isLookupSwitch) {
509:                        int low = getInt(bci + 1 + oldPad + 4);
510:                        int high = getInt(bci + 1 + oldPad + 8);
511:                        len = high - low + 1 + 3; // 3 for default, hi, lo.
512:                    } else {
513:                        int npairs = getInt(bci + 1 + oldPad + 4);
514:                        len = (npairs * 2) + 2; // 2 for default, npairs.
515:                    }
516:
517:                    // Because "relocateCode" does a "changeJumps" loop, which parses instructions to determine their length,
518:                    // we need to call that before messing with the current instruction.  Since it may also overwrite the current
519:                    // instruction when moving down, remember the possibly overwritten part.
520:                    relocateCode(bci, ilen, padDelta, false); // Relocate the code following the instruction...
521:
522:                    if (padDelta < 0) { // Move the shrunken instruction down.
523:                        System.arraycopy(bytecodes, bci + 1 + oldPad,
524:                                bytecodes, bci + 1 + newPad, (len * 4)
525:                                        + padDelta);
526:                        System.arraycopy(_overwrite, 0, bytecodes, bci + 1
527:                                + newPad + (len * 4) + padDelta, -padDelta);
528:                    } else { // Move the expanded instruction up.
529:                        System.arraycopy(bytecodes, bci + 1 + oldPad,
530:                                bytecodes, bci + 1 + newPad, len * 4);
531:                    }
532:                }
533:            }
534:
535:            private void initExceptionTable() {
536:                int startOfs = clazz
537:                        .getExceptionTableStartOffsetInMethodInfo(methodIdx);
538:                excTableEntryCount = getU2(origMethodInfo, startOfs);
539:
540:                int len = excTableEntryCount * 8;
541:
542:                if (reusableExcTable.length < (len + 40)) {
543:                    reusableExcTable = new byte[(len * 2) + 40]; // Can add at least 8*5 = 40 entries.
544:                }
545:
546:                System.arraycopy(origMethodInfo, startOfs + 2,
547:                        reusableExcTable, 0, len);
548:                exceptionTable = reusableExcTable;
549:            }
550:
551:            private void injectProfilePointHit(RuntimeProfilingPoint point,
552:                    int bci, int ppHitCPMethodIdx) {
553:                // Prepare the profilePointHit(char id, char flags) code packet that is to be injected
554:                putU2(injProfilePointHitCode, injProfilePointHitMethodIdx,
555:                        ppHitCPMethodIdx + baseCPoolCount);
556:                putU2(injProfilePointHitCode, injProfilePointHitIDCodeIdx,
557:                        point.getId());
558:
559:                injectCodeAndRewrite(injProfilePointHitCode,
560:                        injProfilePointHitCode.length, bci, true);
561:            }
562:
563:            /**
564:             * We need a special instruction size method, since lookupswitches and tableswitches might not be
565:             * properly aligned during relocation
566:             */
567:            private int rcInstrLen(int bci) {
568:                int bc = bytecodes[bci] & 0xFF;
569:
570:                switch (bc) {
571:                // In the case of switch instructions, see if we have the original padding recorded.
572:                case opc_tableswitch:
573:                case opc_lookupswitch: {
574:                    int pad = getOrigSwitchPadding(bci,
575:                            (bc == opc_lookupswitch));
576:
577:                    if (pad == -1) {
578:                        return opcodeLength(bci);
579:                    }
580:
581:                    // Otherwise, depends on the switch type.
582:                    switch (bc) {
583:                    case opc_tableswitch: {
584:                        int lo = getInt(bci + 1 + pad + (4 * 1));
585:                        int hi = getInt(bci + 1 + pad + (4 * 2));
586:                        int n = hi - lo + 1;
587:
588:                        return 1 + pad + (4 * (3 + n));
589:                    }
590:                    case opc_lookupswitch: {
591:                        int npairs = getInt(bci + 1 + pad + (4 * 1));
592:
593:                        return 1 + pad + (4 * (2 + (2 * npairs)));
594:                    }
595:                    }
596:                }
597:                }
598:
599:                return opcodeLength(bci);
600:            }
601:
602:            /**
603:             * The input is interpreted depending on the injectNewInstr flag value.
604:             * If it's false, instruction at bci, whose size is iLen, is changing size by delta.
605:             * If it's true, we inject some instructions bytes of length delta at bci.
606:             * Reallocate, move code, recalculate jumps, and enqueue more change items as necessary.
607:             * Note that currently it's assumed that delta is a multiple of 4 - in this way we avoid additional problems with changed
608:             * paddings in 'switch' instructions.
609:             */
610:            private void relocateCode(int bci, int iLen, int delta,
611:                    boolean injectNewInstr) {
612:                changeTypeIsInjectNewInstr = injectNewInstr; // Other methods need to know whether we are injecting or widening an instruction
613:
614:                // Change jumps before doing the copying; this routine requires aligned switches. If we inject something in
615:                // the very beginning of the method, changing jumps is not needed.
616:                if (bci > 0) {
617:                    changeJumps(bci, delta);
618:                }
619:
620:                // In case we have shrunken a tableswitch/lookupswitch statement, we store the last
621:                // bytes that get overwritten. We have to copy the bytes after the changeJumps method
622:                // has been called, since it is likely to update last offset in a tableswitch/lookupswitch
623:                if (delta < 0) {
624:                    //assert(delta>=-3, "we cannot overwrite more than 3 bytes");
625:                    System.arraycopy(bytecodes, bci + iLen + delta, _overwrite,
626:                            0, -delta);
627:                }
628:
629:                int nextBCI = bci + iLen; // Needed for instruction widening; ok for injection, since iLen == 0 in that case
630:                System.arraycopy(bytecodes, nextBCI, bytecodes,
631:                        nextBCI + delta, bytecodesLength - nextBCI);
632:                bytecodesLength += delta;
633:
634:                updateExceptionTable(bci, delta);
635:
636:                // We currently don't support the following updates - they are used only by debuggers.
637:                // updateLineNumberTable(injectionPos, delta);
638:                // updateLocalVariableTable(injectionPos, delta);
639:                // updateLocalVariableTypeTable(injectionPos, delta);
640:
641:                // Relocate the bcis of changes in the pending change stack
642:                for (int j = 0; j < changes.size(); j++) {
643:                    ChangeItem ci = (ChangeItem) changes.elementAt(j);
644:                    ci.relocate(bci, delta);
645:                }
646:            }
647:
648:            private void updateExceptionTable(int injectionPos,
649:                    int injectedBytesCount) {
650:                int pos = 0;
651:
652:                for (int i = 0; i < excTableEntryCount; i++) {
653:                    int startPC = getU2(exceptionTable, pos);
654:                    int endPC = getU2(exceptionTable, pos + 2);
655:                    int handlerPC = getU2(exceptionTable, pos + 4);
656:
657:                    if (startPC > injectionPos) {
658:                        startPC += injectedBytesCount;
659:                        endPC += injectedBytesCount;
660:                        putU2(exceptionTable, pos, startPC);
661:                        putU2(exceptionTable, pos + 2, endPC);
662:                    } else if (injectionPos < endPC) {
663:                        endPC += injectedBytesCount;
664:                        putU2(exceptionTable, pos + 2, endPC);
665:                    }
666:
667:                    if (handlerPC > injectionPos) {
668:                        handlerPC += injectedBytesCount;
669:                        putU2(exceptionTable, pos + 4, handlerPC);
670:                    }
671:
672:                    pos += 8;
673:                }
674:            }
675:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.