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