MethodGenerator.java revision 818:26a5fdb90de2
1159784Ssam/* 2159784Ssam * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3159784Ssam * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4159784Ssam * 5159784Ssam * This code is free software; you can redistribute it and/or modify it 6159784Ssam * under the terms of the GNU General Public License version 2 only, as 7159784Ssam * published by the Free Software Foundation. Oracle designates this 8159784Ssam * particular file as subject to the "Classpath" exception as provided 9159784Ssam * by Oracle in the LICENSE file that accompanied this code. 10159784Ssam * 11159784Ssam * This code is distributed in the hope that it will be useful, but WITHOUT 12159784Ssam * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13159784Ssam * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14159784Ssam * version 2 for more details (a copy is included in the LICENSE file that 15159784Ssam * accompanied this code). 16159784Ssam * 17159784Ssam * You should have received a copy of the GNU General Public License version 18159784Ssam * 2 along with this work; if not, write to the Free Software Foundation, 19159784Ssam * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20159784Ssam * 21159784Ssam * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22159784Ssam * or visit www.oracle.com if you need additional information or have any 23159784Ssam * questions. 24159784Ssam */ 25159784Ssam 26159784Ssampackage jdk.nashorn.internal.tools.nasgen; 27159784Ssam 28159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.AALOAD; 29159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.AASTORE; 30159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 31159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL; 32159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; 33159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY; 34159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; 35159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ASM4; 36159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; 37159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.BALOAD; 38159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.BASTORE; 39159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH; 40159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.CALOAD; 41159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.CASTORE; 42159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST; 43159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DALOAD; 44159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DASTORE; 45159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0; 46159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DRETURN; 47159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DUP; 48159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.DUP2; 49159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.FALOAD; 50159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.FASTORE; 51159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.FCONST_0; 52159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.FRETURN; 53159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD; 54159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC; 55159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; 56159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.IALOAD; 57159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.IASTORE; 58159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0; 59159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ILOAD; 60159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE; 61159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; 62159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; 63159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL; 64159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.IRETURN; 65159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.ISTORE; 66159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; 67159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; 68159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0; 69159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.LRETURN; 70159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.NEW; 71159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.POP; 72159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; 73159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC; 74159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.RETURN; 75159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.SALOAD; 76159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.SASTORE; 77159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH; 78159784Ssamimport static jdk.internal.org.objectweb.asm.Opcodes.SWAP; 79159784Ssamimport static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE; 80159784Ssamimport static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE; 81159784Ssam 82159784Ssamimport java.util.List; 83159784Ssamimport jdk.internal.org.objectweb.asm.Handle; 84159784Ssamimport jdk.internal.org.objectweb.asm.MethodVisitor; 85159784Ssamimport jdk.internal.org.objectweb.asm.Type; 86159784Ssam 87159784Ssam/** 88159784Ssam * Base class for all method generating classes. 89159784Ssam * 90159784Ssam */ 91159784Ssampublic class MethodGenerator extends MethodVisitor { 92298881Spfg private final int access; 93159784Ssam private final String name; 94159784Ssam private final String descriptor; 95159784Ssam private final Type returnType; 96159784Ssam private final Type[] argumentTypes; 97159784Ssam 98159784Ssam MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) { 99159784Ssam super(ASM4, mv); 100159784Ssam this.access = access; 101159784Ssam this.name = name; 102159784Ssam this.descriptor = descriptor; 103159784Ssam this.returnType = Type.getReturnType(descriptor); 104159784Ssam this.argumentTypes = Type.getArgumentTypes(descriptor); 105159784Ssam } 106159784Ssam 107159784Ssam int getAccess() { 108159784Ssam return access; 109159784Ssam } 110159784Ssam 111159784Ssam final String getName() { 112159784Ssam return name; 113159784Ssam } 114159784Ssam 115159784Ssam final String getDescriptor() { 116159784Ssam return descriptor; 117159784Ssam } 118159784Ssam 119159784Ssam final Type getReturnType() { 120159784Ssam return returnType; 121159784Ssam } 122159784Ssam 123159784Ssam final Type[] getArgumentTypes() { 124159784Ssam return argumentTypes; 125159784Ssam } 126159784Ssam 127159784Ssam /** 128159784Ssam * Check whether access for this method is static 129159784Ssam * @return true if static 130159784Ssam */ 131159784Ssam protected final boolean isStatic() { 132159784Ssam return (getAccess() & ACC_STATIC) != 0; 133159784Ssam } 134159784Ssam 135159784Ssam /** 136159784Ssam * Check whether this method is a constructor 137159784Ssam * @return true if constructor 138159784Ssam */ 139159784Ssam protected final boolean isConstructor() { 140298881Spfg return "<init>".equals(name); 141159784Ssam } 142159784Ssam 143159784Ssam void newObject(final String type) { 144159784Ssam super.visitTypeInsn(NEW, type); 145159784Ssam } 146159784Ssam 147159784Ssam void newObjectArray(final String type) { 148159784Ssam super.visitTypeInsn(ANEWARRAY, type); 149159784Ssam } 150159784Ssam 151159784Ssam void loadThis() { 152159784Ssam if ((access & ACC_STATIC) != 0) { 153159784Ssam throw new IllegalStateException("no 'this' inside static method"); 154159784Ssam } 155159784Ssam super.visitVarInsn(ALOAD, 0); 156159784Ssam } 157159784Ssam 158159784Ssam void returnValue() { 159159784Ssam super.visitInsn(returnType.getOpcode(IRETURN)); 160159784Ssam } 161159784Ssam 162159784Ssam void returnVoid() { 163159784Ssam super.visitInsn(RETURN); 164159784Ssam } 165159784Ssam 166159784Ssam // load, store 167159784Ssam void arrayLoad(final Type type) { 168159784Ssam super.visitInsn(type.getOpcode(IALOAD)); 169159784Ssam } 170159784Ssam 171159784Ssam void arrayLoad() { 172159784Ssam super.visitInsn(AALOAD); 173159784Ssam } 174159784Ssam 175159784Ssam void arrayStore(final Type type) { 176159784Ssam super.visitInsn(type.getOpcode(IASTORE)); 177159784Ssam } 178159784Ssam 179159784Ssam void arrayStore() { 180159784Ssam super.visitInsn(AASTORE); 181159784Ssam } 182159784Ssam 183159784Ssam void loadLiteral(final Object value) { 184159784Ssam super.visitLdcInsn(value); 185159784Ssam } 186159784Ssam 187159784Ssam void classLiteral(final String className) { 188159784Ssam super.visitLdcInsn(className); 189159784Ssam } 190159784Ssam 191159784Ssam void loadLocal(final Type type, final int index) { 192159784Ssam super.visitVarInsn(type.getOpcode(ILOAD), index); 193159784Ssam } 194159784Ssam 195159784Ssam void loadLocal(final int index) { 196159784Ssam super.visitVarInsn(ALOAD, index); 197159784Ssam } 198159784Ssam 199159784Ssam void storeLocal(final Type type, final int index) { 200159784Ssam super.visitVarInsn(type.getOpcode(ISTORE), index); 201159784Ssam } 202159784Ssam 203159784Ssam void storeLocal(final int index) { 204159784Ssam super.visitVarInsn(ASTORE, index); 205159784Ssam } 206159784Ssam 207159784Ssam void checkcast(final String type) { 208159784Ssam super.visitTypeInsn(CHECKCAST, type); 209159784Ssam } 210159784Ssam 211159784Ssam // push constants/literals 212159784Ssam void pushNull() { 213159784Ssam super.visitInsn(ACONST_NULL); 214159784Ssam } 215159784Ssam 216159784Ssam void push(final int value) { 217159784Ssam if (value >= -1 && value <= 5) { 218159784Ssam super.visitInsn(ICONST_0 + value); 219159784Ssam } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { 220159784Ssam super.visitIntInsn(BIPUSH, value); 221159784Ssam } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { 222159784Ssam super.visitIntInsn(SIPUSH, value); 223159784Ssam } else { 224159784Ssam super.visitLdcInsn(value); 225159784Ssam } 226159784Ssam } 227159784Ssam 228159784Ssam void loadClass(final String className) { 229159784Ssam super.visitLdcInsn(Type.getObjectType(className)); 230159784Ssam } 231159784Ssam 232159784Ssam void pop() { 233159784Ssam super.visitInsn(POP); 234159784Ssam } 235159784Ssam 236159784Ssam // various "dups" 237159784Ssam void dup() { 238159784Ssam super.visitInsn(DUP); 239159784Ssam } 240159784Ssam 241159784Ssam void dup2() { 242159784Ssam super.visitInsn(DUP2); 243159784Ssam } 244159784Ssam 245159784Ssam void swap() { 246159784Ssam super.visitInsn(SWAP); 247159784Ssam } 248159784Ssam 249159784Ssam void dupArrayValue(final int arrayOpcode) { 250159784Ssam switch (arrayOpcode) { 251159784Ssam case IALOAD: case FALOAD: 252159784Ssam case AALOAD: case BALOAD: 253159784Ssam case CALOAD: case SALOAD: 254159784Ssam case IASTORE: case FASTORE: 255159784Ssam case AASTORE: case BASTORE: 256159784Ssam case CASTORE: case SASTORE: 257159784Ssam dup(); 258159784Ssam break; 259159784Ssam 260159784Ssam case LALOAD: case DALOAD: 261159784Ssam case LASTORE: case DASTORE: 262159784Ssam dup2(); 263159829Sobrien break; 264159784Ssam default: 265159784Ssam throw new AssertionError("invalid dup"); 266159784Ssam } 267159784Ssam } 268159784Ssam 269159829Sobrien void dupReturnValue(final int returnOpcode) { 270159784Ssam switch (returnOpcode) { 271159784Ssam case IRETURN: 272159784Ssam case FRETURN: 273159829Sobrien case ARETURN: 274159784Ssam super.visitInsn(DUP); 275159784Ssam return; 276159784Ssam case LRETURN: 277159784Ssam case DRETURN: 278 super.visitInsn(DUP2); 279 return; 280 case RETURN: 281 return; 282 default: 283 throw new IllegalArgumentException("not return"); 284 } 285 } 286 287 void dupValue(final Type type) { 288 switch (type.getSize()) { 289 case 1: 290 dup(); 291 break; 292 case 2: 293 dup2(); 294 break; 295 default: 296 throw new AssertionError("invalid dup"); 297 } 298 } 299 300 void dupValue(final String desc) { 301 final int typeCode = desc.charAt(0); 302 switch (typeCode) { 303 case '[': 304 case 'L': 305 case 'Z': 306 case 'C': 307 case 'B': 308 case 'S': 309 case 'I': 310 super.visitInsn(DUP); 311 break; 312 case 'J': 313 case 'D': 314 super.visitInsn(DUP2); 315 break; 316 default: 317 throw new RuntimeException("invalid signature"); 318 } 319 } 320 321 // push default value of given type desc 322 void defaultValue(final String desc) { 323 final int typeCode = desc.charAt(0); 324 switch (typeCode) { 325 case '[': 326 case 'L': 327 super.visitInsn(ACONST_NULL); 328 break; 329 case 'Z': 330 case 'C': 331 case 'B': 332 case 'S': 333 case 'I': 334 super.visitInsn(ICONST_0); 335 break; 336 case 'J': 337 super.visitInsn(LCONST_0); 338 break; 339 case 'F': 340 super.visitInsn(FCONST_0); 341 break; 342 case 'D': 343 super.visitInsn(DCONST_0); 344 break; 345 default: 346 throw new AssertionError("invalid desc " + desc); 347 } 348 } 349 350 // invokes, field get/sets 351 void invokeInterface(final String owner, final String method, final String desc) { 352 super.visitMethodInsn(INVOKEINTERFACE, owner, method, desc, true); 353 } 354 355 void invokeVirtual(final String owner, final String method, final String desc) { 356 super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc, false); 357 } 358 359 void invokeSpecial(final String owner, final String method, final String desc) { 360 super.visitMethodInsn(INVOKESPECIAL, owner, method, desc, false); 361 } 362 363 void invokeStatic(final String owner, final String method, final String desc) { 364 super.visitMethodInsn(INVOKESTATIC, owner, method, desc, false); 365 } 366 367 void putStatic(final String owner, final String field, final String desc) { 368 super.visitFieldInsn(PUTSTATIC, owner, field, desc); 369 } 370 371 void getStatic(final String owner, final String field, final String desc) { 372 super.visitFieldInsn(GETSTATIC, owner, field, desc); 373 } 374 375 void putField(final String owner, final String field, final String desc) { 376 super.visitFieldInsn(PUTFIELD, owner, field, desc); 377 } 378 379 void getField(final String owner, final String field, final String desc) { 380 super.visitFieldInsn(GETFIELD, owner, field, desc); 381 } 382 383 void memberInfoArray(final String className, final List<MemberInfo> mis) { 384 if (mis.isEmpty()) { 385 pushNull(); 386 return; 387 } 388 389 int pos = 0; 390 push(mis.size()); 391 newObjectArray(METHODHANDLE_TYPE); 392 for (final MemberInfo mi : mis) { 393 dup(); 394 push(pos++); 395 visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc())); 396 arrayStore(TYPE_METHODHANDLE); 397 } 398 } 399 400 void computeMaxs() { 401 // These values are ignored as we create class writer 402 // with ClassWriter.COMPUTE_MAXS flag. 403 super.visitMaxs(Short.MAX_VALUE, Short.MAX_VALUE); 404 } 405 406 // debugging support - print calls 407 void println(final String msg) { 408 super.visitFieldInsn(GETSTATIC, 409 "java/lang/System", 410 "out", 411 "Ljava/io/PrintStream;"); 412 super.visitLdcInsn(msg); 413 super.visitMethodInsn(INVOKEVIRTUAL, 414 "java/io/PrintStream", 415 "println", 416 "(Ljava/lang/String;)V", 417 false); 418 } 419 420 // print the object on the top of the stack 421 void printObject() { 422 super.visitFieldInsn(GETSTATIC, 423 "java/lang/System", 424 "out", 425 "Ljava/io/PrintStream;"); 426 super.visitInsn(SWAP); 427 super.visitMethodInsn(INVOKEVIRTUAL, 428 "java/io/PrintStream", 429 "println", 430 "(Ljava/lang/Object;)V", 431 false); 432 } 433} 434