MethodGenerator.java revision 973:d564abed1e6a
1/* 2 * Copyright (c) 2010, 2013, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.tools.nasgen; 27 28import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD; 29import static jdk.internal.org.objectweb.asm.Opcodes.AASTORE; 30import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 31import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL; 32import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; 33import static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY; 34import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; 35import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; 36import static jdk.internal.org.objectweb.asm.Opcodes.BALOAD; 37import static jdk.internal.org.objectweb.asm.Opcodes.BASTORE; 38import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH; 39import static jdk.internal.org.objectweb.asm.Opcodes.CALOAD; 40import static jdk.internal.org.objectweb.asm.Opcodes.CASTORE; 41import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST; 42import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD; 43import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE; 44import static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0; 45import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN; 46import static jdk.internal.org.objectweb.asm.Opcodes.DUP; 47import static jdk.internal.org.objectweb.asm.Opcodes.DUP2; 48import static jdk.internal.org.objectweb.asm.Opcodes.FALOAD; 49import static jdk.internal.org.objectweb.asm.Opcodes.FASTORE; 50import static jdk.internal.org.objectweb.asm.Opcodes.FCONST_0; 51import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN; 52import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD; 53import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC; 54import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; 55import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD; 56import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE; 57import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0; 58import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD; 59import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE; 60import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; 61import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; 62import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL; 63import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN; 64import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE; 65import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; 66import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; 67import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0; 68import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN; 69import static jdk.internal.org.objectweb.asm.Opcodes.NEW; 70import static jdk.internal.org.objectweb.asm.Opcodes.POP; 71import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; 72import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC; 73import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; 74import static jdk.internal.org.objectweb.asm.Opcodes.SALOAD; 75import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE; 76import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH; 77import static jdk.internal.org.objectweb.asm.Opcodes.SWAP; 78import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE; 79import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE; 80 81import java.util.List; 82import jdk.internal.org.objectweb.asm.Handle; 83import jdk.internal.org.objectweb.asm.MethodVisitor; 84import jdk.internal.org.objectweb.asm.Type; 85 86/** 87 * Base class for all method generating classes. 88 * 89 */ 90public class MethodGenerator extends MethodVisitor { 91 private final int access; 92 private final String name; 93 private final String descriptor; 94 private final Type returnType; 95 private final Type[] argumentTypes; 96 97 MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) { 98 super(Main.ASM_VERSION, mv); 99 this.access = access; 100 this.name = name; 101 this.descriptor = descriptor; 102 this.returnType = Type.getReturnType(descriptor); 103 this.argumentTypes = Type.getArgumentTypes(descriptor); 104 } 105 106 int getAccess() { 107 return access; 108 } 109 110 final String getName() { 111 return name; 112 } 113 114 final String getDescriptor() { 115 return descriptor; 116 } 117 118 final Type getReturnType() { 119 return returnType; 120 } 121 122 final Type[] getArgumentTypes() { 123 return argumentTypes; 124 } 125 126 /** 127 * Check whether access for this method is static 128 * @return true if static 129 */ 130 protected final boolean isStatic() { 131 return (getAccess() & ACC_STATIC) != 0; 132 } 133 134 /** 135 * Check whether this method is a constructor 136 * @return true if constructor 137 */ 138 protected final boolean isConstructor() { 139 return "<init>".equals(name); 140 } 141 142 void newObject(final String type) { 143 super.visitTypeInsn(NEW, type); 144 } 145 146 void newObjectArray(final String type) { 147 super.visitTypeInsn(ANEWARRAY, type); 148 } 149 150 void loadThis() { 151 if ((access & ACC_STATIC) != 0) { 152 throw new IllegalStateException("no 'this' inside static method"); 153 } 154 super.visitVarInsn(ALOAD, 0); 155 } 156 157 void returnValue() { 158 super.visitInsn(returnType.getOpcode(IRETURN)); 159 } 160 161 void returnVoid() { 162 super.visitInsn(RETURN); 163 } 164 165 // load, store 166 void arrayLoad(final Type type) { 167 super.visitInsn(type.getOpcode(IALOAD)); 168 } 169 170 void arrayLoad() { 171 super.visitInsn(AALOAD); 172 } 173 174 void arrayStore(final Type type) { 175 super.visitInsn(type.getOpcode(IASTORE)); 176 } 177 178 void arrayStore() { 179 super.visitInsn(AASTORE); 180 } 181 182 void loadLiteral(final Object value) { 183 super.visitLdcInsn(value); 184 } 185 186 void classLiteral(final String className) { 187 super.visitLdcInsn(className); 188 } 189 190 void loadLocal(final Type type, final int index) { 191 super.visitVarInsn(type.getOpcode(ILOAD), index); 192 } 193 194 void loadLocal(final int index) { 195 super.visitVarInsn(ALOAD, index); 196 } 197 198 void storeLocal(final Type type, final int index) { 199 super.visitVarInsn(type.getOpcode(ISTORE), index); 200 } 201 202 void storeLocal(final int index) { 203 super.visitVarInsn(ASTORE, index); 204 } 205 206 void checkcast(final String type) { 207 super.visitTypeInsn(CHECKCAST, type); 208 } 209 210 // push constants/literals 211 void pushNull() { 212 super.visitInsn(ACONST_NULL); 213 } 214 215 void push(final int value) { 216 if (value >= -1 && value <= 5) { 217 super.visitInsn(ICONST_0 + value); 218 } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { 219 super.visitIntInsn(BIPUSH, value); 220 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { 221 super.visitIntInsn(SIPUSH, value); 222 } else { 223 super.visitLdcInsn(value); 224 } 225 } 226 227 void loadClass(final String className) { 228 super.visitLdcInsn(Type.getObjectType(className)); 229 } 230 231 void pop() { 232 super.visitInsn(POP); 233 } 234 235 // various "dups" 236 void dup() { 237 super.visitInsn(DUP); 238 } 239 240 void dup2() { 241 super.visitInsn(DUP2); 242 } 243 244 void swap() { 245 super.visitInsn(SWAP); 246 } 247 248 void dupArrayValue(final int arrayOpcode) { 249 switch (arrayOpcode) { 250 case IALOAD: case FALOAD: 251 case AALOAD: case BALOAD: 252 case CALOAD: case SALOAD: 253 case IASTORE: case FASTORE: 254 case AASTORE: case BASTORE: 255 case CASTORE: case SASTORE: 256 dup(); 257 break; 258 259 case LALOAD: case DALOAD: 260 case LASTORE: case DASTORE: 261 dup2(); 262 break; 263 default: 264 throw new AssertionError("invalid dup"); 265 } 266 } 267 268 void dupReturnValue(final int returnOpcode) { 269 switch (returnOpcode) { 270 case IRETURN: 271 case FRETURN: 272 case ARETURN: 273 super.visitInsn(DUP); 274 return; 275 case LRETURN: 276 case DRETURN: 277 super.visitInsn(DUP2); 278 return; 279 case RETURN: 280 return; 281 default: 282 throw new IllegalArgumentException("not return"); 283 } 284 } 285 286 void dupValue(final Type type) { 287 switch (type.getSize()) { 288 case 1: 289 dup(); 290 break; 291 case 2: 292 dup2(); 293 break; 294 default: 295 throw new AssertionError("invalid dup"); 296 } 297 } 298 299 void dupValue(final String desc) { 300 final int typeCode = desc.charAt(0); 301 switch (typeCode) { 302 case '[': 303 case 'L': 304 case 'Z': 305 case 'C': 306 case 'B': 307 case 'S': 308 case 'I': 309 super.visitInsn(DUP); 310 break; 311 case 'J': 312 case 'D': 313 super.visitInsn(DUP2); 314 break; 315 default: 316 throw new RuntimeException("invalid signature"); 317 } 318 } 319 320 // push default value of given type desc 321 void defaultValue(final String desc) { 322 final int typeCode = desc.charAt(0); 323 switch (typeCode) { 324 case '[': 325 case 'L': 326 super.visitInsn(ACONST_NULL); 327 break; 328 case 'Z': 329 case 'C': 330 case 'B': 331 case 'S': 332 case 'I': 333 super.visitInsn(ICONST_0); 334 break; 335 case 'J': 336 super.visitInsn(LCONST_0); 337 break; 338 case 'F': 339 super.visitInsn(FCONST_0); 340 break; 341 case 'D': 342 super.visitInsn(DCONST_0); 343 break; 344 default: 345 throw new AssertionError("invalid desc " + desc); 346 } 347 } 348 349 // invokes, field get/sets 350 void invokeInterface(final String owner, final String method, final String desc) { 351 super.visitMethodInsn(INVOKEINTERFACE, owner, method, desc, true); 352 } 353 354 void invokeVirtual(final String owner, final String method, final String desc) { 355 super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc, false); 356 } 357 358 void invokeSpecial(final String owner, final String method, final String desc) { 359 super.visitMethodInsn(INVOKESPECIAL, owner, method, desc, false); 360 } 361 362 void invokeStatic(final String owner, final String method, final String desc) { 363 super.visitMethodInsn(INVOKESTATIC, owner, method, desc, false); 364 } 365 366 void putStatic(final String owner, final String field, final String desc) { 367 super.visitFieldInsn(PUTSTATIC, owner, field, desc); 368 } 369 370 void getStatic(final String owner, final String field, final String desc) { 371 super.visitFieldInsn(GETSTATIC, owner, field, desc); 372 } 373 374 void putField(final String owner, final String field, final String desc) { 375 super.visitFieldInsn(PUTFIELD, owner, field, desc); 376 } 377 378 void getField(final String owner, final String field, final String desc) { 379 super.visitFieldInsn(GETFIELD, owner, field, desc); 380 } 381 382 void memberInfoArray(final String className, final List<MemberInfo> mis) { 383 if (mis.isEmpty()) { 384 pushNull(); 385 return; 386 } 387 388 int pos = 0; 389 push(mis.size()); 390 newObjectArray(METHODHANDLE_TYPE); 391 for (final MemberInfo mi : mis) { 392 dup(); 393 push(pos++); 394 visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc())); 395 arrayStore(TYPE_METHODHANDLE); 396 } 397 } 398 399 void computeMaxs() { 400 // These values are ignored as we create class writer 401 // with ClassWriter.COMPUTE_MAXS flag. 402 super.visitMaxs(Short.MAX_VALUE, Short.MAX_VALUE); 403 } 404 405 // debugging support - print calls 406 void println(final String msg) { 407 super.visitFieldInsn(GETSTATIC, 408 "java/lang/System", 409 "out", 410 "Ljava/io/PrintStream;"); 411 super.visitLdcInsn(msg); 412 super.visitMethodInsn(INVOKEVIRTUAL, 413 "java/io/PrintStream", 414 "println", 415 "(Ljava/lang/String;)V", 416 false); 417 } 418 419 // print the object on the top of the stack 420 void printObject() { 421 super.visitFieldInsn(GETSTATIC, 422 "java/lang/System", 423 "out", 424 "Ljava/io/PrintStream;"); 425 super.visitInsn(SWAP); 426 super.visitMethodInsn(INVOKEVIRTUAL, 427 "java/io/PrintStream", 428 "println", 429 "(Ljava/lang/Object;)V", 430 false); 431 } 432} 433