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.codegen;
  27 
  28 import static jdk.nashorn.internal.lookup.Lookup.MH;
  29 
  30 import java.lang.invoke.MethodHandle;
  31 import java.lang.invoke.MethodHandles;
  32 import java.util.HashSet;
  33 import java.util.Iterator;
  34 import java.util.Set;
  35 import jdk.internal.org.objectweb.asm.MethodVisitor;
  36 import jdk.internal.org.objectweb.asm.Opcodes;
  37 import jdk.nashorn.internal.codegen.types.Type;
  38 import jdk.nashorn.internal.runtime.ScriptFunction;
  39 import jdk.nashorn.internal.runtime.ScriptObject;
  40 import jdk.nashorn.internal.runtime.Source;
  41 
  42 /**
  43  * This class represents constant names of variables, methods and fields in
  44  * the compiler
  45  */
  46 
  47 public enum CompilerConstants {
  48     /** the __FILE__ variable */
  49     __FILE__,
  50 
  51     /** the __DIR__ variable */
  52     __DIR__,
  53 
  54     /** the __LINE__ variable */
  55     __LINE__,
  56 
  57     /** constructor name */
  58     INIT("<init>"),
  59 
  60     /** static initializer name */
  61     CLINIT("<clinit>"),
  62 
  63     /** eval name */
  64     EVAL("eval"),
  65 
  66     /** source name and class */
  67     SOURCE("source", Source.class),
  68 
  69     /** constants name and class */
  70     CONSTANTS("constants", Object[].class),
  71 
  72     /** strict mode field name and type */
  73     STRICT_MODE("strictMode", boolean.class),
  74 
  75     /** default script name */
  76     DEFAULT_SCRIPT_NAME("Script"),
  77 
  78     /** function prefix for anonymous functions */
  79     ANON_FUNCTION_PREFIX("L:"),
  80 
  81     /** separator for method names of nested functions */
  82     NESTED_FUNCTION_SEPARATOR("#"),
  83 
  84     /** separator for making method names unique by appending numeric ids */
  85     ID_FUNCTION_SEPARATOR("-"),
  86 
  87     /** method name for Java method that is the program entry point */
  88     PROGRAM(":program"),
  89 
  90     /** method name for Java method that creates the script function for the program */
  91     CREATE_PROGRAM_FUNCTION(":createProgramFunction"),
  92 
  93     /**
  94      * "this" name symbol for a parameter representing ECMAScript "this" in static methods that are compiled
  95      * representations of ECMAScript functions. It is not assigned a slot, as its position in the method signature is
  96      * dependent on other factors (most notably, callee can precede it).
  97      */
  98     THIS("this", Object.class),
  99 
 100     /** this debugger symbol */
 101     THIS_DEBUGGER(":this"),
 102 
 103     /** scope name, type and slot */
 104     SCOPE(":scope", ScriptObject.class, 2),
 105 
 106     /** the return value variable name were intermediate results are stored for scripts */
 107     RETURN(":return"),
 108 
 109     /** the callee value variable when necessary */
 110     CALLEE(":callee", ScriptFunction.class),
 111 
 112     /** the varargs variable when necessary */
 113     VARARGS(":varargs", Object[].class),
 114 
 115     /** the arguments variable (visible to function body). Initially set to ARGUMENTS, but can be reassigned by code in
 116      * the function body.*/
 117     ARGUMENTS_VAR("arguments", Object.class),
 118 
 119     /** the internal arguments object, when necessary (not visible to scripts, can't be reassigned). */
 120     ARGUMENTS(":arguments", ScriptObject.class),
 121 
 122     /** prefix for apply-to-call exploded arguments */
 123     EXPLODED_ARGUMENT_PREFIX(":xarg"),
 124 
 125     /** prefix for iterators for for (x in ...) */
 126     ITERATOR_PREFIX(":i", Iterator.class),
 127 
 128     /** prefix for tag variable used for switch evaluation */
 129     SWITCH_TAG_PREFIX(":s"),
 130 
 131     /** prefix for JVM exceptions */
 132     EXCEPTION_PREFIX(":e", Throwable.class),
 133 
 134     /** prefix for quick slots generated in Store */
 135     QUICK_PREFIX(":q"),
 136 
 137     /** prefix for temporary variables */
 138     TEMP_PREFIX(":t"),
 139 
 140     /** prefix for literals */
 141     LITERAL_PREFIX(":l"),
 142 
 143     /** prefix for regexps */
 144     REGEX_PREFIX(":r"),
 145 
 146     /** "this" used in non-static Java methods; always in slot 0 */
 147     JAVA_THIS(null, 0),
 148 
 149     /** Map parameter in scope object constructors; always in slot 1 */
 150     INIT_MAP(null, 1),
 151 
 152     /** Parent scope parameter in scope object constructors; always in slot 2 */
 153     INIT_SCOPE(null, 2),
 154 
 155     /** Arguments parameter in scope object constructors; in slot 3 when present */
 156     INIT_ARGUMENTS(null, 3),
 157 
 158     /** prefix for all ScriptObject subclasses with dual object/primitive fields, see {@link ObjectClassGenerator} */
 159     JS_OBJECT_DUAL_FIELD_PREFIX("JD"),
 160 
 161     /** prefix for all ScriptObject subclasses with object fields only, see {@link ObjectClassGenerator} */
 162     JS_OBJECT_SINGLE_FIELD_PREFIX("JO"),
 163 
 164     /** name for allocate method in JO objects */
 165     ALLOCATE("allocate"),
 166 
 167     /** prefix for split methods, @see Splitter */
 168     SPLIT_PREFIX(":split"),
 169 
 170     /** prefix for split array method and slot */
 171     SPLIT_ARRAY_ARG(":split_array", 3),
 172 
 173     /** get string from constant pool */
 174     GET_STRING(":getString"),
 175 
 176     /** get map */
 177     GET_MAP(":getMap"),
 178 
 179     /** set map */
 180     SET_MAP(":setMap"),
 181 
 182     /** get array prefix */
 183     GET_ARRAY_PREFIX(":get"),
 184 
 185     /** get array suffix */
 186     GET_ARRAY_SUFFIX("$array");
 187 
 188     /** To save memory - intern the compiler constant symbol names, as they are frequently reused */
 189     static {
 190         for (final CompilerConstants c : values()) {
 191             final String symbolName = c.symbolName();
 192             if (symbolName != null) {
 193                 symbolName.intern();
 194             }
 195         }
 196     }
 197 
 198     private static Set<String> symbolNames;
 199 
 200     /**
 201      * Prefix used for internal methods generated in script classes.
 202      */
 203     private static final String INTERNAL_METHOD_PREFIX = ":";
 204 
 205     private final String symbolName;
 206     private final Class<?> type;
 207     private final int slot;
 208 
 209     private CompilerConstants() {
 210         this.symbolName = name();
 211         this.type = null;
 212         this.slot = -1;
 213     }
 214 
 215     private CompilerConstants(final String symbolName) {
 216         this(symbolName, -1);
 217     }
 218 
 219     private CompilerConstants(final String symbolName, final int slot) {
 220         this(symbolName, null, slot);
 221     }
 222 
 223     private CompilerConstants(final String symbolName, final Class<?> type) {
 224         this(symbolName, type, -1);
 225     }
 226 
 227     private CompilerConstants(final String symbolName, final Class<?> type, final int slot) {
 228         this.symbolName = symbolName;
 229         this.type       = type;
 230         this.slot       = slot;
 231     }
 232 
 233     /**
 234      * Check whether a name is that of a reserved compiler constant
 235      * @param name name
 236      * @return true if compiler constant name
 237      */
 238     public static boolean isCompilerConstant(final String name) {
 239         ensureSymbolNames();
 240         return symbolNames.contains(name);
 241     }
 242 
 243     private static void ensureSymbolNames() {
 244         if(symbolNames == null) {
 245             symbolNames = new HashSet<>();
 246             for(final CompilerConstants cc: CompilerConstants.values()) {
 247                 symbolNames.add(cc.symbolName);
 248             }
 249         }
 250     }
 251 
 252     /**
 253      * Return the tag for this compile constant. Deliberately avoiding "name" here
 254      * not to conflate with enum implementation. This is the master string for the
 255      * constant - every constant has one.
 256      *
 257      * @return the tag
 258      */
 259     public final String symbolName() {
 260         return symbolName;
 261     }
 262 
 263     /**
 264      * Return the type for this compile constant
 265      *
 266      * @return type for this constant's instances, or null if N/A
 267      */
 268     public final Class<?> type() {
 269         return type;
 270     }
 271 
 272     /**
 273      * Return the slot for this compile constant
 274      *
 275      * @return byte code slot where constant is stored or -1 if N/A
 276      */
 277     public final int slot() {
 278         return slot;
 279     }
 280 
 281     /**
 282      * Return a descriptor for this compile constant. Only relevant if it has
 283      * a type
 284      *
 285      * @return descriptor the descriptor
 286      */
 287     public final String descriptor() {
 288         assert type != null : " asking for descriptor of typeless constant";
 289         return typeDescriptor(type);
 290     }
 291 
 292     /**
 293      * Get the internal class name for a type
 294      *
 295      * @param type a type
 296      * @return  the internal name for this type
 297      */
 298     public static String className(final Class<?> type) {
 299         return Type.getInternalName(type);
 300     }
 301 
 302     /**
 303      * Get the method descriptor for a given method type collection
 304      *
 305      * @param rtype  return type
 306      * @param ptypes parameter types
 307      *
 308      * @return internal descriptor for this method
 309      */
 310     public static String methodDescriptor(final Class<?> rtype, final Class<?>... ptypes) {
 311         return Type.getMethodDescriptor(rtype, ptypes);
 312     }
 313 
 314     /**
 315      * Get the type descriptor for a type
 316      *
 317      * @param clazz a type
 318      *
 319      * @return the internal descriptor for this type
 320      */
 321     public static String typeDescriptor(final Class<?> clazz) {
 322         return Type.typeFor(clazz).getDescriptor();
 323     }
 324 
 325     /**
 326      * Create a call representing a void constructor for a given type. Don't
 327      * attempt to look this up at compile time
 328      *
 329      * @param clazz the class
 330      *
 331      * @return Call representing void constructor for type
 332      */
 333     public static Call constructorNoLookup(final Class<?> clazz) {
 334         return specialCallNoLookup(clazz, INIT.symbolName(), void.class);
 335     }
 336 
 337     /**
 338      * Create a call representing a constructor for a given type. Don't
 339      * attempt to look this up at compile time
 340      *
 341      * @param className the type class name
 342      * @param ptypes    the parameter types for the constructor
 343      *
 344      * @return Call representing constructor for type
 345      */
 346     public static Call constructorNoLookup(final String className, final Class<?>... ptypes) {
 347         return specialCallNoLookup(className, INIT.symbolName(), methodDescriptor(void.class, ptypes));
 348     }
 349 
 350     /**
 351      * Create a call representing a constructor for a given type. Don't
 352      * attempt to look this up at compile time
 353      *
 354      * @param clazz  the class name
 355      * @param ptypes the parameter types for the constructor
 356      *
 357      * @return Call representing constructor for type
 358      */
 359     public static Call constructorNoLookup(final Class<?> clazz, final Class<?>... ptypes) {
 360         return specialCallNoLookup(clazz, INIT.symbolName(), void.class, ptypes);
 361     }
 362 
 363     /**
 364      * Create a call representing an invokespecial to a given method. Don't
 365      * attempt to look this up at compile time
 366      *
 367      * @param className the class name
 368      * @param name      the method name
 369      * @param desc      the descriptor
 370      *
 371      * @return Call representing specified invokespecial call
 372      */
 373     public static Call specialCallNoLookup(final String className, final String name, final String desc) {
 374         return new Call(null, className, name, desc) {
 375             @Override
 376             MethodEmitter invoke(final MethodEmitter method) {
 377                 return method.invokespecial(className, name, descriptor);
 378             }
 379 
 380             @Override
 381             public void invoke(final MethodVisitor mv) {
 382                 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, name, desc, false);
 383             }
 384         };
 385     }
 386 
 387     /**
 388      * Create a call representing an invokespecial to a given method. Don't
 389      * attempt to look this up at compile time
 390      *
 391      * @param clazz  the class
 392      * @param name   the method name
 393      * @param rtype  the return type
 394      * @param ptypes the parameter types
 395      *
 396      * @return Call representing specified invokespecial call
 397      */
 398     public static Call specialCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
 399         return specialCallNoLookup(className(clazz), name, methodDescriptor(rtype, ptypes));
 400     }
 401 
 402     /**
 403      * Create a call representing an invokestatic to a given method. Don't
 404      * attempt to look this up at compile time
 405      *
 406      * @param className the class name
 407      * @param name      the method name
 408      * @param desc      the descriptor
 409      *
 410      * @return Call representing specified invokestatic call
 411      */
 412     public static Call staticCallNoLookup(final String className, final String name, final String desc) {
 413         return new Call(null, className, name, desc) {
 414             @Override
 415             MethodEmitter invoke(final MethodEmitter method) {
 416                 return method.invokestatic(className, name, descriptor);
 417             }
 418 
 419             @Override
 420             public void invoke(final MethodVisitor mv) {
 421                 mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, name, desc, false);
 422             }
 423         };
 424     }
 425 
 426     /**
 427      * Create a call representing an invokestatic to a given method. Don't
 428      * attempt to look this up at compile time
 429      *
 430      * @param clazz  the class
 431      * @param name   the method name
 432      * @param rtype  the return type
 433      * @param ptypes the parameter types
 434      *
 435      * @return Call representing specified invokestatic call
 436      */
 437     public static Call staticCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
 438         return staticCallNoLookup(className(clazz), name, methodDescriptor(rtype, ptypes));
 439     }
 440 
 441     /**
 442      * Create a call representing an invokevirtual to a given method. Don't
 443      * attempt to look this up at compile time
 444      *
 445      * @param clazz  the class
 446      * @param name   the method name
 447      * @param rtype  the return type
 448      * @param ptypes the parameter types
 449      *
 450      * @return Call representing specified invokevirtual call
 451      */
 452     public static Call virtualCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
 453         return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) {
 454             @Override
 455             MethodEmitter invoke(final MethodEmitter method) {
 456                 return method.invokevirtual(className, name, descriptor);
 457             }
 458 
 459             @Override
 460             public void invoke(final MethodVisitor mv) {
 461                 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, name, descriptor, false);
 462             }
 463         };
 464     }
 465 
 466     /**
 467      * Create a call representing an invokeinterface to a given method. Don't
 468      * attempt to look this up at compile time
 469      *
 470      * @param clazz  the class
 471      * @param name   the method name
 472      * @param rtype  the return type
 473      * @param ptypes the parameter types
 474      *
 475      * @return Call representing specified invokeinterface call
 476      */
 477     public static Call interfaceCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
 478         return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) {
 479             @Override
 480             MethodEmitter invoke(final MethodEmitter method) {
 481                 return method.invokeinterface(className, name, descriptor);
 482             }
 483 
 484             @Override
 485             public void invoke(final MethodVisitor mv) {
 486                 mv.visitMethodInsn(Opcodes.INVOKEINTERFACE, className, name, descriptor, true);
 487             }
 488         };
 489     }
 490 
 491     /**
 492      * Create a FieldAccess representing a virtual field, that can be subject to put
 493      * or get operations
 494      *
 495      * @param className name of the class where the field is a member
 496      * @param name      name of the field
 497      * @param desc      type descriptor of the field
 498      *
 499      * @return a field access object giving access code generation method for the virtual field
 500      */
 501     public static FieldAccess virtualField(final String className, final String name, final String desc) {
 502         return new FieldAccess(className, name, desc) {
 503             @Override
 504             public MethodEmitter get(final MethodEmitter method) {
 505                 return method.getField(className, name, descriptor);
 506             }
 507 
 508             @Override
 509             public void put(final MethodEmitter method) {
 510                 method.putField(className, name, descriptor);
 511             }
 512         };
 513     }
 514 
 515     /**
 516      * Create a FieldAccess representing a virtual field, that can be subject to put
 517      * or get operations
 518      *
 519      * @param clazz class where the field is a member
 520      * @param name  name of the field
 521      * @param type  type of the field
 522      *
 523      * @return a field access object giving access code generation method for the virtual field
 524      */
 525     public static FieldAccess virtualField(final Class<?> clazz, final String name, final Class<?> type) {
 526         return virtualField(className(clazz), name, typeDescriptor(type));
 527     }
 528 
 529     /**
 530      * Create a FieldAccess representing a static field, that can be subject to put
 531      * or get operations
 532      *
 533      * @param className name of the class where the field is a member
 534      * @param name      name of the field
 535      * @param desc      type descriptor of the field
 536      *
 537      * @return a field access object giving access code generation method for the static field
 538      */
 539     public static FieldAccess staticField(final String className, final String name, final String desc) {
 540         return new FieldAccess(className, name, desc) {
 541             @Override
 542             public MethodEmitter get(final MethodEmitter method) {
 543                 return method.getStatic(className, name, descriptor);
 544             }
 545 
 546             @Override
 547             public void put(final MethodEmitter method) {
 548                 method.putStatic(className, name, descriptor);
 549             }
 550         };
 551     }
 552 
 553     /**
 554      * Create a FieldAccess representing a static field, that can be subject to put
 555      * or get operations
 556      *
 557      * @param clazz class where the field is a member
 558      * @param name  name of the field
 559      * @param type  type of the field
 560      *
 561      * @return a field access object giving access code generation method for the virtual field
 562      */
 563     public static FieldAccess staticField(final Class<?> clazz, final String name, final Class<?> type) {
 564         return staticField(className(clazz), name, typeDescriptor(type));
 565     }
 566 
 567     /**
 568      * Create a static call, given an explicit lookup, looking up the method handle for it at the same time
 569      *
 570      * @param lookup the lookup
 571      * @param clazz  the class
 572      * @param name   the name of the method
 573      * @param rtype  the return type
 574      * @param ptypes the parameter types
 575      *
 576      * @return the call object representing the static call
 577      */
 578     public static Call staticCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
 579         return new Call(MH.findStatic(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) {
 580             @Override
 581             MethodEmitter invoke(final MethodEmitter method) {
 582                 return method.invokestatic(className, name, descriptor);
 583             }
 584 
 585             @Override
 586             public void invoke(final MethodVisitor mv) {
 587                 mv.visitMethodInsn(Opcodes.INVOKESTATIC, className, name, descriptor, false);
 588             }
 589         };
 590     }
 591 
 592     /**
 593      * Create a virtual call, given an explicit lookup, looking up the method handle for it at the same time
 594      *
 595      * @param lookup the lookup
 596      * @param clazz  the class
 597      * @param name   the name of the method
 598      * @param rtype  the return type
 599      * @param ptypes the parameter types
 600      *
 601      * @return the call object representing the virtual call
 602      */
 603     public static Call virtualCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
 604         return new Call(MH.findVirtual(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) {
 605             @Override
 606             MethodEmitter invoke(final MethodEmitter method) {
 607                 return method.invokevirtual(className, name, descriptor);
 608             }
 609 
 610             @Override
 611             public void invoke(final MethodVisitor mv) {
 612                 mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, className, name, descriptor, false);
 613             }
 614         };
 615     }
 616 
 617     /**
 618      * Create a special call, given an explicit lookup, looking up the method handle for it at the same time.
 619      * clazz is used as this class
 620      *
 621      * @param lookup    the lookup
 622      * @param clazz     the class
 623      * @param name      the name of the method
 624      * @param rtype     the return type
 625      * @param ptypes    the parameter types
 626      *
 627      * @return the call object representing the virtual call
 628      */
 629     public static Call specialCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
 630         return new Call(MH.findSpecial(lookup, clazz, name, MH.type(rtype, ptypes), clazz), className(clazz), name, methodDescriptor(rtype, ptypes)) {
 631             @Override
 632             MethodEmitter invoke(final MethodEmitter method) {
 633                 return method.invokespecial(className, name, descriptor);
 634             }
 635 
 636             @Override
 637             public void invoke(final MethodVisitor mv) {
 638                 mv.visitMethodInsn(Opcodes.INVOKESPECIAL, className, name, descriptor, false);
 639             }
 640         };
 641     }
 642 
 643     /**
 644      * Returns true if the passed string looks like a method name of an internally generated Nashorn method. Basically,
 645      * if it starts with a colon character {@code :} but is not the name of the program method {@code :program}.
 646      * Program function is not considered internal as we want it to show up in exception stack traces.
 647      * @param methodName the name of a method
 648      * @return true if it looks like an internal Nashorn method name.
 649      * @throws NullPointerException if passed null
 650      */
 651     public static boolean isInternalMethodName(final String methodName) {
 652         return methodName.startsWith(INTERNAL_METHOD_PREFIX) && !methodName.equals(PROGRAM.symbolName);
 653      }
 654 
 655     /**
 656      * Private class representing an access. This can generate code into a method code or
 657      * a field access.
 658      */
 659     private abstract static class Access {
 660         protected final MethodHandle methodHandle;
 661         protected final String       className;
 662         protected final String       name;
 663         protected final String       descriptor;
 664 
 665         /**
 666          * Constructor
 667          *
 668          * @param methodHandle methodHandle or null if none
 669          * @param className    class name for access
 670          * @param name         field or method name for access
 671          * @param descriptor   descriptor for access field or method
 672          */
 673         protected Access(final MethodHandle methodHandle, final String className, final String name, final String descriptor) {
 674             this.methodHandle = methodHandle;
 675             this.className    = className;
 676             this.name         = name;
 677             this.descriptor   = descriptor;
 678         }
 679 
 680         /**
 681          * Get the method handle, or null if access hasn't been looked up
 682          *
 683          * @return method handle
 684          */
 685         public MethodHandle methodHandle() {
 686             return methodHandle;
 687         }
 688 
 689         /**
 690          * Get the class name of the access
 691          *
 692          * @return the class name
 693          */
 694         public String className() {
 695             return className;
 696         }
 697 
 698         /**
 699          * Get the field name or method name of the access
 700          *
 701          * @return the name
 702          */
 703         public String name() {
 704             return name;
 705         }
 706 
 707         /**
 708          * Get the descriptor of the method or field of the access
 709          *
 710          * @return the descriptor
 711          */
 712         public String descriptor() {
 713             return descriptor;
 714         }
 715     }
 716 
 717     /**
 718      * Field access - this can be used for generating code for static or
 719      * virtual field accesses
 720      */
 721     public abstract static class FieldAccess extends Access {
 722         /**
 723          * Constructor
 724          *
 725          * @param className  name of the class where the field is
 726          * @param name       name of the field
 727          * @param descriptor descriptor of the field
 728          */
 729         protected FieldAccess(final String className, final String name, final String descriptor) {
 730             super(null, className, name, descriptor);
 731         }
 732 
 733         /**
 734          * Generate get code for the field
 735          *
 736          * @param emitter a method emitter
 737          *
 738          * @return the method emitter
 739          */
 740         protected abstract MethodEmitter get(final MethodEmitter emitter);
 741 
 742         /**
 743          * Generate put code for the field
 744          *
 745          * @param emitter a method emitter
 746          */
 747         protected abstract void put(final MethodEmitter emitter);
 748     }
 749 
 750     /**
 751      * Call - this can be used for generating code for different types of calls
 752      */
 753     public abstract static class Call extends Access {
 754 
 755         /**
 756          * Constructor
 757          *
 758          * @param className  class name for the method of the call
 759          * @param name       method name
 760          * @param descriptor method descriptor
 761          */
 762         protected Call(final String className, final String name, final String descriptor) {
 763             super(null, className, name, descriptor);
 764         }
 765 
 766         /**
 767          * Constructor
 768          *
 769          * @param methodHandle method handle for the call if resolved
 770          * @param className    class name for the method of the call
 771          * @param name         method name
 772          * @param descriptor   method descriptor
 773          */
 774         protected Call(final MethodHandle methodHandle, final String className, final String name, final String descriptor) {
 775             super(methodHandle, className, name, descriptor);
 776         }
 777 
 778         /**
 779          * Generate invocation code for the method
 780          *
 781          * @param emitter a method emitter
 782          *
 783          * @return the method emitter
 784          */
 785         abstract MethodEmitter invoke(final MethodEmitter emitter);
 786 
 787         /**
 788          * Generate invocation code for the method
 789          *
 790          * @param mv a method visitor
 791          */
 792         public abstract void invoke(final MethodVisitor mv);
 793     }
 794 
 795 }