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