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 }