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