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