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 26 package jdk.nashorn.internal.tools.nasgen; 27 28 import static jdk.internal.org.objectweb.asm.Opcodes.AALOAD; 29 import static jdk.internal.org.objectweb.asm.Opcodes.AASTORE; 30 import static jdk.internal.org.objectweb.asm.Opcodes.ACC_STATIC; 31 import static jdk.internal.org.objectweb.asm.Opcodes.ACONST_NULL; 32 import static jdk.internal.org.objectweb.asm.Opcodes.ALOAD; 33 import static jdk.internal.org.objectweb.asm.Opcodes.ANEWARRAY; 34 import static jdk.internal.org.objectweb.asm.Opcodes.ARETURN; 35 import static jdk.internal.org.objectweb.asm.Opcodes.ASM4; 36 import static jdk.internal.org.objectweb.asm.Opcodes.ASTORE; 37 import static jdk.internal.org.objectweb.asm.Opcodes.BALOAD; 38 import static jdk.internal.org.objectweb.asm.Opcodes.BASTORE; 39 import static jdk.internal.org.objectweb.asm.Opcodes.BIPUSH; 40 import static jdk.internal.org.objectweb.asm.Opcodes.CALOAD; 41 import static jdk.internal.org.objectweb.asm.Opcodes.CASTORE; 42 import static jdk.internal.org.objectweb.asm.Opcodes.CHECKCAST; 43 import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD; 44 import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE; 45 import static jdk.internal.org.objectweb.asm.Opcodes.DCONST_0; 46 import static jdk.internal.org.objectweb.asm.Opcodes.DRETURN; 47 import static jdk.internal.org.objectweb.asm.Opcodes.DUP; 48 import static jdk.internal.org.objectweb.asm.Opcodes.DUP2; 49 import static jdk.internal.org.objectweb.asm.Opcodes.FALOAD; 50 import static jdk.internal.org.objectweb.asm.Opcodes.FASTORE; 51 import static jdk.internal.org.objectweb.asm.Opcodes.FCONST_0; 52 import static jdk.internal.org.objectweb.asm.Opcodes.FRETURN; 53 import static jdk.internal.org.objectweb.asm.Opcodes.GETFIELD; 54 import static jdk.internal.org.objectweb.asm.Opcodes.GETSTATIC; 55 import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; 56 import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD; 57 import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE; 58 import static jdk.internal.org.objectweb.asm.Opcodes.ICONST_0; 59 import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD; 60 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE; 61 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; 62 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; 63 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL; 64 import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN; 65 import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE; 66 import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; 67 import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; 68 import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0; 69 import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN; 70 import static jdk.internal.org.objectweb.asm.Opcodes.NEW; 71 import static jdk.internal.org.objectweb.asm.Opcodes.POP; 72 import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; 73 import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC; 74 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; 75 import static jdk.internal.org.objectweb.asm.Opcodes.SALOAD; 76 import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE; 77 import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH; 78 import static jdk.internal.org.objectweb.asm.Opcodes.SWAP; 79 import static jdk.nashorn.internal.tools.nasgen.StringConstants.METHODHANDLE_TYPE; 80 import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_METHODHANDLE; 81 82 import java.util.List; 83 import jdk.internal.org.objectweb.asm.Handle; 84 import jdk.internal.org.objectweb.asm.MethodVisitor; 85 import jdk.internal.org.objectweb.asm.Type; 86 87 /** 88 * Base class for all method generating classes. 89 * 90 */ 91 public class MethodGenerator extends MethodVisitor { 92 private final int access; 93 private final String name; 94 private final String descriptor; 95 private final Type returnType; 96 private final Type[] argumentTypes; 97 98 MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) { 99 super(ASM4, mv); 100 this.access = access; 101 this.name = name; 102 this.descriptor = descriptor; 103 this.returnType = Type.getReturnType(descriptor); 104 this.argumentTypes = Type.getArgumentTypes(descriptor); 105 } 106 107 int getAccess() { 108 return access; 109 } 110 111 final String getName() { 112 return name; 113 } 114 115 final String getDescriptor() { 116 return descriptor; 117 } 118 119 final Type getReturnType() { 120 return returnType; 121 } 122 123 final Type[] getArgumentTypes() { 124 return argumentTypes; 125 } 126 127 /** 128 * Check whether access for this method is static 129 * @return true if static 130 */ 131 protected final boolean isStatic() { 132 return (getAccess() & ACC_STATIC) != 0; 133 } 134 135 /** 136 * Check whether this method is a constructor 137 * @return true if constructor 138 */ 139 protected final boolean isConstructor() { 140 return "<init>".equals(name); 141 } 142 143 void newObject(final String type) { 144 super.visitTypeInsn(NEW, type); 145 } 146 147 void newObjectArray(final String type) { 148 super.visitTypeInsn(ANEWARRAY, type); 149 } 150 151 void loadThis() { 152 if ((access & ACC_STATIC) != 0) { 153 throw new IllegalStateException("no 'this' inside static method"); 154 } 155 super.visitVarInsn(ALOAD, 0); 156 } 157 158 void returnValue() { 159 super.visitInsn(returnType.getOpcode(IRETURN)); 160 } 161 162 void returnVoid() { 163 super.visitInsn(RETURN); 164 } 165 166 // load, store 167 void arrayLoad(final Type type) { 168 super.visitInsn(type.getOpcode(IALOAD)); 169 } 170 171 void arrayLoad() { 172 super.visitInsn(AALOAD); 173 } 174 175 void arrayStore(final Type type) { 176 super.visitInsn(type.getOpcode(IASTORE)); 177 } 178 179 void arrayStore() { 180 super.visitInsn(AASTORE); 181 } 182 183 void loadLiteral(final Object value) { 184 super.visitLdcInsn(value); 185 } 186 187 void classLiteral(final String className) { 188 super.visitLdcInsn(className); 189 } 190 191 void loadLocal(final Type type, final int index) { 192 super.visitVarInsn(type.getOpcode(ILOAD), index); 193 } 194 195 void loadLocal(final int index) { 196 super.visitVarInsn(ALOAD, index); 197 } 198 199 void storeLocal(final Type type, final int index) { 200 super.visitVarInsn(type.getOpcode(ISTORE), index); 201 } 202 203 void storeLocal(final int index) { 204 super.visitVarInsn(ASTORE, index); 205 } 206 207 void checkcast(final String type) { 208 super.visitTypeInsn(CHECKCAST, type); 209 } 210 211 // push constants/literals 212 void pushNull() { 213 super.visitInsn(ACONST_NULL); 214 } 215 216 void push(final int value) { 217 if (value >= -1 && value <= 5) { 218 super.visitInsn(ICONST_0 + value); 219 } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { 220 super.visitIntInsn(BIPUSH, value); 221 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { 222 super.visitIntInsn(SIPUSH, value); 223 } else { 224 super.visitLdcInsn(value); 225 } 226 } 227 228 void loadClass(final String className) { 229 super.visitLdcInsn(Type.getObjectType(className)); 230 } 231 232 void pop() { 233 super.visitInsn(POP); 234 } 235 236 // various "dups" 237 void dup() { 238 super.visitInsn(DUP); 239 } 240 241 void dup2() { 242 super.visitInsn(DUP2); 243 } 244 245 void swap() { 246 super.visitInsn(SWAP); 247 } 248 249 void dupArrayValue(final int arrayOpcode) { 250 switch (arrayOpcode) { 251 case IALOAD: case FALOAD: 252 case AALOAD: case BALOAD: 253 case CALOAD: case SALOAD: 254 case IASTORE: case FASTORE: 255 case AASTORE: case BASTORE: 256 case CASTORE: case SASTORE: 257 dup(); 258 break; 259 260 case LALOAD: case DALOAD: 261 case LASTORE: case DASTORE: 262 dup2(); 263 break; 264 default: 265 throw new AssertionError("invalid dup"); 266 } 267 } 268 269 void dupReturnValue(final int returnOpcode) { 270 switch (returnOpcode) { 271 case IRETURN: 272 case FRETURN: 273 case ARETURN: 274 super.visitInsn(DUP); 275 return; 276 case LRETURN: 277 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); 353 } 354 355 void invokeVirtual(final String owner, final String method, final String desc) { 356 super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc); 357 } 358 359 void invokeSpecial(final String owner, final String method, final String desc) { 360 super.visitMethodInsn(INVOKESPECIAL, owner, method, desc); 361 } 362 363 void invokeStatic(final String owner, final String method, final String desc) { 364 super.visitMethodInsn(INVOKESTATIC, owner, method, desc); 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 } 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 } 431 }