src/jdk/nashorn/internal/codegen/types/Type.java

Mon, 03 Nov 2014 11:47:41 +0100

author
lagergren
date
Mon, 03 Nov 2014 11:47:41 +0100
changeset 1082
e1e27c4262be
parent 1071
78eb2b415108
child 1086
d0b26e6f602c
permissions
-rw-r--r--

8060204: Fix warnings in Joni and tests
Reviewed-by: hannesw, sundar, attila

jlaskey@3 1 /*
jlaskey@7 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved.
jlaskey@3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
jlaskey@3 4 *
jlaskey@3 5 * This code is free software; you can redistribute it and/or modify it
jlaskey@3 6 * under the terms of the GNU General Public License version 2 only, as
jlaskey@3 7 * published by the Free Software Foundation. Oracle designates this
jlaskey@3 8 * particular file as subject to the "Classpath" exception as provided
jlaskey@3 9 * by Oracle in the LICENSE file that accompanied this code.
jlaskey@3 10 *
jlaskey@3 11 * This code is distributed in the hope that it will be useful, but WITHOUT
jlaskey@3 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
jlaskey@3 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
jlaskey@3 14 * version 2 for more details (a copy is included in the LICENSE file that
jlaskey@3 15 * accompanied this code).
jlaskey@3 16 *
jlaskey@3 17 * You should have received a copy of the GNU General Public License version
jlaskey@3 18 * 2 along with this work; if not, write to the Free Software Foundation,
jlaskey@3 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
jlaskey@3 20 *
jlaskey@3 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
jlaskey@3 22 * or visit www.oracle.com if you need additional information or have any
jlaskey@3 23 * questions.
jlaskey@3 24 */
jlaskey@3 25
jlaskey@3 26 package jdk.nashorn.internal.codegen.types;
jlaskey@3 27
jlaskey@3 28 import static jdk.internal.org.objectweb.asm.Opcodes.DALOAD;
jlaskey@3 29 import static jdk.internal.org.objectweb.asm.Opcodes.DASTORE;
jlaskey@3 30 import static jdk.internal.org.objectweb.asm.Opcodes.DUP;
jlaskey@3 31 import static jdk.internal.org.objectweb.asm.Opcodes.DUP2;
jlaskey@3 32 import static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X1;
jlaskey@3 33 import static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X2;
jlaskey@3 34 import static jdk.internal.org.objectweb.asm.Opcodes.DUP_X1;
jlaskey@3 35 import static jdk.internal.org.objectweb.asm.Opcodes.DUP_X2;
attila@963 36 import static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC;
jlaskey@3 37 import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
jlaskey@3 38 import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
jlaskey@3 39 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
lagergren@395 40 import static jdk.internal.org.objectweb.asm.Opcodes.LALOAD;
jlaskey@3 41 import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
jlaskey@3 42 import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY;
jlaskey@3 43 import static jdk.internal.org.objectweb.asm.Opcodes.POP;
jlaskey@3 44 import static jdk.internal.org.objectweb.asm.Opcodes.POP2;
jlaskey@3 45 import static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
jlaskey@3 46 import static jdk.internal.org.objectweb.asm.Opcodes.T_DOUBLE;
jlaskey@3 47 import static jdk.internal.org.objectweb.asm.Opcodes.T_INT;
lagergren@395 48 import static jdk.internal.org.objectweb.asm.Opcodes.T_LONG;
attila@963 49 import static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup;
attila@1063 50
attila@963 51 import java.io.DataInput;
attila@963 52 import java.io.DataOutput;
attila@963 53 import java.io.IOException;
attila@1063 54 import java.io.Serializable;
attila@963 55 import java.lang.invoke.CallSite;
jlaskey@3 56 import java.lang.invoke.MethodHandle;
attila@963 57 import java.lang.invoke.MethodHandles;
attila@963 58 import java.lang.invoke.MethodType;
lagergren@1029 59 import java.util.Collections;
attila@963 60 import java.util.Map;
attila@963 61 import java.util.TreeMap;
lagergren@1029 62 import java.util.WeakHashMap;
attila@422 63 import java.util.concurrent.ConcurrentHashMap;
attila@422 64 import java.util.concurrent.ConcurrentMap;
attila@963 65 import jdk.internal.org.objectweb.asm.Handle;
jlaskey@3 66 import jdk.internal.org.objectweb.asm.MethodVisitor;
jlaskey@3 67 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
attila@963 68 import jdk.nashorn.internal.runtime.ScriptObject;
attila@963 69 import jdk.nashorn.internal.runtime.Undefined;
attila@963 70 import jdk.nashorn.internal.runtime.linker.Bootstrap;
jlaskey@3 71
jlaskey@3 72 /**
jlaskey@3 73 * This is the representation of a JavaScript type, disassociated from java
jlaskey@3 74 * Classes, with the basis for conversion weight, mapping to ASM types
jlaskey@3 75 * and implementing the ByteCodeOps interface which tells this type
jlaskey@3 76 * how to generate code for various operations.
jlaskey@3 77 *
jlaskey@3 78 * Except for ClassEmitter, this is the only class that has to know
jlaskey@3 79 * about the underlying byte code generation system.
jlaskey@3 80 *
jlaskey@3 81 * The different types know how to generate bytecode for the different
jlaskey@3 82 * operations, inherited from BytecodeOps, that they support. This avoids
jlaskey@3 83 * if/else chains depending on type in several cases and allows for
jlaskey@3 84 * more readable and shorter code
jlaskey@3 85 *
jlaskey@3 86 * The Type class also contains logic used by the type inference and
jlaskey@3 87 * for comparing types against each other, as well as the concepts
jlaskey@3 88 * of narrower to wider types. The widest type is an object. Ideally we
jlaskey@3 89 * would like as narrow types as possible for code to be efficient, e.g
jlaskey@3 90 * INTs rather than OBJECTs
jlaskey@3 91 */
jlaskey@3 92
attila@1063 93 public abstract class Type implements Comparable<Type>, BytecodeOps, Serializable {
attila@1063 94 private static final long serialVersionUID = 1L;
jlaskey@3 95
jlaskey@3 96 /** Human readable name for type */
attila@1063 97 private transient final String name;
jlaskey@3 98
jlaskey@3 99 /** Descriptor for type */
attila@1063 100 private transient final String descriptor;
jlaskey@3 101
jlaskey@3 102 /** The "weight" of the type. Used for picking widest/least specific common type */
attila@1063 103 private transient final int weight;
jlaskey@3 104
jlaskey@3 105 /** How many bytecode slots does this type occupy */
attila@1063 106 private transient final int slots;
jlaskey@3 107
jlaskey@3 108 /** The class for this type */
jlaskey@3 109 private final Class<?> clazz;
jlaskey@3 110
lagergren@1029 111 /**
lagergren@1029 112 * Cache for internal types - this is a query that requires complex stringbuilding inside
lagergren@1029 113 * ASM and it saves startup time to cache the type mappings
lagergren@1029 114 */
lagergren@1029 115 private static final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> INTERNAL_TYPE_CACHE =
lagergren@1029 116 Collections.synchronizedMap(new WeakHashMap<Class<?>, jdk.internal.org.objectweb.asm.Type>());
lagergren@1029 117
lagergren@1029 118 /** Internal ASM type for this Type - computed once at construction */
attila@1063 119 private transient final jdk.internal.org.objectweb.asm.Type internalType;
lagergren@1029 120
jlaskey@3 121 /** Weights are used to decide which types are "wider" than other types */
jlaskey@3 122 protected static final int MIN_WEIGHT = -1;
jlaskey@3 123
jlaskey@3 124 /** Set way below Integer.MAX_VALUE to prevent overflow when adding weights. Objects are still heaviest. */
jlaskey@3 125 protected static final int MAX_WEIGHT = 20;
jlaskey@3 126
attila@963 127 static final Call BOOTSTRAP = staticCallNoLookup(Bootstrap.class, "mathBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class);
attila@963 128
attila@963 129 static final Handle MATHBOOTSTRAP = new Handle(H_INVOKESTATIC, BOOTSTRAP.className(), "mathBootstrap", BOOTSTRAP.descriptor());
attila@963 130
jlaskey@3 131 /**
jlaskey@3 132 * Constructor
jlaskey@3 133 *
jlaskey@3 134 * @param clazz class for type
jlaskey@3 135 * @param weight weight - higher is more generic
jlaskey@3 136 * @param slots how many bytecode slots the type takes up
jlaskey@3 137 */
jlaskey@3 138 Type(final String name, final Class<?> clazz, final int weight, final int slots) {
lagergren@1029 139 this.name = name;
lagergren@1029 140 this.clazz = clazz;
lagergren@1029 141 this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz);
lagergren@1029 142 this.weight = weight;
jlaskey@3 143 assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight;
lagergren@1029 144 this.slots = slots;
lagergren@1029 145 this.internalType = getInternalType(clazz);
jlaskey@3 146 }
jlaskey@3 147
jlaskey@3 148 /**
jlaskey@3 149 * Get the weight of this type - use this e.g. for sorting method descriptors
jlaskey@3 150 * @return the weight
jlaskey@3 151 */
jlaskey@3 152 public int getWeight() {
jlaskey@3 153 return weight;
jlaskey@3 154 }
jlaskey@3 155
jlaskey@3 156 /**
jlaskey@3 157 * Get the Class representing this type
jlaskey@3 158 * @return the class for this type
jlaskey@3 159 */
jlaskey@3 160 public Class<?> getTypeClass() {
jlaskey@3 161 return clazz;
jlaskey@3 162 }
jlaskey@3 163
jlaskey@3 164 /**
jlaskey@3 165 * For specialization, return the next, slightly more difficulty, type
jlaskey@3 166 * to test.
jlaskey@3 167 *
jlaskey@3 168 * @return the next Type
jlaskey@3 169 */
jlaskey@3 170 public Type nextWider() {
jlaskey@3 171 return null;
jlaskey@3 172 }
jlaskey@3 173
jlaskey@3 174 /**
jlaskey@3 175 * Get the boxed type for this class
jlaskey@3 176 * @return the boxed version of this type or null if N/A
jlaskey@3 177 */
jlaskey@3 178 public Class<?> getBoxedType() {
jlaskey@3 179 assert !getTypeClass().isPrimitive();
jlaskey@3 180 return null;
jlaskey@3 181 }
jlaskey@3 182
jlaskey@3 183 /**
attila@963 184 * Returns the character describing the bytecode type for this value on the stack or local variable, identical to
attila@963 185 * what would be used as the prefix for a bytecode {@code LOAD} or {@code STORE} instruction, therefore it must be
attila@963 186 * one of {@code A, F, D, I, L}. Also, the special value {@code U} is used for local variable slots that haven't
attila@963 187 * been initialized yet (it can't appear for a value pushed to the operand stack, those always have known values).
attila@963 188 * Note that while we allow all JVM internal types, Nashorn doesn't necessarily use them all - currently we don't
attila@963 189 * have floats, only doubles, but that might change in the future.
attila@963 190 * @return the character describing the bytecode type for this value on the stack.
attila@963 191 */
attila@963 192 public abstract char getBytecodeStackType();
attila@963 193
attila@963 194 /**
jlaskey@3 195 * Generate a method descriptor given a return type and a param array
jlaskey@3 196 *
jlaskey@3 197 * @param returnType return type
jlaskey@3 198 * @param types parameters
jlaskey@3 199 *
jlaskey@3 200 * @return a descriptor string
jlaskey@3 201 */
jlaskey@3 202 public static String getMethodDescriptor(final Type returnType, final Type... types) {
jlaskey@3 203 final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length];
jlaskey@3 204 for (int i = 0; i < types.length; i++) {
jlaskey@3 205 itypes[i] = types[i].getInternalType();
jlaskey@3 206 }
jlaskey@3 207 return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(returnType.getInternalType(), itypes);
jlaskey@3 208 }
jlaskey@3 209
jlaskey@3 210 /**
jlaskey@3 211 * Generate a method descriptor given a return type and a param array
jlaskey@3 212 *
jlaskey@3 213 * @param returnType return type
jlaskey@3 214 * @param types parameters
jlaskey@3 215 *
jlaskey@3 216 * @return a descriptor string
jlaskey@3 217 */
jlaskey@3 218 public static String getMethodDescriptor(final Class<?> returnType, final Class<?>... types) {
jlaskey@3 219 final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length];
jlaskey@3 220 for (int i = 0; i < types.length; i++) {
jlaskey@3 221 itypes[i] = getInternalType(types[i]);
jlaskey@3 222 }
jlaskey@3 223 return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(getInternalType(returnType), itypes);
jlaskey@3 224 }
jlaskey@3 225
jlaskey@3 226 /**
attila@963 227 * Return a character representing {@code type} in a method signature.
attila@963 228 *
attila@963 229 * @param type parameter type
attila@963 230 * @return descriptor character
attila@963 231 */
attila@963 232 public static char getShortSignatureDescriptor(final Type type) {
attila@963 233 // Use 'Z' for boolean parameters as we need to distinguish from int
attila@963 234 if (type instanceof BooleanType) {
attila@963 235 return 'Z';
attila@963 236 }
attila@963 237 return type.getBytecodeStackType();
attila@963 238 }
attila@963 239
attila@963 240 /**
jlaskey@3 241 * Return the type for an internal type, package private - do not use
jlaskey@3 242 * outside code gen
jlaskey@3 243 *
jlaskey@3 244 * @param itype internal type
jlaskey@3 245 * @return Nashorn type
jlaskey@3 246 */
jlaskey@3 247 @SuppressWarnings("fallthrough")
jlaskey@3 248 static Type typeFor(final jdk.internal.org.objectweb.asm.Type itype) {
jlaskey@3 249 switch (itype.getSort()) {
jlaskey@3 250 case jdk.internal.org.objectweb.asm.Type.BOOLEAN:
jlaskey@3 251 return BOOLEAN;
jlaskey@3 252 case jdk.internal.org.objectweb.asm.Type.INT:
jlaskey@3 253 return INT;
jlaskey@3 254 case jdk.internal.org.objectweb.asm.Type.LONG:
jlaskey@3 255 return LONG;
jlaskey@3 256 case jdk.internal.org.objectweb.asm.Type.DOUBLE:
jlaskey@3 257 return NUMBER;
jlaskey@3 258 case jdk.internal.org.objectweb.asm.Type.OBJECT:
attila@963 259 try {
attila@963 260 return Type.typeFor(Class.forName(itype.getClassName()));
attila@963 261 } catch(final ClassNotFoundException e) {
attila@963 262 throw new AssertionError(e);
attila@963 263 }
jlaskey@3 264 case jdk.internal.org.objectweb.asm.Type.VOID:
jlaskey@3 265 return null;
jlaskey@3 266 case jdk.internal.org.objectweb.asm.Type.ARRAY:
jlaskey@3 267 switch (itype.getElementType().getSort()) {
jlaskey@3 268 case jdk.internal.org.objectweb.asm.Type.DOUBLE:
jlaskey@3 269 return NUMBER_ARRAY;
jlaskey@3 270 case jdk.internal.org.objectweb.asm.Type.INT:
jlaskey@3 271 return INT_ARRAY;
jlaskey@3 272 case jdk.internal.org.objectweb.asm.Type.LONG:
jlaskey@3 273 return LONG_ARRAY;
jlaskey@3 274 default:
jlaskey@3 275 assert false;
jlaskey@3 276 case jdk.internal.org.objectweb.asm.Type.OBJECT:
jlaskey@3 277 return OBJECT_ARRAY;
jlaskey@3 278 }
jlaskey@3 279
jlaskey@3 280 default:
jlaskey@3 281 assert false : "Unknown itype : " + itype + " sort " + itype.getSort();
jlaskey@3 282 break;
jlaskey@3 283 }
jlaskey@3 284 return null;
jlaskey@3 285 }
jlaskey@3 286
jlaskey@3 287 /**
jlaskey@3 288 * Get the return type for a method
jlaskey@3 289 *
jlaskey@3 290 * @param methodDescriptor method descriptor
jlaskey@3 291 * @return return type
jlaskey@3 292 */
jlaskey@3 293 public static Type getMethodReturnType(final String methodDescriptor) {
jlaskey@3 294 return Type.typeFor(jdk.internal.org.objectweb.asm.Type.getReturnType(methodDescriptor));
jlaskey@3 295 }
jlaskey@3 296
jlaskey@3 297 /**
jlaskey@3 298 * Get type array representing arguments of a method in order
jlaskey@3 299 *
jlaskey@3 300 * @param methodDescriptor method descriptor
jlaskey@3 301 * @return parameter type array
jlaskey@3 302 */
jlaskey@3 303 public static Type[] getMethodArguments(final String methodDescriptor) {
jlaskey@3 304 final jdk.internal.org.objectweb.asm.Type itypes[] = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodDescriptor);
jlaskey@3 305 final Type types[] = new Type[itypes.length];
jlaskey@3 306 for (int i = 0; i < itypes.length; i++) {
jlaskey@3 307 types[i] = Type.typeFor(itypes[i]);
jlaskey@3 308 }
jlaskey@3 309 return types;
jlaskey@3 310 }
jlaskey@3 311
attila@963 312 /**
attila@963 313 * Write a map of {@code int} to {@code Type} to an output stream. This is used to store deoptimization state.
attila@963 314 *
attila@963 315 * @param typeMap the type map
attila@963 316 * @param output data output
lagergren@1028 317 * @throws IOException if write cannot be completed
attila@963 318 */
attila@963 319 public static void writeTypeMap(final Map<Integer, Type> typeMap, final DataOutput output) throws IOException {
attila@963 320 if (typeMap == null) {
attila@963 321 output.writeInt(0);
attila@963 322 } else {
attila@963 323 output.writeInt(typeMap.size());
attila@963 324 for(final Map.Entry<Integer, Type> e: typeMap.entrySet()) {
attila@963 325 output.writeInt(e.getKey());
attila@963 326 final byte typeChar;
attila@963 327 final Type type = e.getValue();
attila@963 328 if(type == Type.OBJECT) {
attila@963 329 typeChar = 'L';
attila@963 330 } else if (type == Type.NUMBER) {
attila@963 331 typeChar = 'D';
attila@963 332 } else if (type == Type.LONG) {
attila@963 333 typeChar = 'J';
attila@963 334 } else {
attila@963 335 throw new AssertionError();
attila@963 336 }
attila@963 337 output.writeByte(typeChar);
attila@963 338 }
attila@963 339 }
attila@963 340 }
attila@963 341
attila@963 342 /**
attila@963 343 * Read a map of {@code int} to {@code Type} from an input stream. This is used to store deoptimization state.
attila@963 344 *
attila@963 345 * @param input data input
attila@963 346 * @return type map
lagergren@1028 347 * @throws IOException if read cannot be completed
attila@963 348 */
attila@963 349 public static Map<Integer, Type> readTypeMap(final DataInput input) throws IOException {
attila@963 350 final int size = input.readInt();
attila@990 351 if (size <= 0) {
attila@963 352 return null;
attila@963 353 }
attila@963 354 final Map<Integer, Type> map = new TreeMap<>();
attila@963 355 for(int i = 0; i < size; ++i) {
attila@963 356 final int pp = input.readInt();
attila@963 357 final int typeChar = input.readByte();
attila@963 358 final Type type;
lagergren@1082 359 switch (typeChar) {
attila@963 360 case 'L': type = Type.OBJECT; break;
attila@963 361 case 'D': type = Type.NUMBER; break;
attila@963 362 case 'J': type = Type.LONG; break;
attila@990 363 default: continue;
attila@963 364 }
attila@963 365 map.put(pp, type);
attila@963 366 }
attila@963 367 return map;
attila@963 368 }
attila@963 369
jlaskey@3 370 static jdk.internal.org.objectweb.asm.Type getInternalType(final String className) {
jlaskey@3 371 return jdk.internal.org.objectweb.asm.Type.getType(className);
jlaskey@3 372 }
jlaskey@3 373
jlaskey@3 374 private jdk.internal.org.objectweb.asm.Type getInternalType() {
lagergren@1029 375 return internalType;
lagergren@1029 376 }
lagergren@1029 377
lagergren@1029 378 private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class<?> type) {
lagergren@1082 379 final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> c = INTERNAL_TYPE_CACHE;
lagergren@1082 380 jdk.internal.org.objectweb.asm.Type itype = c.get(type);
lagergren@1029 381 if (itype != null) {
lagergren@1029 382 return itype;
lagergren@1029 383 }
lagergren@1029 384 itype = jdk.internal.org.objectweb.asm.Type.getType(type);
lagergren@1082 385 c.put(type, itype);
lagergren@1029 386 return itype;
jlaskey@3 387 }
jlaskey@3 388
jlaskey@3 389 private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) {
lagergren@1029 390 return lookupInternalType(type);
jlaskey@3 391 }
jlaskey@3 392
attila@963 393 static void invokestatic(final MethodVisitor method, final Call call) {
sundar@747 394 method.visitMethodInsn(INVOKESTATIC, call.className(), call.name(), call.descriptor(), false);
jlaskey@3 395 }
jlaskey@3 396
jlaskey@3 397 /**
jlaskey@3 398 * Get the internal JVM name of a type
jlaskey@3 399 * @return the internal name
jlaskey@3 400 */
jlaskey@3 401 public String getInternalName() {
jlaskey@3 402 return jdk.internal.org.objectweb.asm.Type.getInternalName(getTypeClass());
jlaskey@3 403 }
jlaskey@3 404
jlaskey@3 405 /**
jlaskey@3 406 * Get the internal JVM name of type type represented by a given Java class
jlaskey@3 407 * @param clazz the class
jlaskey@3 408 * @return the internal name
jlaskey@3 409 */
jlaskey@3 410 public static String getInternalName(final Class<?> clazz) {
jlaskey@3 411 return jdk.internal.org.objectweb.asm.Type.getInternalName(clazz);
jlaskey@3 412 }
jlaskey@3 413
jlaskey@3 414 /**
jlaskey@3 415 * Determines whether a type is the UNKNOWN type, i.e. not set yet
jlaskey@3 416 * Used for type inference.
jlaskey@3 417 *
jlaskey@3 418 * @return true if UNKNOWN, false otherwise
jlaskey@3 419 */
jlaskey@3 420 public boolean isUnknown() {
jlaskey@3 421 return this.equals(Type.UNKNOWN);
jlaskey@3 422 }
jlaskey@3 423
jlaskey@3 424 /**
hannesw@652 425 * Determines whether this type represents an primitive type according to the ECMAScript specification,
hannesw@652 426 * which includes Boolean, Number, and String.
hannesw@652 427 *
hannesw@652 428 * @return true if a JavaScript primitive type, false otherwise.
hannesw@652 429 */
hannesw@652 430 public boolean isJSPrimitive() {
hannesw@652 431 return !isObject() || isString();
hannesw@652 432 }
hannesw@652 433
hannesw@652 434 /**
jlaskey@3 435 * Determines whether a type is the BOOLEAN type
jlaskey@3 436 * @return true if BOOLEAN, false otherwise
jlaskey@3 437 */
jlaskey@3 438 public boolean isBoolean() {
jlaskey@3 439 return this.equals(Type.BOOLEAN);
jlaskey@3 440 }
jlaskey@3 441
jlaskey@3 442 /**
jlaskey@3 443 * Determines whether a type is the INT type
jlaskey@3 444 * @return true if INTEGER, false otherwise
jlaskey@3 445 */
jlaskey@3 446 public boolean isInteger() {
jlaskey@3 447 return this.equals(Type.INT);
jlaskey@3 448 }
jlaskey@3 449
jlaskey@3 450 /**
jlaskey@3 451 * Determines whether a type is the LONG type
jlaskey@3 452 * @return true if LONG, false otherwise
jlaskey@3 453 */
jlaskey@3 454 public boolean isLong() {
jlaskey@3 455 return this.equals(Type.LONG);
jlaskey@3 456 }
jlaskey@3 457
jlaskey@3 458 /**
jlaskey@3 459 * Determines whether a type is the NUMBER type
jlaskey@3 460 * @return true if NUMBER, false otherwise
jlaskey@3 461 */
jlaskey@3 462 public boolean isNumber() {
jlaskey@3 463 return this.equals(Type.NUMBER);
jlaskey@3 464 }
jlaskey@3 465
jlaskey@3 466 /**
jlaskey@3 467 * Determines whether a type is numeric, i.e. NUMBER,
jlaskey@3 468 * INT, LONG.
jlaskey@3 469 *
jlaskey@3 470 * @return true if numeric, false otherwise
jlaskey@3 471 */
jlaskey@3 472 public boolean isNumeric() {
jlaskey@3 473 return this instanceof NumericType;
jlaskey@3 474 }
jlaskey@3 475
jlaskey@3 476 /**
jlaskey@3 477 * Determines whether a type is an array type, i.e.
jlaskey@3 478 * OBJECT_ARRAY or NUMBER_ARRAY (for now)
jlaskey@3 479 *
jlaskey@3 480 * @return true if an array type, false otherwise
jlaskey@3 481 */
jlaskey@3 482 public boolean isArray() {
jlaskey@3 483 return this instanceof ArrayType;
jlaskey@3 484 }
jlaskey@3 485
jlaskey@3 486 /**
jlaskey@3 487 * Determines if a type takes up two bytecode slots or not
jlaskey@3 488 *
jlaskey@3 489 * @return true if type takes up two bytecode slots rather than one
jlaskey@3 490 */
jlaskey@3 491 public boolean isCategory2() {
jlaskey@3 492 return getSlots() == 2;
jlaskey@3 493 }
jlaskey@3 494
jlaskey@3 495 /**
jlaskey@3 496 * Determines whether a type is an OBJECT type, e.g. OBJECT, STRING,
jlaskey@3 497 * NUMBER_ARRAY etc.
jlaskey@3 498 *
jlaskey@3 499 * @return true if object type, false otherwise
jlaskey@3 500 */
jlaskey@3 501 public boolean isObject() {
jlaskey@3 502 return this instanceof ObjectType;
jlaskey@3 503 }
jlaskey@3 504
jlaskey@3 505 /**
attila@963 506 * Is this a primitive type (e.g int, long, double, boolean)
attila@963 507 * @return true if primitive
attila@963 508 */
attila@963 509 public boolean isPrimitive() {
attila@963 510 return !isObject();
attila@963 511 }
attila@963 512
attila@963 513 /**
jlaskey@3 514 * Determines whether a type is a STRING type
jlaskey@3 515 *
jlaskey@3 516 * @return true if object type, false otherwise
jlaskey@3 517 */
jlaskey@3 518 public boolean isString() {
jlaskey@3 519 return this.equals(Type.STRING);
jlaskey@3 520 }
jlaskey@3 521
jlaskey@3 522 /**
attila@963 523 * Determines whether a type is a CHARSEQUENCE type used internally strings
attila@963 524 *
attila@963 525 * @return true if CharSequence (internal string) type, false otherwise
attila@963 526 */
attila@963 527 public boolean isCharSequence() {
attila@963 528 return this.equals(Type.CHARSEQUENCE);
attila@963 529 }
attila@963 530
attila@963 531 /**
jlaskey@3 532 * Determine if two types are equivalent, i.e. need no conversion
jlaskey@3 533 *
jlaskey@3 534 * @param type the second type to check
jlaskey@3 535 *
jlaskey@3 536 * @return true if types are equivalent, false otherwise
jlaskey@3 537 */
jlaskey@3 538 public boolean isEquivalentTo(final Type type) {
attila@963 539 return this.weight() == type.weight() || isObject() && type.isObject();
jlaskey@3 540 }
jlaskey@3 541
jlaskey@3 542 /**
jlaskey@3 543 * Determine if a type can be assigned to from another
jlaskey@3 544 *
jlaskey@3 545 * @param type0 the first type to check
jlaskey@3 546 * @param type1 the second type to check
jlaskey@3 547 *
jlaskey@3 548 * @return true if type1 can be written to type2, false otherwise
jlaskey@3 549 */
jlaskey@3 550 public static boolean isAssignableFrom(final Type type0, final Type type1) {
jlaskey@3 551 if (type0.isObject() && type1.isObject()) {
jlaskey@3 552 return type0.weight() >= type1.weight();
jlaskey@3 553 }
jlaskey@3 554
jlaskey@3 555 return type0.weight() == type1.weight();
jlaskey@3 556 }
jlaskey@3 557
jlaskey@3 558 /**
jlaskey@3 559 * Determine if this type is assignable from another type
jlaskey@3 560 * @param type the type to check against
jlaskey@3 561 *
jlaskey@3 562 * @return true if "type" can be written to this type, false otherwise
jlaskey@3 563 */
jlaskey@3 564 public boolean isAssignableFrom(final Type type) {
jlaskey@3 565 return Type.isAssignableFrom(this, type);
jlaskey@3 566 }
jlaskey@3 567
jlaskey@3 568 /**
jlaskey@3 569 * Determines is this type is equivalent to another, i.e. needs no conversion
jlaskey@3 570 * to be assigned to it.
jlaskey@3 571 *
jlaskey@3 572 * @param type0 the first type to check
jlaskey@3 573 * @param type1 the second type to check
jlaskey@3 574 *
jlaskey@3 575 * @return true if this type is equivalent to type, false otherwise
jlaskey@3 576 */
jlaskey@3 577 public static boolean areEquivalent(final Type type0, final Type type1) {
jlaskey@3 578 return type0.isEquivalentTo(type1);
jlaskey@3 579 }
jlaskey@3 580
jlaskey@3 581 /**
jlaskey@3 582 * Determine the number of bytecode slots a type takes up
jlaskey@3 583 *
jlaskey@3 584 * @return the number of slots for this type, 1 or 2.
jlaskey@3 585 */
jlaskey@3 586 public int getSlots() {
jlaskey@3 587 return slots;
jlaskey@3 588 }
lagergren@1071 589
jlaskey@3 590 /**
jlaskey@3 591 * Returns the widest or most common of two types
jlaskey@3 592 *
jlaskey@3 593 * @param type0 type one
jlaskey@3 594 * @param type1 type two
jlaskey@3 595 *
jlaskey@3 596 * @return the widest type
jlaskey@3 597 */
jlaskey@3 598 public static Type widest(final Type type0, final Type type1) {
jlaskey@3 599 if (type0.isArray() && type1.isArray()) {
jlaskey@3 600 return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT;
jlaskey@3 601 } else if (type0.isArray() != type1.isArray()) {
lagergren@605 602 //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense
lagergren@605 603 return Type.OBJECT;
hannesw@652 604 } else if (type0.isObject() && type1.isObject() && type0.getTypeClass() != type1.getTypeClass()) {
lagergren@605 605 // Object<type=String> and Object<type=ScriptFunction> will produce Object
lagergren@605 606 // TODO: maybe find most specific common superclass?
lagergren@605 607 return Type.OBJECT;
jlaskey@3 608 }
jlaskey@3 609 return type0.weight() > type1.weight() ? type0 : type1;
jlaskey@3 610 }
jlaskey@3 611
jlaskey@3 612 /**
lagergren@1071 613 * Returns the widest or most common of two types, given as classes
lagergren@1071 614 *
lagergren@1071 615 * @param type0 type one
lagergren@1071 616 * @param type1 type two
lagergren@1071 617 *
lagergren@1071 618 * @return the widest type
lagergren@1071 619 */
lagergren@1071 620 public static Class<?> widest(final Class<?> type0, final Class<?> type1) {
lagergren@1071 621 return widest(Type.typeFor(type0), Type.typeFor(type1)).getTypeClass();
lagergren@1071 622 }
lagergren@1071 623
lagergren@1071 624 /**
attila@963 625 * When doing widening for return types of a function or a ternary operator, it is not valid to widen a boolean to
attila@963 626 * anything other than object. Note that this wouldn't be necessary if {@code Type.widest} did not allow
attila@963 627 * boolean-to-number widening. Eventually, we should address it there, but it affects too many other parts of the
attila@963 628 * system and is sometimes legitimate (e.g. whenever a boolean value would undergo ToNumber conversion anyway).
attila@963 629 * @param t1 type 1
attila@963 630 * @param t2 type 2
attila@963 631 * @return wider of t1 and t2, except if one is boolean and the other is neither boolean nor unknown, in which case
attila@963 632 * {@code Type.OBJECT} is returned.
attila@963 633 */
attila@963 634 public static Type widestReturnType(final Type t1, final Type t2) {
attila@963 635 if (t1.isUnknown()) {
attila@963 636 return t2;
attila@963 637 } else if (t2.isUnknown()) {
attila@963 638 return t1;
attila@963 639 } else if(t1.isBoolean() != t2.isBoolean() || t1.isNumeric() != t2.isNumeric()) {
attila@963 640 return Type.OBJECT;
attila@963 641 }
attila@963 642 return Type.widest(t1, t2);
attila@963 643 }
attila@963 644
attila@963 645 /**
attila@963 646 * Returns a generic version of the type. Basically, if the type {@link #isObject()}, returns {@link #OBJECT},
attila@963 647 * otherwise returns the type unchanged.
attila@963 648 * @param type the type to generify
attila@963 649 * @return the generified type
attila@963 650 */
attila@963 651 public static Type generic(final Type type) {
attila@963 652 return type.isObject() ? Type.OBJECT : type;
attila@963 653 }
attila@963 654
attila@963 655 /**
jlaskey@3 656 * Returns the narrowest or least common of two types
jlaskey@3 657 *
jlaskey@3 658 * @param type0 type one
jlaskey@3 659 * @param type1 type two
jlaskey@3 660 *
jlaskey@3 661 * @return the widest type
jlaskey@3 662 */
jlaskey@3 663 public static Type narrowest(final Type type0, final Type type1) {
attila@963 664 return type0.narrowerThan(type1) ? type0 : type1;
attila@963 665 }
attila@963 666
attila@963 667 /**
attila@963 668 * Check whether this type is strictly narrower than another one
attila@963 669 * @param type type to check against
attila@963 670 * @return true if this type is strictly narrower
attila@963 671 */
attila@963 672 public boolean narrowerThan(final Type type) {
attila@963 673 return weight() < type.weight();
attila@963 674 }
attila@963 675
attila@963 676 /**
attila@963 677 * Check whether this type is strictly wider than another one
attila@963 678 * @param type type to check against
attila@963 679 * @return true if this type is strictly wider
attila@963 680 */
attila@963 681 public boolean widerThan(final Type type) {
attila@963 682 return weight() > type.weight();
jlaskey@3 683 }
jlaskey@3 684
jlaskey@3 685 /**
jlaskey@3 686 * Returns the widest or most common of two types, but no wider than "limit"
jlaskey@3 687 *
jlaskey@3 688 * @param type0 type one
jlaskey@3 689 * @param type1 type two
jlaskey@3 690 * @param limit limiting type
jlaskey@3 691 *
jlaskey@3 692 * @return the widest type, but no wider than limit
jlaskey@3 693 */
jlaskey@3 694 public static Type widest(final Type type0, final Type type1, final Type limit) {
jlaskey@3 695 final Type type = Type.widest(type0, type1);
jlaskey@3 696 if (type.weight() > limit.weight()) {
jlaskey@3 697 return limit;
jlaskey@3 698 }
jlaskey@3 699 return type;
jlaskey@3 700 }
jlaskey@3 701
jlaskey@3 702 /**
jlaskey@3 703 * Returns the widest or most common of two types, but no narrower than "limit"
jlaskey@3 704 *
jlaskey@3 705 * @param type0 type one
jlaskey@3 706 * @param type1 type two
jlaskey@3 707 * @param limit limiting type
jlaskey@3 708 *
jlaskey@3 709 * @return the widest type, but no wider than limit
jlaskey@3 710 */
jlaskey@3 711 public static Type narrowest(final Type type0, final Type type1, final Type limit) {
jlaskey@3 712 final Type type = type0.weight() < type1.weight() ? type0 : type1;
jlaskey@3 713 if (type.weight() < limit.weight()) {
jlaskey@3 714 return limit;
jlaskey@3 715 }
jlaskey@3 716 return type;
jlaskey@3 717 }
jlaskey@3 718
jlaskey@3 719 /**
jlaskey@3 720 * Returns the narrowest of this type and another
jlaskey@3 721 *
jlaskey@3 722 * @param other type to compare against
jlaskey@3 723 *
jlaskey@3 724 * @return the widest type
jlaskey@3 725 */
jlaskey@3 726 public Type narrowest(final Type other) {
jlaskey@3 727 return Type.narrowest(this, other);
jlaskey@3 728 }
jlaskey@3 729
jlaskey@3 730 /**
jlaskey@3 731 * Returns the widest of this type and another
jlaskey@3 732 *
jlaskey@3 733 * @param other type to compare against
jlaskey@3 734 *
jlaskey@3 735 * @return the widest type
jlaskey@3 736 */
jlaskey@3 737 public Type widest(final Type other) {
jlaskey@3 738 return Type.widest(this, other);
jlaskey@3 739 }
jlaskey@3 740
jlaskey@3 741 /**
jlaskey@3 742 * Returns the weight of a type, used for type comparison
jlaskey@3 743 * between wider and narrower types
jlaskey@3 744 *
jlaskey@3 745 * @return the weight
jlaskey@3 746 */
jlaskey@3 747 int weight() {
jlaskey@3 748 return weight;
jlaskey@3 749 }
jlaskey@3 750
jlaskey@3 751 /**
jlaskey@3 752 * Return the descriptor of a type, used for e.g. signature
jlaskey@3 753 * generation
jlaskey@3 754 *
jlaskey@3 755 * @return the descriptor
jlaskey@3 756 */
jlaskey@3 757 public String getDescriptor() {
jlaskey@3 758 return descriptor;
jlaskey@3 759 }
jlaskey@3 760
attila@963 761 /**
attila@963 762 * Return the descriptor of a type, short version
attila@963 763 * Used mainly for debugging purposes
attila@963 764 *
attila@963 765 * @return the short descriptor
attila@963 766 */
attila@963 767 public String getShortDescriptor() {
attila@963 768 return descriptor;
attila@963 769 }
attila@963 770
jlaskey@3 771 @Override
jlaskey@3 772 public String toString() {
jlaskey@3 773 return name;
jlaskey@3 774 }
jlaskey@3 775
jlaskey@3 776 /**
jlaskey@3 777 * Return the (possibly cached) Type object for this class
jlaskey@3 778 *
jlaskey@3 779 * @param clazz the class to check
jlaskey@3 780 *
jlaskey@3 781 * @return the Type representing this class
jlaskey@3 782 */
jlaskey@3 783 public static Type typeFor(final Class<?> clazz) {
attila@422 784 final Type type = cache.get(clazz);
attila@422 785 if(type != null) {
attila@422 786 return type;
jlaskey@3 787 }
attila@422 788 assert !clazz.isPrimitive() || clazz == void.class;
attila@422 789 final Type newType;
attila@422 790 if (clazz.isArray()) {
attila@422 791 newType = new ArrayType(clazz);
attila@422 792 } else {
attila@422 793 newType = new ObjectType(clazz);
attila@422 794 }
attila@422 795 final Type existingType = cache.putIfAbsent(clazz, newType);
attila@422 796 return existingType == null ? newType : existingType;
jlaskey@3 797 }
jlaskey@3 798
jlaskey@3 799 @Override
jlaskey@3 800 public int compareTo(final Type o) {
jlaskey@3 801 return o.weight() - weight();
jlaskey@3 802 }
jlaskey@3 803
jlaskey@3 804 /**
jlaskey@3 805 * Common logic for implementing dup for all types
jlaskey@3 806 *
jlaskey@3 807 * @param method method visitor
jlaskey@3 808 * @param depth dup depth
jlaskey@3 809 *
jlaskey@3 810 * @return the type at the top of the stack afterwards
jlaskey@3 811 */
jlaskey@3 812 @Override
jlaskey@3 813 public Type dup(final MethodVisitor method, final int depth) {
jlaskey@3 814 return Type.dup(method, this, depth);
jlaskey@3 815 }
jlaskey@3 816
jlaskey@3 817 /**
jlaskey@3 818 * Common logic for implementing swap for all types
jlaskey@3 819 *
jlaskey@3 820 * @param method method visitor
jlaskey@3 821 * @param other the type to swap with
jlaskey@3 822 *
jlaskey@3 823 * @return the type at the top of the stack afterwards, i.e. other
jlaskey@3 824 */
jlaskey@3 825 @Override
jlaskey@3 826 public Type swap(final MethodVisitor method, final Type other) {
jlaskey@3 827 Type.swap(method, this, other);
jlaskey@3 828 return other;
jlaskey@3 829 }
jlaskey@3 830
jlaskey@3 831 /**
jlaskey@3 832 * Common logic for implementing pop for all types
jlaskey@3 833 *
jlaskey@3 834 * @param method method visitor
jlaskey@3 835 *
jlaskey@3 836 * @return the type that was popped
jlaskey@3 837 */
jlaskey@3 838 @Override
jlaskey@3 839 public Type pop(final MethodVisitor method) {
jlaskey@3 840 Type.pop(method, this);
jlaskey@3 841 return this;
jlaskey@3 842 }
jlaskey@3 843
lagergren@237 844 @Override
lagergren@237 845 public Type loadEmpty(final MethodVisitor method) {
lagergren@237 846 assert false : "unsupported operation";
lagergren@237 847 return null;
lagergren@237 848 }
lagergren@237 849
jlaskey@3 850 /**
jlaskey@3 851 * Superclass logic for pop for all types
jlaskey@3 852 *
jlaskey@3 853 * @param method method emitter
jlaskey@3 854 * @param type type to pop
jlaskey@3 855 */
jlaskey@3 856 protected static void pop(final MethodVisitor method, final Type type) {
jlaskey@3 857 method.visitInsn(type.isCategory2() ? POP2 : POP);
jlaskey@3 858 }
jlaskey@3 859
jlaskey@3 860 private static Type dup(final MethodVisitor method, final Type type, final int depth) {
jlaskey@3 861 final boolean cat2 = type.isCategory2();
jlaskey@3 862
jlaskey@3 863 switch (depth) {
jlaskey@3 864 case 0:
jlaskey@3 865 method.visitInsn(cat2 ? DUP2 : DUP);
jlaskey@3 866 break;
jlaskey@3 867 case 1:
jlaskey@3 868 method.visitInsn(cat2 ? DUP2_X1 : DUP_X1);
jlaskey@3 869 break;
jlaskey@3 870 case 2:
jlaskey@3 871 method.visitInsn(cat2 ? DUP2_X2 : DUP_X2);
jlaskey@3 872 break;
jlaskey@3 873 default:
jlaskey@3 874 return null; //invalid depth
jlaskey@3 875 }
jlaskey@3 876
jlaskey@3 877 return type;
jlaskey@3 878 }
jlaskey@3 879
jlaskey@3 880 private static void swap(final MethodVisitor method, final Type above, final Type below) {
jlaskey@3 881 if (below.isCategory2()) {
jlaskey@3 882 if (above.isCategory2()) {
lagergren@137 883 method.visitInsn(DUP2_X2);
lagergren@137 884 method.visitInsn(POP2);
jlaskey@3 885 } else {
lagergren@137 886 method.visitInsn(DUP_X2);
lagergren@137 887 method.visitInsn(POP);
jlaskey@3 888 }
jlaskey@3 889 } else {
jlaskey@3 890 if (above.isCategory2()) {
lagergren@137 891 method.visitInsn(DUP2_X1);
lagergren@137 892 method.visitInsn(POP2);
jlaskey@3 893 } else {
lagergren@137 894 method.visitInsn(SWAP);
jlaskey@3 895 }
jlaskey@3 896 }
jlaskey@3 897 }
jlaskey@3 898
attila@422 899 /** Mappings between java classes and their Type singletons */
attila@422 900 private static final ConcurrentMap<Class<?>, Type> cache = new ConcurrentHashMap<>();
attila@422 901
jlaskey@3 902 /**
jlaskey@3 903 * This is the boolean singleton, used for all boolean types
jlaskey@3 904 */
attila@422 905 public static final Type BOOLEAN = putInCache(new BooleanType());
jlaskey@3 906
jlaskey@3 907 /**
jlaskey@3 908 * This is an integer type, i.e INT, INT32.
jlaskey@3 909 */
attila@963 910 public static final BitwiseType INT = putInCache(new IntType());
jlaskey@3 911
jlaskey@3 912 /**
jlaskey@3 913 * This is the number singleton, used for all number types
jlaskey@3 914 */
attila@963 915 public static final NumericType NUMBER = putInCache(new NumberType());
jlaskey@3 916
jlaskey@3 917 /**
jlaskey@3 918 * This is the long singleton, used for all long types
jlaskey@3 919 */
attila@963 920 public static final BitwiseType LONG = putInCache(new LongType());
jlaskey@3 921
jlaskey@3 922 /**
jlaskey@3 923 * A string singleton
jlaskey@3 924 */
attila@422 925 public static final Type STRING = putInCache(new ObjectType(String.class));
jlaskey@3 926
jlaskey@3 927 /**
attila@963 928 * This is the CharSequence singleton used to represent JS strings internally
attila@963 929 * (either a {@code java.lang.String} or {@code jdk.nashorn.internal.runtime.ConsString}.
attila@963 930 */
attila@963 931 public static final Type CHARSEQUENCE = putInCache(new ObjectType(CharSequence.class));
attila@963 932
attila@963 933
attila@963 934 /**
jlaskey@3 935 * This is the object singleton, used for all object types
jlaskey@3 936 */
attila@422 937 public static final Type OBJECT = putInCache(new ObjectType());
jlaskey@3 938
jlaskey@3 939 /**
attila@963 940 * A undefined singleton
attila@963 941 */
attila@963 942 public static final Type UNDEFINED = putInCache(new ObjectType(Undefined.class));
attila@963 943
attila@963 944 /**
attila@963 945 * This is the singleton for ScriptObjects
attila@963 946 */
attila@963 947 public static final Type SCRIPT_OBJECT = putInCache(new ObjectType(ScriptObject.class));
attila@963 948
attila@963 949 /**
jlaskey@3 950 * This is the singleton for integer arrays
jlaskey@3 951 */
jlaskey@3 952 public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
attila@1063 953 private static final long serialVersionUID = 1L;
attila@1063 954
jlaskey@3 955 @Override
jlaskey@3 956 public void astore(final MethodVisitor method) {
jlaskey@3 957 method.visitInsn(IASTORE);
jlaskey@3 958 }
jlaskey@3 959
jlaskey@3 960 @Override
jlaskey@3 961 public Type aload(final MethodVisitor method) {
jlaskey@3 962 method.visitInsn(IALOAD);
jlaskey@3 963 return INT;
jlaskey@3 964 }
jlaskey@3 965
jlaskey@3 966 @Override
jlaskey@3 967 public Type newarray(final MethodVisitor method) {
jlaskey@3 968 method.visitIntInsn(NEWARRAY, T_INT);
jlaskey@3 969 return this;
jlaskey@3 970 }
jlaskey@3 971
jlaskey@3 972 @Override
jlaskey@3 973 public Type getElementType() {
jlaskey@3 974 return INT;
jlaskey@3 975 }
jlaskey@3 976 };
jlaskey@3 977
jlaskey@3 978 /**
jlaskey@3 979 * This is the singleton for long arrays
jlaskey@3 980 */
jlaskey@3 981 public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
attila@1063 982 private static final long serialVersionUID = 1L;
attila@1063 983
jlaskey@3 984 @Override
jlaskey@3 985 public void astore(final MethodVisitor method) {
jlaskey@3 986 method.visitInsn(LASTORE);
jlaskey@3 987 }
jlaskey@3 988
jlaskey@3 989 @Override
jlaskey@3 990 public Type aload(final MethodVisitor method) {
lagergren@395 991 method.visitInsn(LALOAD);
lagergren@395 992 return LONG;
jlaskey@3 993 }
jlaskey@3 994
jlaskey@3 995 @Override
jlaskey@3 996 public Type newarray(final MethodVisitor method) {
lagergren@395 997 method.visitIntInsn(NEWARRAY, T_LONG);
jlaskey@3 998 return this;
jlaskey@3 999 }
jlaskey@3 1000
jlaskey@3 1001 @Override
jlaskey@3 1002 public Type getElementType() {
lagergren@395 1003 return LONG;
jlaskey@3 1004 }
jlaskey@3 1005 };
jlaskey@3 1006
jlaskey@3 1007 /**
jlaskey@3 1008 * This is the singleton for numeric arrays
jlaskey@3 1009 */
jlaskey@3 1010 public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
attila@1063 1011 private static final long serialVersionUID = 1L;
attila@1063 1012
jlaskey@3 1013 @Override
jlaskey@3 1014 public void astore(final MethodVisitor method) {
jlaskey@3 1015 method.visitInsn(DASTORE);
jlaskey@3 1016 }
jlaskey@3 1017
jlaskey@3 1018 @Override
jlaskey@3 1019 public Type aload(final MethodVisitor method) {
jlaskey@3 1020 method.visitInsn(DALOAD);
jlaskey@3 1021 return NUMBER;
jlaskey@3 1022 }
jlaskey@3 1023
jlaskey@3 1024 @Override
jlaskey@3 1025 public Type newarray(final MethodVisitor method) {
jlaskey@3 1026 method.visitIntInsn(NEWARRAY, T_DOUBLE);
jlaskey@3 1027 return this;
jlaskey@3 1028 }
jlaskey@3 1029
jlaskey@3 1030 @Override
jlaskey@3 1031 public Type getElementType() {
jlaskey@3 1032 return NUMBER;
jlaskey@3 1033 }
jlaskey@3 1034 };
jlaskey@3 1035
jlaskey@3 1036 /** Singleton for method handle arrays used for properties etc. */
attila@422 1037 public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class));
jlaskey@3 1038
jlaskey@3 1039 /** This is the singleton for string arrays */
attila@422 1040 public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class));
jlaskey@3 1041
jlaskey@3 1042 /** This is the singleton for object arrays */
attila@422 1043 public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class));
jlaskey@3 1044
jlaskey@3 1045 /** This type, always an object type, just a toString override */
jlaskey@3 1046 public static final Type THIS = new ObjectType() {
attila@1063 1047 private static final long serialVersionUID = 1L;
attila@1063 1048
jlaskey@3 1049 @Override
jlaskey@3 1050 public String toString() {
jlaskey@3 1051 return "this";
jlaskey@3 1052 }
jlaskey@3 1053 };
jlaskey@3 1054
jlaskey@3 1055 /** Scope type, always an object type, just a toString override */
jlaskey@3 1056 public static final Type SCOPE = new ObjectType() {
attila@1063 1057 private static final long serialVersionUID = 1L;
attila@1063 1058
jlaskey@3 1059 @Override
jlaskey@3 1060 public String toString() {
jlaskey@3 1061 return "scope";
jlaskey@3 1062 }
jlaskey@3 1063 };
jlaskey@3 1064
jlaskey@3 1065 private static interface Unknown {
jlaskey@3 1066 // EMPTY - used as a class that is absolutely not compatible with a type to represent "unknown"
jlaskey@3 1067 }
jlaskey@3 1068
attila@963 1069 private abstract static class ValueLessType extends Type {
attila@1063 1070 private static final long serialVersionUID = 1L;
attila@963 1071
attila@963 1072 ValueLessType(final String name) {
attila@963 1073 super(name, Unknown.class, MIN_WEIGHT, 1);
attila@963 1074 }
attila@963 1075
attila@963 1076 @Override
attila@963 1077 public Type load(final MethodVisitor method, final int slot) {
attila@963 1078 throw new UnsupportedOperationException("load " + slot);
attila@963 1079 }
attila@963 1080
attila@963 1081 @Override
attila@963 1082 public void store(final MethodVisitor method, final int slot) {
attila@963 1083 throw new UnsupportedOperationException("store " + slot);
attila@963 1084 }
attila@963 1085
attila@963 1086 @Override
attila@963 1087 public Type ldc(final MethodVisitor method, final Object c) {
attila@963 1088 throw new UnsupportedOperationException("ldc " + c);
attila@963 1089 }
attila@963 1090
attila@963 1091 @Override
attila@963 1092 public Type loadUndefined(final MethodVisitor method) {
attila@963 1093 throw new UnsupportedOperationException("load undefined");
attila@963 1094 }
attila@963 1095
attila@963 1096 @Override
attila@963 1097 public Type loadForcedInitializer(final MethodVisitor method) {
attila@963 1098 throw new UnsupportedOperationException("load forced initializer");
attila@963 1099 }
attila@963 1100
attila@963 1101 @Override
attila@963 1102 public Type convert(final MethodVisitor method, final Type to) {
attila@963 1103 throw new UnsupportedOperationException("convert => " + to);
attila@963 1104 }
attila@963 1105
attila@963 1106 @Override
attila@963 1107 public void _return(final MethodVisitor method) {
attila@963 1108 throw new UnsupportedOperationException("return");
attila@963 1109 }
attila@963 1110
attila@963 1111 @Override
attila@963 1112 public Type add(final MethodVisitor method, final int programPoint) {
attila@963 1113 throw new UnsupportedOperationException("add");
attila@963 1114 }
attila@963 1115 }
attila@963 1116
jlaskey@3 1117 /**
jlaskey@3 1118 * This is the unknown type which is used as initial type for type
jlaskey@3 1119 * inference. It has the minimum type width
jlaskey@3 1120 */
attila@963 1121 public static final Type UNKNOWN = new ValueLessType("<unknown>") {
attila@1063 1122 private static final long serialVersionUID = 1L;
attila@1063 1123
jlaskey@3 1124 @Override
jlaskey@3 1125 public String getDescriptor() {
jlaskey@3 1126 return "<unknown>";
jlaskey@3 1127 }
jlaskey@3 1128
jlaskey@3 1129 @Override
attila@963 1130 public char getBytecodeStackType() {
attila@963 1131 return 'U';
attila@963 1132 }
attila@963 1133 };
attila@963 1134
attila@963 1135 /**
attila@963 1136 * This is the unknown type which is used as initial type for type
attila@963 1137 * inference. It has the minimum type width
attila@963 1138 */
attila@963 1139 public static final Type SLOT_2 = new ValueLessType("<slot_2>") {
attila@1063 1140 private static final long serialVersionUID = 1L;
attila@963 1141
attila@963 1142 @Override
attila@963 1143 public String getDescriptor() {
attila@963 1144 return "<slot_2>";
jlaskey@3 1145 }
jlaskey@3 1146
jlaskey@3 1147 @Override
attila@963 1148 public char getBytecodeStackType() {
attila@963 1149 throw new UnsupportedOperationException("getBytecodeStackType");
jlaskey@3 1150 }
jlaskey@3 1151 };
jlaskey@3 1152
attila@962 1153 private static <T extends Type> T putInCache(final T type) {
attila@422 1154 cache.put(type.getTypeClass(), type);
attila@422 1155 return type;
jlaskey@3 1156 }
attila@1063 1157
attila@1063 1158 protected final Object readResolve() {
attila@1063 1159 return Type.typeFor(clazz);
attila@1063 1160 }
jlaskey@3 1161 }

mercurial