1/*
2 * Copyright (c) 2002, 2014, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25package sun.jvm.hotspot.tools.jcore;
26
27import sun.jvm.hotspot.oops.*;
28import sun.jvm.hotspot.interpreter.*;
29import sun.jvm.hotspot.utilities.*;
30import sun.jvm.hotspot.debugger.*;
31import sun.jvm.hotspot.runtime.*;
32import java.security.AccessController;
33import java.security.PrivilegedAction;
34import java.security.AccessControlContext;
35import java.security.PrivilegedExceptionAction;
36import java.security.PrivilegedActionException;
37
38public class ByteCodeRewriter
39{
40    private Method method;
41    private ConstantPool cpool;
42    private ConstantPoolCache cpCache;
43    private byte[] code;
44    private Bytes  bytes;
45
46    private static final int jintSize = 4;
47    public static final boolean DEBUG;
48
49    static {
50        String debug =  (String) AccessController.doPrivileged(
51            new PrivilegedAction() {
52                public Object run() {
53                    return System.getProperty("sun.jvm.hotspot.tools.jcore.ByteCodeRewriter.DEBUG");
54                }
55            }
56        );
57        DEBUG = (debug != null ? debug.equalsIgnoreCase("true") : false);
58    }
59
60
61    protected void debugMessage(String message) {
62        System.out.println(message);
63    }
64
65    public ByteCodeRewriter(Method method, ConstantPool cpool, byte[] code) {
66        this.method = method;
67        this.cpool = cpool;
68        this.cpCache = cpool.getCache();
69        this.code = code;
70        this.bytes = VM.getVM().getBytes();
71
72    }
73
74    protected short getConstantPoolIndexFromRefMap(int rawcode, int bci) {
75        int refIndex;
76        String fmt = Bytecodes.format(rawcode);
77        switch (fmt.length()) {
78            case 2: refIndex = 0xFF & method.getBytecodeByteArg(bci); break;
79            case 3: refIndex = 0xFFFF & bytes.swapShort(method.getBytecodeShortArg(bci)); break;
80            default: throw new IllegalArgumentException();
81        }
82
83        return (short)cpool.objectToCPIndex(refIndex);
84     }
85
86    protected short getConstantPoolIndex(int rawcode, int bci) {
87       // get ConstantPool index from ConstantPoolCacheIndex at given bci
88       String fmt = Bytecodes.format(rawcode);
89       int cpCacheIndex;
90       switch (fmt.length()) {
91       case 2: cpCacheIndex = method.getBytecodeByteArg(bci); break;
92       case 3: cpCacheIndex = method.getBytecodeShortArg(bci); break;
93       case 5:
94           if (fmt.indexOf("__") >= 0)
95               cpCacheIndex = method.getBytecodeShortArg(bci);
96           else
97               cpCacheIndex = method.getBytecodeIntArg(bci);
98           break;
99       default: throw new IllegalArgumentException();
100       }
101
102       if (cpCache == null) {
103          return (short) cpCacheIndex;
104       } else if (fmt.indexOf("JJJJ") >= 0) {
105          // Invokedynamic require special handling
106          cpCacheIndex = ~cpCacheIndex;
107          cpCacheIndex = bytes.swapInt(cpCacheIndex);
108          return (short) cpCache.getEntryAt(cpCacheIndex).getConstantPoolIndex();
109       } else if (fmt.indexOf("JJ") >= 0) {
110          // change byte-ordering and go via cache
111          return (short) cpCache.getEntryAt((int) (0xFFFF & bytes.swapShort((short)cpCacheIndex))).getConstantPoolIndex();
112       } else if (fmt.indexOf("j") >= 0) {
113          // go via cache
114          return (short) cpCache.getEntryAt((int) (0xFF & cpCacheIndex)).getConstantPoolIndex();
115       } else {
116          return (short) cpCacheIndex;
117       }
118    }
119
120    static private void writeShort(byte[] buf, int index, short value) {
121        buf[index] = (byte) ((value >> 8) & 0x00FF);
122        buf[index + 1] = (byte) (value & 0x00FF);
123    }
124
125    public void rewrite() {
126        int bytecode = Bytecodes._illegal;
127        int hotspotcode = Bytecodes._illegal;
128        int len = 0;
129
130        if (DEBUG) {
131            String msg = method.getMethodHolder().getName().asString() + "." +
132                         method.getName().asString() +
133                         method.getSignature().asString();
134            debugMessage(msg);
135        }
136        for (int bci = 0; bci < code.length;) {
137            hotspotcode = Bytecodes.codeAt(method, bci);
138            bytecode = Bytecodes.javaCode(hotspotcode);
139
140            if (Assert.ASSERTS_ENABLED) {
141                int code_from_buffer = 0xFF & code[bci];
142                Assert.that(code_from_buffer == hotspotcode
143                          || code_from_buffer == Bytecodes._breakpoint,
144                          "Unexpected bytecode found in method bytecode buffer!");
145            }
146
147            // update the code buffer hotspot specific bytecode with the jvm bytecode
148            code[bci] = (byte) (0xFF & bytecode);
149
150            short cpoolIndex = 0;
151            switch (bytecode) {
152                // bytecodes with ConstantPoolCache index
153                case Bytecodes._getstatic:
154                case Bytecodes._putstatic:
155                case Bytecodes._getfield:
156                case Bytecodes._putfield:
157                case Bytecodes._invokevirtual:
158                case Bytecodes._invokespecial:
159                case Bytecodes._invokestatic:
160                case Bytecodes._invokeinterface: {
161                    cpoolIndex = getConstantPoolIndex(hotspotcode, bci + 1);
162                    writeShort(code, bci + 1, cpoolIndex);
163                    break;
164                }
165
166                case Bytecodes._invokedynamic:
167                    cpoolIndex = getConstantPoolIndex(hotspotcode, bci + 1);
168                    writeShort(code, bci + 1, cpoolIndex);
169                    writeShort(code, bci + 3, (short)0);  // clear out trailing bytes
170                    break;
171
172                case Bytecodes._ldc_w:
173                    if (hotspotcode != bytecode) {
174                        // fast_aldc_w puts constant in reference map
175                        cpoolIndex = getConstantPoolIndexFromRefMap(hotspotcode, bci + 1);
176                        writeShort(code, bci + 1, cpoolIndex);
177                    }
178                    break;
179                case Bytecodes._ldc:
180                    if (hotspotcode != bytecode) {
181                        // fast_aldc puts constant in reference map
182                        cpoolIndex = getConstantPoolIndexFromRefMap(hotspotcode, bci + 1);
183                        code[bci + 1] = (byte)(cpoolIndex);
184                    }
185                    break;
186            }
187
188            len = Bytecodes.lengthFor(bytecode);
189            if (len <= 0) len = Bytecodes.lengthAt(method, bci);
190
191            if (DEBUG) {
192                String operand = "";
193                switch (len) {
194                   case 2:
195                        operand += code[bci + 1];
196                        break;
197                   case 3:
198                        operand += (cpoolIndex != 0)? cpoolIndex :
199                                            method.getBytecodeShortArg(bci + 1);
200                        break;
201                   case 5:
202                        operand += method.getBytecodeIntArg(bci + 1);
203                        break;
204                }
205
206                // the operand following # is not quite like javap output.
207                // in particular, for goto & goto_w, the operand is PC relative
208                // offset for jump. Javap adds relative offset with current PC
209                // to give absolute bci to jump to.
210
211                String message = "\t\t" + bci + " " + Bytecodes.name(bytecode);
212                if (hotspotcode != bytecode)
213                    message += " [" + Bytecodes.name(hotspotcode) + "]";
214                if (operand != "")
215                    message += " #" + operand;
216
217                if (DEBUG) debugMessage(message);
218            }
219
220            bci += len;
221        }
222    }
223}
224