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.ICONST_1; 60 import static jdk.internal.org.objectweb.asm.Opcodes.ILOAD; 61 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEINTERFACE; 62 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESPECIAL; 63 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; 64 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKEVIRTUAL; 65 import static jdk.internal.org.objectweb.asm.Opcodes.IRETURN; 66 import static jdk.internal.org.objectweb.asm.Opcodes.ISTORE; 67 import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; 68 import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; 69 import static jdk.internal.org.objectweb.asm.Opcodes.LCONST_0; 70 import static jdk.internal.org.objectweb.asm.Opcodes.LRETURN; 71 import static jdk.internal.org.objectweb.asm.Opcodes.NEW; 72 import static jdk.internal.org.objectweb.asm.Opcodes.POP; 73 import static jdk.internal.org.objectweb.asm.Opcodes.PUTFIELD; 74 import static jdk.internal.org.objectweb.asm.Opcodes.PUTSTATIC; 75 import static jdk.internal.org.objectweb.asm.Opcodes.RETURN; 76 import static jdk.internal.org.objectweb.asm.Opcodes.SALOAD; 77 import static jdk.internal.org.objectweb.asm.Opcodes.SASTORE; 78 import static jdk.internal.org.objectweb.asm.Opcodes.SIPUSH; 79 import static jdk.internal.org.objectweb.asm.Opcodes.SWAP; 80 import static jdk.nashorn.internal.tools.nasgen.StringConstants.INIT; 81 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_INIT2; 82 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_INIT3; 83 import static jdk.nashorn.internal.tools.nasgen.StringConstants.SPECIALIZATION_TYPE; 84 import static jdk.nashorn.internal.tools.nasgen.StringConstants.TYPE_SPECIALIZATION; 85 import java.util.List; 86 import jdk.internal.org.objectweb.asm.Handle; 87 import jdk.internal.org.objectweb.asm.MethodVisitor; 88 import jdk.internal.org.objectweb.asm.Type; 89 import jdk.nashorn.internal.objects.annotations.SpecializedFunction.LinkLogic; 90 91 /** 92 * Base class for all method generating classes. 93 * 94 */ 95 public class MethodGenerator extends MethodVisitor { 96 private final int access; 97 private final String name; 98 private final String descriptor; 99 private final Type returnType; 100 private final Type[] argumentTypes; 101 102 static final Type EMPTY_LINK_LOGIC_TYPE = Type.getType(LinkLogic.getEmptyLinkLogicClass()); 103 104 MethodGenerator(final MethodVisitor mv, final int access, final String name, final String descriptor) { 105 super(ASM4, mv); 106 this.access = access; 107 this.name = name; 108 this.descriptor = descriptor; 109 this.returnType = Type.getReturnType(descriptor); 110 this.argumentTypes = Type.getArgumentTypes(descriptor); 111 } 112 113 int getAccess() { 114 return access; 115 } 116 117 final String getName() { 118 return name; 119 } 120 121 final String getDescriptor() { 122 return descriptor; 123 } 124 125 final Type getReturnType() { 126 return returnType; 127 } 128 129 final Type[] getArgumentTypes() { 130 return argumentTypes; 131 } 132 133 /** 134 * Check whether access for this method is static 135 * @return true if static 136 */ 137 protected final boolean isStatic() { 138 return (getAccess() & ACC_STATIC) != 0; 139 } 140 141 /** 142 * Check whether this method is a constructor 143 * @return true if constructor 144 */ 145 protected final boolean isConstructor() { 146 return "<init>".equals(name); 147 } 148 149 void newObject(final String type) { 150 super.visitTypeInsn(NEW, type); 151 } 152 153 void newObjectArray(final String type) { 154 super.visitTypeInsn(ANEWARRAY, type); 155 } 156 157 void loadThis() { 158 if ((access & ACC_STATIC) != 0) { 159 throw new IllegalStateException("no 'this' inside static method"); 160 } 161 super.visitVarInsn(ALOAD, 0); 162 } 163 164 void returnValue() { 165 super.visitInsn(returnType.getOpcode(IRETURN)); 166 } 167 168 void returnVoid() { 169 super.visitInsn(RETURN); 170 } 171 172 // load, store 173 void arrayLoad(final Type type) { 174 super.visitInsn(type.getOpcode(IALOAD)); 175 } 176 177 void arrayLoad() { 178 super.visitInsn(AALOAD); 179 } 180 181 void arrayStore(final Type type) { 182 super.visitInsn(type.getOpcode(IASTORE)); 183 } 184 185 void arrayStore() { 186 super.visitInsn(AASTORE); 187 } 188 189 void loadLiteral(final Object value) { 190 super.visitLdcInsn(value); 191 } 192 193 void classLiteral(final String className) { 194 super.visitLdcInsn(className); 195 } 196 197 void loadLocal(final Type type, final int index) { 198 super.visitVarInsn(type.getOpcode(ILOAD), index); 199 } 200 201 void loadLocal(final int index) { 202 super.visitVarInsn(ALOAD, index); 203 } 204 205 void storeLocal(final Type type, final int index) { 206 super.visitVarInsn(type.getOpcode(ISTORE), index); 207 } 208 209 void storeLocal(final int index) { 210 super.visitVarInsn(ASTORE, index); 211 } 212 213 void checkcast(final String type) { 214 super.visitTypeInsn(CHECKCAST, type); 215 } 216 217 // push constants/literals 218 void pushNull() { 219 super.visitInsn(ACONST_NULL); 220 } 221 222 void push(final int value) { 223 if (value >= -1 && value <= 5) { 224 super.visitInsn(ICONST_0 + value); 225 } else if (value >= Byte.MIN_VALUE && value <= Byte.MAX_VALUE) { 226 super.visitIntInsn(BIPUSH, value); 227 } else if (value >= Short.MIN_VALUE && value <= Short.MAX_VALUE) { 228 super.visitIntInsn(SIPUSH, value); 229 } else { 230 super.visitLdcInsn(value); 231 } 232 } 233 234 void loadClass(final String className) { 235 super.visitLdcInsn(Type.getObjectType(className)); 236 } 237 238 void pop() { 239 super.visitInsn(POP); 240 } 241 242 // various "dups" 243 void dup() { 244 super.visitInsn(DUP); 245 } 246 247 void dup2() { 248 super.visitInsn(DUP2); 249 } 250 251 void swap() { 252 super.visitInsn(SWAP); 253 } 254 255 void dupArrayValue(final int arrayOpcode) { 256 switch (arrayOpcode) { 257 case IALOAD: case FALOAD: 258 case AALOAD: case BALOAD: 259 case CALOAD: case SALOAD: 260 case IASTORE: case FASTORE: 261 case AASTORE: case BASTORE: 262 case CASTORE: case SASTORE: 263 dup(); 264 break; 265 266 case LALOAD: case DALOAD: 267 case LASTORE: case DASTORE: 268 dup2(); 269 break; 270 default: 271 throw new AssertionError("invalid dup"); 272 } 273 } 274 275 void dupReturnValue(final int returnOpcode) { 276 switch (returnOpcode) { 277 case IRETURN: 278 case FRETURN: 279 case ARETURN: 280 super.visitInsn(DUP); 281 return; 282 case LRETURN: 283 case DRETURN: 284 super.visitInsn(DUP2); 285 return; 286 case RETURN: 287 return; 288 default: 289 throw new IllegalArgumentException("not return"); 290 } 291 } 292 293 void dupValue(final Type type) { 294 switch (type.getSize()) { 295 case 1: 296 dup(); 297 break; 298 case 2: 299 dup2(); 300 break; 301 default: 302 throw new AssertionError("invalid dup"); 303 } 304 } 305 306 void dupValue(final String desc) { 307 final int typeCode = desc.charAt(0); 308 switch (typeCode) { 309 case '[': 310 case 'L': 311 case 'Z': 312 case 'C': 313 case 'B': 314 case 'S': 315 case 'I': 316 super.visitInsn(DUP); 317 break; 318 case 'J': 319 case 'D': 320 super.visitInsn(DUP2); 321 break; 322 default: 323 throw new RuntimeException("invalid signature"); 324 } 325 } 326 327 // push default value of given type desc 328 void defaultValue(final String desc) { 329 final int typeCode = desc.charAt(0); 330 switch (typeCode) { 331 case '[': 332 case 'L': 333 super.visitInsn(ACONST_NULL); 334 break; 335 case 'Z': 336 case 'C': 337 case 'B': 338 case 'S': 339 case 'I': 340 super.visitInsn(ICONST_0); 341 break; 342 case 'J': 343 super.visitInsn(LCONST_0); 344 break; 345 case 'F': 346 super.visitInsn(FCONST_0); 347 break; 348 case 'D': 349 super.visitInsn(DCONST_0); 350 break; 351 default: 352 throw new AssertionError("invalid desc " + desc); 353 } 354 } 355 356 // invokes, field get/sets 357 void invokeInterface(final String owner, final String method, final String desc) { 358 super.visitMethodInsn(INVOKEINTERFACE, owner, method, desc, true); 359 } 360 361 void invokeVirtual(final String owner, final String method, final String desc) { 362 super.visitMethodInsn(INVOKEVIRTUAL, owner, method, desc, false); 363 } 364 365 void invokeSpecial(final String owner, final String method, final String desc) { 366 super.visitMethodInsn(INVOKESPECIAL, owner, method, desc, false); 367 } 368 369 void invokeStatic(final String owner, final String method, final String desc) { 370 super.visitMethodInsn(INVOKESTATIC, owner, method, desc, false); 371 } 372 373 void putStatic(final String owner, final String field, final String desc) { 374 super.visitFieldInsn(PUTSTATIC, owner, field, desc); 375 } 376 377 void getStatic(final String owner, final String field, final String desc) { 378 super.visitFieldInsn(GETSTATIC, owner, field, desc); 379 } 380 381 void putField(final String owner, final String field, final String desc) { 382 super.visitFieldInsn(PUTFIELD, owner, field, desc); 383 } 384 385 void getField(final String owner, final String field, final String desc) { 386 super.visitFieldInsn(GETFIELD, owner, field, desc); 387 } 388 389 private static boolean linkLogicIsEmpty(final Type type) { 390 assert EMPTY_LINK_LOGIC_TYPE != null; //type is ok for null if we are a @SpecializedFunction without any attribs 391 return EMPTY_LINK_LOGIC_TYPE.equals(type); 392 } 393 394 void memberInfoArray(final String className, final List<MemberInfo> mis) { 395 if (mis.isEmpty()) { 396 pushNull(); 397 return; 398 } 399 400 int pos = 0; 401 push(mis.size()); 402 newObjectArray(SPECIALIZATION_TYPE); 403 for (final MemberInfo mi : mis) { 404 dup(); 405 push(pos++); 406 visitTypeInsn(NEW, SPECIALIZATION_TYPE); 407 dup(); 408 visitLdcInsn(new Handle(H_INVOKESTATIC, className, mi.getJavaName(), mi.getJavaDesc())); 409 final Type linkLogicClass = mi.getLinkLogicClass(); 410 final boolean linkLogic = !linkLogicIsEmpty(linkLogicClass); 411 final String ctor = linkLogic ? SPECIALIZATION_INIT3 : SPECIALIZATION_INIT2; 412 if (linkLogic) { 413 visitLdcInsn(linkLogicClass); 414 } 415 visitInsn(mi.isOptimistic() ? ICONST_1 : ICONST_0); 416 visitMethodInsn(INVOKESPECIAL, SPECIALIZATION_TYPE, INIT, ctor, false); 417 arrayStore(TYPE_SPECIALIZATION); 418 } 419 } 420 421 void computeMaxs() { 422 // These values are ignored as we create class writer 423 // with ClassWriter.COMPUTE_MAXS flag. 424 super.visitMaxs(Short.MAX_VALUE, Short.MAX_VALUE); 425 } 426 427 // debugging support - print calls 428 void println(final String msg) { 429 super.visitFieldInsn(GETSTATIC, 430 "java/lang/System", 431 "out", 432 "Ljava/io/PrintStream;"); 433 super.visitLdcInsn(msg); 434 super.visitMethodInsn(INVOKEVIRTUAL, 435 "java/io/PrintStream", 436 "println", 437 "(Ljava/lang/String;)V", 438 false); 439 } 440 441 // print the object on the top of the stack 442 void printObject() { 443 super.visitFieldInsn(GETSTATIC, 444 "java/lang/System", 445 "out", 446 "Ljava/io/PrintStream;"); 447 super.visitInsn(SWAP); 448 super.visitMethodInsn(INVOKEVIRTUAL, 449 "java/io/PrintStream", 450 "println", 451 "(Ljava/lang/Object;)V", 452 false); 453 } 454 }