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