blob: 1d978d963108cc1d4b1c0da8cd5d91270b5c9912 [file] [log] [blame]
/*
* Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package jdk.nashorn.internal.codegen;
import static jdk.nashorn.internal.lookup.Lookup.MH;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import jdk.nashorn.internal.codegen.types.Type;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.Source;
/**
* This class represents constant names of variables, methods and fields in
* the compiler
*/
public enum CompilerConstants {
/** the __FILE__ variable */
__FILE__,
/** the __DIR__ variable */
__DIR__,
/** the __LINE__ variable */
__LINE__,
/** lazy prefix for classes of jitted methods */
LAZY("Lazy"),
/** leaf tag used for functions that require no scope */
LEAF("__leaf__"),
/** constructor name */
INIT("<init>"),
/** static initializer name */
CLINIT("<clinit>"),
/** eval name */
EVAL("eval"),
/** source name and class */
SOURCE("source", Source.class),
/** constants name and class */
CONSTANTS("constants", Object[].class),
/** strict mode field name and type */
STRICT_MODE("strictMode", boolean.class),
/** default script name */
DEFAULT_SCRIPT_NAME("Script"),
/** function prefix for anonymous functions */
FUNCTION_PREFIX("function$"),
/** method name for Java method that is script entry point */
RUN_SCRIPT("runScript"),
/**
* "this" name symbol for a parameter representing ECMAScript "this" in static methods that are compiled
* representations of ECMAScript functions. It is not assigned a slot, as its position in the method signature is
* dependent on other factors (most notably, callee can precede it).
*/
THIS("this"),
/** this debugger symbol */
THIS_DEBUGGER("__this__"),
/** scope name, type and slot */
SCOPE("__scope__", ScriptObject.class, 2),
/** the return value variable name were intermediate results are stored for scripts */
SCRIPT_RETURN("__return__"),
/** the callee value variable when necessary */
CALLEE("__callee__", ScriptFunction.class),
/** the varargs variable when necessary */
VARARGS("__varargs__"),
/** the arguments vector when necessary and the slot */
ARGUMENTS("arguments", Object.class, 2),
/** prefix for iterators for for (x in ...) */
ITERATOR_PREFIX("$iter"),
/** prefix for tag variable used for switch evaluation */
SWITCH_TAG_PREFIX("$tag"),
/** prefix for all exceptions */
EXCEPTION_PREFIX("$exception"),
/** prefix for quick slots generated in Store */
QUICK_PREFIX("$quick"),
/** prefix for temporary variables */
TEMP_PREFIX("$temp"),
/** prefix for literals */
LITERAL_PREFIX("$lit"),
/** prefix for map */
MAP("$map", 1),
/** prefix for regexps */
REGEX_PREFIX("$regex"),
/** "this" used in non-static Java methods; always in slot 0 */
JAVA_THIS("this", 0),
/** init scope */
INIT_SCOPE("$scope", 2),
/** init arguments */
INIT_ARGUMENTS("$arguments", 3),
/** prefix for all ScriptObject subclasses with fields, @see ObjectGenerator */
JS_OBJECT_PREFIX("JO"),
/** name for allocate method in JO objects */
ALLOCATE("allocate"),
/** prefix for split methods, @see Splitter */
SPLIT_PREFIX("$split"),
/** prefix for split array method and slot */
SPLIT_ARRAY_ARG("split_array", 3),
/** get string from constant pool */
GET_STRING("$getString"),
/** get map */
GET_MAP("$getMap"),
/** get map */
SET_MAP("$setMap"),
/** get array prefix */
GET_ARRAY_PREFIX("$get"),
/** get array suffix */
GET_ARRAY_SUFFIX("$array");
private final String tag;
private final Class<?> type;
private final int slot;
private CompilerConstants() {
this.tag = name();
this.type = null;
this.slot = -1;
}
private CompilerConstants(final String tag) {
this(tag, -1);
}
private CompilerConstants(final String tag, final int slot) {
this(tag, null, slot);
}
private CompilerConstants(final String tag, final Class<?> type) {
this(tag, type, -1);
}
private CompilerConstants(final String tag, final Class<?> type, final int slot) {
this.tag = tag;
this.type = type;
this.slot = slot;
}
/**
* Return the tag for this compile constant. Deliberately avoiding "name" here
* not to conflate with enum implementation. This is the master string for the
* constant - every constant has one.
*
* @return the tag
*/
public final String tag() {
return tag;
}
/**
* Return the type for this compile constant
*
* @return type for this constant's instances, or null if N/A
*/
public final Class<?> type() {
return type;
}
/**
* Return the slot for this compile constant
*
* @return byte code slot where constant is stored or -1 if N/A
*/
public final int slot() {
return slot;
}
/**
* Return a descriptor for this compile constant. Only relevant if it has
* a type
*
* @return descriptor the descriptor
*/
public final String descriptor() {
assert type != null : " asking for descriptor of typeless constant";
return typeDescriptor(type);
}
/**
* Get the internal class name for a type
*
* @param type a type
* @return the internal name for this type
*/
public static String className(final Class<?> type) {
return Type.getInternalName(type);
}
/**
* Get the method descriptor for a given method type collection
*
* @param rtype return type
* @param ptypes parameter types
*
* @return internal descriptor for this method
*/
public static String methodDescriptor(final Class<?> rtype, final Class<?>... ptypes) {
return Type.getMethodDescriptor(rtype, ptypes);
}
/**
* Get the type descriptor for a type
*
* @param clazz a type
*
* @return the internal descriptor for this type
*/
public static String typeDescriptor(final Class<?> clazz) {
return Type.getDescriptor(clazz);
}
/**
* Create a call representing a void constructor for a given type. Don't
* attempt to look this up at compile time
*
* @param clazz the class
*
* @return Call representing void constructor for type
*/
public static Call constructorNoLookup(final Class<?> clazz) {
return specialCallNoLookup(clazz, INIT.tag(), void.class);
}
/**
* Create a call representing a constructor for a given type. Don't
* attempt to look this up at compile time
*
* @param className the type class name
* @param ptypes the parameter types for the constructor
*
* @return Call representing constructor for type
*/
public static Call constructorNoLookup(final String className, final Class<?>... ptypes) {
return specialCallNoLookup(className, INIT.tag(), methodDescriptor(void.class, ptypes));
}
/**
* Create a call representing a constructor for a given type. Don't
* attempt to look this up at compile time
*
* @param clazz the class name
* @param ptypes the parameter types for the constructor
*
* @return Call representing constructor for type
*/
public static Call constructorNoLookup(final Class<?> clazz, final Class<?>... ptypes) {
return specialCallNoLookup(clazz, INIT.tag(), void.class, ptypes);
}
/**
* Create a call representing an invokespecial to a given method. Don't
* attempt to look this up at compile time
*
* @param className the class name
* @param name the method name
* @param desc the descriptor
*
* @return Call representing specified invokespecial call
*/
public static Call specialCallNoLookup(final String className, final String name, final String desc) {
return new Call(null, className, name, desc) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
return method.invokespecial(className, name, descriptor);
}
};
}
/**
* Create a call representing an invokespecial to a given method. Don't
* attempt to look this up at compile time
*
* @param clazz the class
* @param name the method name
* @param rtype the return type
* @param ptypes the parameter types
*
* @return Call representing specified invokespecial call
*/
public static Call specialCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return specialCallNoLookup(className(clazz), name, methodDescriptor(rtype, ptypes));
}
/**
* Create a call representing an invokestatic to a given method. Don't
* attempt to look this up at compile time
*
* @param className the class name
* @param name the method name
* @param desc the descriptor
*
* @return Call representing specified invokestatic call
*/
public static Call staticCallNoLookup(final String className, final String name, final String desc) {
return new Call(null, className, name, desc) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
return method.invokestatic(className, name, descriptor);
}
};
}
/**
* Create a call representing an invokestatic to a given method. Don't
* attempt to look this up at compile time
*
* @param clazz the class
* @param name the method name
* @param rtype the return type
* @param ptypes the parameter types
*
* @return Call representing specified invokestatic call
*/
public static Call staticCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return staticCallNoLookup(className(clazz), name, methodDescriptor(rtype, ptypes));
}
/**
* Create a call representing an invokevirtual to a given method. Don't
* attempt to look this up at compile time
*
* @param clazz the class
* @param name the method name
* @param rtype the return type
* @param ptypes the parameter types
*
* @return Call representing specified invokevirtual call
*/
public static Call virtualCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
return method.invokevirtual(className, name, descriptor);
}
};
}
/**
* Create a call representing an invokeinterface to a given method. Don't
* attempt to look this up at compile time
*
* @param clazz the class
* @param name the method name
* @param rtype the return type
* @param ptypes the parameter types
*
* @return Call representing specified invokeinterface call
*/
public static Call interfaceCallNoLookup(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Call(null, className(clazz), name, methodDescriptor(rtype, ptypes)) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
return method.invokeinterface(className, name, descriptor);
}
};
}
/**
* Create a FieldAccess representing a virtual field, that can be subject to put
* or get operations
*
* @param className name of the class where the field is a member
* @param name name of the field
* @param desc type descriptor of the field
*
* @return a field access object giving access code generation method for the virtual field
*/
public static FieldAccess virtualField(final String className, final String name, final String desc) {
return new FieldAccess(className, name, desc) {
@Override
public MethodEmitter get(final MethodEmitter method) {
return method.getField(className, name, descriptor);
}
@Override
public void put(final MethodEmitter method) {
method.putField(className, name, descriptor);
}
};
}
/**
* Create a FieldAccess representing a virtual field, that can be subject to put
* or get operations
*
* @param clazz class where the field is a member
* @param name name of the field
* @param type type of the field
*
* @return a field access object giving access code generation method for the virtual field
*/
public static FieldAccess virtualField(final Class<?> clazz, final String name, final Class<?> type) {
return virtualField(className(clazz), name, typeDescriptor(type));
}
/**
* Create a FieldAccess representing a static field, that can be subject to put
* or get operations
*
* @param className name of the class where the field is a member
* @param name name of the field
* @param desc type descriptor of the field
*
* @return a field access object giving access code generation method for the static field
*/
public static FieldAccess staticField(final String className, final String name, final String desc) {
return new FieldAccess(className, name, desc) {
@Override
public MethodEmitter get(final MethodEmitter method) {
return method.getStatic(className, name, descriptor);
}
@Override
public void put(final MethodEmitter method) {
method.putStatic(className, name, descriptor);
}
};
}
/**
* Create a FieldAccess representing a static field, that can be subject to put
* or get operations
*
* @param clazz class where the field is a member
* @param name name of the field
* @param type type of the field
*
* @return a field access object giving access code generation method for the virtual field
*/
public static FieldAccess staticField(final Class<?> clazz, final String name, final Class<?> type) {
return staticField(className(clazz), name, typeDescriptor(type));
}
/**
* Create a static call, looking up the method handle for it at the same time
*
* @param clazz the class
* @param name the name of the method
* @param rtype the return type of the method
* @param ptypes the parameter types of the method
*
* @return the call object representing the static call
*/
public static Call staticCall(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return staticCall(MethodHandles.publicLookup(), clazz, name, rtype, ptypes);
}
/**
* Create a static call, given an explicit lookup, looking up the method handle for it at the same time
*
* @param lookup the lookup
* @param clazz the class
* @param name the name of the method
* @param rtype the return type
* @param ptypes the parameter types
*
* @return the call object representing the static call
*/
public static Call staticCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Call(MH.findStatic(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
return method.invokestatic(className, name, descriptor);
}
};
}
/**
* Create a virtual call, looking up the method handle for it at the same time
*
* @param clazz the class
* @param name the name of the method
* @param rtype the return type of the method
* @param ptypes the parameter types of the method
*
* @return the call object representing the virtual call
*/
public static Call virtualCall(final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return virtualCall(MethodHandles.publicLookup(), clazz, name, rtype, ptypes);
}
/**
* Create a virtual call, given an explicit lookup, looking up the method handle for it at the same time
*
* @param lookup the lookup
* @param clazz the class
* @param name the name of the method
* @param rtype the return type
* @param ptypes the parameter types
*
* @return the call object representing the virtual call
*/
public static Call virtualCall(final MethodHandles.Lookup lookup, final Class<?> clazz, final String name, final Class<?> rtype, final Class<?>... ptypes) {
return new Call(MH.findVirtual(lookup, clazz, name, MH.type(rtype, ptypes)), className(clazz), name, methodDescriptor(rtype, ptypes)) {
@Override
public MethodEmitter invoke(final MethodEmitter method) {
return method.invokevirtual(className, name, descriptor);
}
};
}
/**
* Private class representing an access. This can generate code into a method code or
* a field access.
*/
private abstract static class Access {
protected final MethodHandle methodHandle;
protected final String className;
protected final String name;
protected final String descriptor;
/**
* Constructor
*
* @param methodHandle methodHandle or null if none
* @param className class name for access
* @param name field or method name for access
* @param descriptor descriptor for access field or method
*/
protected Access(final MethodHandle methodHandle, final String className, final String name, final String descriptor) {
this.methodHandle = methodHandle;
this.className = className;
this.name = name;
this.descriptor = descriptor;
}
/**
* Get the method handle, or null if access hasn't been looked up
*
* @return method handle
*/
public MethodHandle methodHandle() {
return methodHandle;
}
/**
* Get the class name of the access
*
* @return the class name
*/
public String className() {
return className;
}
/**
* Get the field name or method name of the access
*
* @return the name
*/
public String name() {
return name;
}
/**
* Get the descriptor of the method or field of the access
*
* @return the descriptor
*/
public String descriptor() {
return descriptor;
}
}
/**
* Field access - this can be used for generating code for static or
* virtual field accesses
*/
public abstract static class FieldAccess extends Access {
/**
* Constructor
*
* @param className name of the class where the field is
* @param name name of the field
* @param descriptor descriptor of the field
*/
protected FieldAccess(final String className, final String name, final String descriptor) {
super(null, className, name, descriptor);
}
/**
* Generate get code for the field
*
* @param emitter a method emitter
*
* @return the method emitter
*/
protected abstract MethodEmitter get(final MethodEmitter emitter);
/**
* Generate put code for the field
*
* @param emitter a method emitter
*/
protected abstract void put(final MethodEmitter emitter);
}
/**
* Call - this can be used for generating code for different types of calls
*/
public abstract static class Call extends Access {
/**
* Constructor
*
* @param className class name for the method of the call
* @param name method name
* @param descriptor method descriptor
*/
protected Call(final String className, final String name, final String descriptor) {
super(null, className, name, descriptor);
}
/**
* Constructor
*
* @param methodHandle method handle for the call if resolved
* @param className class name for the method of the call
* @param name method name
* @param descriptor method descriptor
*/
protected Call(final MethodHandle methodHandle, final String className, final String name, final String descriptor) {
super(methodHandle, className, name, descriptor);
}
/**
* Generate invocation code for the method
*
* @param emitter a method emitter
*
* @return the method emitter
*/
protected abstract MethodEmitter invoke(final MethodEmitter emitter);
}
}