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

Tue, 12 Mar 2013 15:30:53 +0100

author
lagergren
date
Tue, 12 Mar 2013 15:30:53 +0100
changeset 137
e15806b9d716
parent 62
f7825c1a11d3
child 237
ad28f2b52b12
permissions
-rw-r--r--

8009718: Lazy execution architecture continued - ScriptFunctionData is either final or recompilable. Moved ScriptFunctionData creation logic away from runtime to compile time. Prepared for method generation/specialization. Got rid of ScriptFunctionImplTrampoline whose semantics could be done as part of the relinking anyway. Merge with the lookup package change.
Reviewed-by: attila, jlaskey

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;
jlaskey@3 36 import static jdk.internal.org.objectweb.asm.Opcodes.IALOAD;
jlaskey@3 37 import static jdk.internal.org.objectweb.asm.Opcodes.IASTORE;
jlaskey@3 38 import static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC;
jlaskey@3 39 import static jdk.internal.org.objectweb.asm.Opcodes.LASTORE;
jlaskey@3 40 import static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY;
jlaskey@3 41 import static jdk.internal.org.objectweb.asm.Opcodes.POP;
jlaskey@3 42 import static jdk.internal.org.objectweb.asm.Opcodes.POP2;
jlaskey@3 43 import static jdk.internal.org.objectweb.asm.Opcodes.SWAP;
jlaskey@3 44 import static jdk.internal.org.objectweb.asm.Opcodes.T_DOUBLE;
jlaskey@3 45 import static jdk.internal.org.objectweb.asm.Opcodes.T_INT;
jlaskey@3 46
jlaskey@3 47 import java.lang.invoke.MethodHandle;
jlaskey@3 48 import java.util.Collections;
jlaskey@3 49 import java.util.HashMap;
jlaskey@3 50 import java.util.Map;
jlaskey@3 51 import jdk.internal.org.objectweb.asm.MethodVisitor;
jlaskey@3 52 import jdk.nashorn.internal.codegen.CompilerConstants.Call;
jlaskey@3 53
jlaskey@3 54
jlaskey@3 55 /**
jlaskey@3 56 * This is the representation of a JavaScript type, disassociated from java
jlaskey@3 57 * Classes, with the basis for conversion weight, mapping to ASM types
jlaskey@3 58 * and implementing the ByteCodeOps interface which tells this type
jlaskey@3 59 * how to generate code for various operations.
jlaskey@3 60 *
jlaskey@3 61 * Except for ClassEmitter, this is the only class that has to know
jlaskey@3 62 * about the underlying byte code generation system.
jlaskey@3 63 *
jlaskey@3 64 * The different types know how to generate bytecode for the different
jlaskey@3 65 * operations, inherited from BytecodeOps, that they support. This avoids
jlaskey@3 66 * if/else chains depending on type in several cases and allows for
jlaskey@3 67 * more readable and shorter code
jlaskey@3 68 *
jlaskey@3 69 * The Type class also contains logic used by the type inference and
jlaskey@3 70 * for comparing types against each other, as well as the concepts
jlaskey@3 71 * of narrower to wider types. The widest type is an object. Ideally we
jlaskey@3 72 * would like as narrow types as possible for code to be efficient, e.g
jlaskey@3 73 * INTs rather than OBJECTs
jlaskey@3 74 */
jlaskey@3 75
jlaskey@3 76 public abstract class Type implements Comparable<Type>, BytecodeOps {
jlaskey@3 77
jlaskey@3 78 /** Human readable name for type */
jlaskey@3 79 private final String name;
jlaskey@3 80
jlaskey@3 81 /** Descriptor for type */
jlaskey@3 82 private final String descriptor;
jlaskey@3 83
jlaskey@3 84 /** The "weight" of the type. Used for picking widest/least specific common type */
jlaskey@3 85 private final int weight;
jlaskey@3 86
jlaskey@3 87 /** How many bytecode slots does this type occupy */
jlaskey@3 88 private final int slots;
jlaskey@3 89
jlaskey@3 90 /** The class for this type */
jlaskey@3 91 private final Class<?> clazz;
jlaskey@3 92
jlaskey@3 93 /** Weights are used to decide which types are "wider" than other types */
jlaskey@3 94 protected static final int MIN_WEIGHT = -1;
jlaskey@3 95
jlaskey@3 96 /** Set way below Integer.MAX_VALUE to prevent overflow when adding weights. Objects are still heaviest. */
jlaskey@3 97 protected static final int MAX_WEIGHT = 20;
jlaskey@3 98
jlaskey@3 99 /**
jlaskey@3 100 * Constructor
jlaskey@3 101 *
jlaskey@3 102 * @param clazz class for type
jlaskey@3 103 * @param weight weight - higher is more generic
jlaskey@3 104 * @param slots how many bytecode slots the type takes up
jlaskey@3 105 */
jlaskey@3 106 Type(final String name, final Class<?> clazz, final int weight, final int slots) {
jlaskey@3 107 this.name = name;
jlaskey@3 108 this.clazz = clazz;
jlaskey@3 109 this.descriptor = Type.getDescriptor(clazz);
jlaskey@3 110 this.weight = weight;
jlaskey@3 111 assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight;
jlaskey@3 112 this.slots = slots;
jlaskey@3 113 }
jlaskey@3 114
jlaskey@3 115 /**
jlaskey@3 116 * Return an internal descriptor for a type
jlaskey@3 117 *
jlaskey@3 118 * @param type the type
jlaskey@3 119 * @return descriptor string
jlaskey@3 120 */
jlaskey@3 121 public static String getDescriptor(final Class<?> type) {
jlaskey@3 122 return jdk.internal.org.objectweb.asm.Type.getDescriptor(type);
jlaskey@3 123 }
jlaskey@3 124
jlaskey@3 125 /**
jlaskey@3 126 * Get the weight of this type - use this e.g. for sorting method descriptors
jlaskey@3 127 * @return the weight
jlaskey@3 128 */
jlaskey@3 129 public int getWeight() {
jlaskey@3 130 return weight;
jlaskey@3 131 }
jlaskey@3 132
jlaskey@3 133 /**
jlaskey@3 134 * Get the Class representing this type
jlaskey@3 135 * @return the class for this type
jlaskey@3 136 */
jlaskey@3 137 public Class<?> getTypeClass() {
jlaskey@3 138 return clazz;
jlaskey@3 139 }
jlaskey@3 140
jlaskey@3 141 /**
jlaskey@3 142 * For specialization, return the next, slightly more difficulty, type
jlaskey@3 143 * to test.
jlaskey@3 144 *
jlaskey@3 145 * @return the next Type
jlaskey@3 146 */
jlaskey@3 147 public Type nextWider() {
jlaskey@3 148 return null;
jlaskey@3 149 }
jlaskey@3 150
jlaskey@3 151 /**
jlaskey@3 152 * Get the boxed type for this class
jlaskey@3 153 * @return the boxed version of this type or null if N/A
jlaskey@3 154 */
jlaskey@3 155 public Class<?> getBoxedType() {
jlaskey@3 156 assert !getTypeClass().isPrimitive();
jlaskey@3 157 return null;
jlaskey@3 158 }
jlaskey@3 159
jlaskey@3 160 /**
jlaskey@3 161 * Generate a method descriptor given a return type and a param array
jlaskey@3 162 *
jlaskey@3 163 * @param returnType return type
jlaskey@3 164 * @param types parameters
jlaskey@3 165 *
jlaskey@3 166 * @return a descriptor string
jlaskey@3 167 */
jlaskey@3 168 public static String getMethodDescriptor(final Type returnType, final Type... types) {
jlaskey@3 169 final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length];
jlaskey@3 170 for (int i = 0; i < types.length; i++) {
jlaskey@3 171 itypes[i] = types[i].getInternalType();
jlaskey@3 172 }
jlaskey@3 173 return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(returnType.getInternalType(), itypes);
jlaskey@3 174 }
jlaskey@3 175
jlaskey@3 176 /**
jlaskey@3 177 * Generate a method descriptor given a return type and a param array
jlaskey@3 178 *
jlaskey@3 179 * @param returnType return type
jlaskey@3 180 * @param types parameters
jlaskey@3 181 *
jlaskey@3 182 * @return a descriptor string
jlaskey@3 183 */
jlaskey@3 184 public static String getMethodDescriptor(final Class<?> returnType, final Class<?>... types) {
jlaskey@3 185 final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length];
jlaskey@3 186 for (int i = 0; i < types.length; i++) {
jlaskey@3 187 itypes[i] = getInternalType(types[i]);
jlaskey@3 188 }
jlaskey@3 189 return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(getInternalType(returnType), itypes);
jlaskey@3 190 }
jlaskey@3 191
jlaskey@3 192 /**
jlaskey@3 193 * Return the type for an internal type, package private - do not use
jlaskey@3 194 * outside code gen
jlaskey@3 195 *
jlaskey@3 196 * @param itype internal type
jlaskey@3 197 * @return Nashorn type
jlaskey@3 198 */
jlaskey@3 199 @SuppressWarnings("fallthrough")
jlaskey@3 200 static Type typeFor(final jdk.internal.org.objectweb.asm.Type itype) {
jlaskey@3 201 switch (itype.getSort()) {
jlaskey@3 202 case jdk.internal.org.objectweb.asm.Type.BOOLEAN:
jlaskey@3 203 return BOOLEAN;
jlaskey@3 204 case jdk.internal.org.objectweb.asm.Type.INT:
jlaskey@3 205 return INT;
jlaskey@3 206 case jdk.internal.org.objectweb.asm.Type.LONG:
jlaskey@3 207 return LONG;
jlaskey@3 208 case jdk.internal.org.objectweb.asm.Type.DOUBLE:
jlaskey@3 209 return NUMBER;
jlaskey@3 210 case jdk.internal.org.objectweb.asm.Type.OBJECT:
jlaskey@3 211 return OBJECT;
jlaskey@3 212 case jdk.internal.org.objectweb.asm.Type.VOID:
jlaskey@3 213 return null;
jlaskey@3 214 case jdk.internal.org.objectweb.asm.Type.ARRAY:
jlaskey@3 215 switch (itype.getElementType().getSort()) {
jlaskey@3 216 case jdk.internal.org.objectweb.asm.Type.DOUBLE:
jlaskey@3 217 return NUMBER_ARRAY;
jlaskey@3 218 case jdk.internal.org.objectweb.asm.Type.INT:
jlaskey@3 219 return INT_ARRAY;
jlaskey@3 220 case jdk.internal.org.objectweb.asm.Type.LONG:
jlaskey@3 221 return LONG_ARRAY;
jlaskey@3 222 default:
jlaskey@3 223 assert false;
jlaskey@3 224 case jdk.internal.org.objectweb.asm.Type.OBJECT:
jlaskey@3 225 return OBJECT_ARRAY;
jlaskey@3 226 }
jlaskey@3 227
jlaskey@3 228 default:
jlaskey@3 229 assert false : "Unknown itype : " + itype + " sort " + itype.getSort();
jlaskey@3 230 break;
jlaskey@3 231 }
jlaskey@3 232 return null;
jlaskey@3 233 }
jlaskey@3 234
jlaskey@3 235 /**
jlaskey@3 236 * Get the return type for a method
jlaskey@3 237 *
jlaskey@3 238 * @param methodDescriptor method descriptor
jlaskey@3 239 * @return return type
jlaskey@3 240 */
jlaskey@3 241 public static Type getMethodReturnType(final String methodDescriptor) {
jlaskey@3 242 return Type.typeFor(jdk.internal.org.objectweb.asm.Type.getReturnType(methodDescriptor));
jlaskey@3 243 }
jlaskey@3 244
jlaskey@3 245 /**
jlaskey@3 246 * Get type array representing arguments of a method in order
jlaskey@3 247 *
jlaskey@3 248 * @param methodDescriptor method descriptor
jlaskey@3 249 * @return parameter type array
jlaskey@3 250 */
jlaskey@3 251 public static Type[] getMethodArguments(final String methodDescriptor) {
jlaskey@3 252 final jdk.internal.org.objectweb.asm.Type itypes[] = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodDescriptor);
jlaskey@3 253 final Type types[] = new Type[itypes.length];
jlaskey@3 254 for (int i = 0; i < itypes.length; i++) {
jlaskey@3 255 types[i] = Type.typeFor(itypes[i]);
jlaskey@3 256 }
jlaskey@3 257 return types;
jlaskey@3 258 }
jlaskey@3 259
jlaskey@3 260 static jdk.internal.org.objectweb.asm.Type getInternalType(final String className) {
jlaskey@3 261 return jdk.internal.org.objectweb.asm.Type.getType(className);
jlaskey@3 262 }
jlaskey@3 263
jlaskey@3 264 private jdk.internal.org.objectweb.asm.Type getInternalType() {
jlaskey@3 265 return jdk.internal.org.objectweb.asm.Type.getType(getTypeClass());
jlaskey@3 266 }
jlaskey@3 267
jlaskey@3 268 private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) {
jlaskey@3 269 return jdk.internal.org.objectweb.asm.Type.getType(type);
jlaskey@3 270 }
jlaskey@3 271
jlaskey@3 272 static void invokeStatic(final MethodVisitor method, final Call call) {
jlaskey@3 273 method.visitMethodInsn(INVOKESTATIC, call.className(), call.name(), call.descriptor());
jlaskey@3 274 }
jlaskey@3 275
jlaskey@3 276 /**
jlaskey@3 277 * Get the internal JVM name of a type
jlaskey@3 278 * @return the internal name
jlaskey@3 279 */
jlaskey@3 280 public String getInternalName() {
jlaskey@3 281 return jdk.internal.org.objectweb.asm.Type.getInternalName(getTypeClass());
jlaskey@3 282 }
jlaskey@3 283
jlaskey@3 284 /**
jlaskey@3 285 * Get the internal JVM name of type type represented by a given Java class
jlaskey@3 286 * @param clazz the class
jlaskey@3 287 * @return the internal name
jlaskey@3 288 */
jlaskey@3 289 public static String getInternalName(final Class<?> clazz) {
jlaskey@3 290 return jdk.internal.org.objectweb.asm.Type.getInternalName(clazz);
jlaskey@3 291 }
jlaskey@3 292
jlaskey@3 293 /**
jlaskey@3 294 * Determines whether a type is the UNKNOWN type, i.e. not set yet
jlaskey@3 295 * Used for type inference.
jlaskey@3 296 *
jlaskey@3 297 * @return true if UNKNOWN, false otherwise
jlaskey@3 298 */
jlaskey@3 299 public boolean isUnknown() {
jlaskey@3 300 return this.equals(Type.UNKNOWN);
jlaskey@3 301 }
jlaskey@3 302
jlaskey@3 303 /**
jlaskey@3 304 * Determines whether a type is the BOOLEAN type
jlaskey@3 305 * @return true if BOOLEAN, false otherwise
jlaskey@3 306 */
jlaskey@3 307 public boolean isBoolean() {
jlaskey@3 308 return this.equals(Type.BOOLEAN);
jlaskey@3 309 }
jlaskey@3 310
jlaskey@3 311 /**
jlaskey@3 312 * Determines whether a type is the INT type
jlaskey@3 313 * @return true if INTEGER, false otherwise
jlaskey@3 314 */
jlaskey@3 315 public boolean isInteger() {
jlaskey@3 316 return this.equals(Type.INT);
jlaskey@3 317 }
jlaskey@3 318
jlaskey@3 319 /**
jlaskey@3 320 * Determines whether a type is the LONG type
jlaskey@3 321 * @return true if LONG, false otherwise
jlaskey@3 322 */
jlaskey@3 323 public boolean isLong() {
jlaskey@3 324 return this.equals(Type.LONG);
jlaskey@3 325 }
jlaskey@3 326
jlaskey@3 327 /**
jlaskey@3 328 * Determines whether a type is the NUMBER type
jlaskey@3 329 * @return true if NUMBER, false otherwise
jlaskey@3 330 */
jlaskey@3 331 public boolean isNumber() {
jlaskey@3 332 return this.equals(Type.NUMBER);
jlaskey@3 333 }
jlaskey@3 334
jlaskey@3 335 /**
jlaskey@3 336 * Determines whether a type is numeric, i.e. NUMBER,
jlaskey@3 337 * INT, LONG.
jlaskey@3 338 *
jlaskey@3 339 * @return true if numeric, false otherwise
jlaskey@3 340 */
jlaskey@3 341 public boolean isNumeric() {
jlaskey@3 342 return this instanceof NumericType;
jlaskey@3 343 }
jlaskey@3 344
jlaskey@3 345 /**
jlaskey@3 346 * Determines whether a type is an array type, i.e.
jlaskey@3 347 * OBJECT_ARRAY or NUMBER_ARRAY (for now)
jlaskey@3 348 *
jlaskey@3 349 * @return true if an array type, false otherwise
jlaskey@3 350 */
jlaskey@3 351 public boolean isArray() {
jlaskey@3 352 return this instanceof ArrayType;
jlaskey@3 353 }
jlaskey@3 354
jlaskey@3 355 /**
jlaskey@3 356 * Determines if a type takes up two bytecode slots or not
jlaskey@3 357 *
jlaskey@3 358 * @return true if type takes up two bytecode slots rather than one
jlaskey@3 359 */
jlaskey@3 360 public boolean isCategory2() {
jlaskey@3 361 return getSlots() == 2;
jlaskey@3 362 }
jlaskey@3 363
jlaskey@3 364 /**
jlaskey@3 365 * Determines whether a type is an OBJECT type, e.g. OBJECT, STRING,
jlaskey@3 366 * NUMBER_ARRAY etc.
jlaskey@3 367 *
jlaskey@3 368 * @return true if object type, false otherwise
jlaskey@3 369 */
jlaskey@3 370 public boolean isObject() {
jlaskey@3 371 return this instanceof ObjectType;
jlaskey@3 372 }
jlaskey@3 373
jlaskey@3 374 /**
jlaskey@3 375 * Determines whether a type is a STRING type
jlaskey@3 376 *
jlaskey@3 377 * @return true if object type, false otherwise
jlaskey@3 378 */
jlaskey@3 379 public boolean isString() {
jlaskey@3 380 return this.equals(Type.STRING);
jlaskey@3 381 }
jlaskey@3 382
jlaskey@3 383 /**
jlaskey@3 384 * Determine if two types are equivalent, i.e. need no conversion
jlaskey@3 385 *
jlaskey@3 386 * @param type the second type to check
jlaskey@3 387 *
jlaskey@3 388 * @return true if types are equivalent, false otherwise
jlaskey@3 389 */
jlaskey@3 390 public boolean isEquivalentTo(final Type type) {
jlaskey@3 391 return this.weight() == type.weight() || (isObject() && type.isObject());
jlaskey@3 392 }
jlaskey@3 393
jlaskey@3 394 /**
jlaskey@3 395 * Determine if a type can be assigned to from another
jlaskey@3 396 *
jlaskey@3 397 * @param type0 the first type to check
jlaskey@3 398 * @param type1 the second type to check
jlaskey@3 399 *
jlaskey@3 400 * @return true if type1 can be written to type2, false otherwise
jlaskey@3 401 */
jlaskey@3 402 public static boolean isAssignableFrom(final Type type0, final Type type1) {
jlaskey@3 403 if (type0.isObject() && type1.isObject()) {
jlaskey@3 404 return type0.weight() >= type1.weight();
jlaskey@3 405 }
jlaskey@3 406
jlaskey@3 407 return type0.weight() == type1.weight();
jlaskey@3 408 }
jlaskey@3 409
jlaskey@3 410 /**
jlaskey@3 411 * Determine if this type is assignable from another type
jlaskey@3 412 * @param type the type to check against
jlaskey@3 413 *
jlaskey@3 414 * @return true if "type" can be written to this type, false otherwise
jlaskey@3 415 */
jlaskey@3 416 public boolean isAssignableFrom(final Type type) {
jlaskey@3 417 return Type.isAssignableFrom(this, type);
jlaskey@3 418 }
jlaskey@3 419
jlaskey@3 420 /**
jlaskey@3 421 * Determines is this type is equivalent to another, i.e. needs no conversion
jlaskey@3 422 * to be assigned to it.
jlaskey@3 423 *
jlaskey@3 424 * @param type0 the first type to check
jlaskey@3 425 * @param type1 the second type to check
jlaskey@3 426 *
jlaskey@3 427 * @return true if this type is equivalent to type, false otherwise
jlaskey@3 428 */
jlaskey@3 429 public static boolean areEquivalent(final Type type0, final Type type1) {
jlaskey@3 430 return type0.isEquivalentTo(type1);
jlaskey@3 431 }
jlaskey@3 432
jlaskey@3 433 /**
jlaskey@3 434 * Determine the number of bytecode slots a type takes up
jlaskey@3 435 *
jlaskey@3 436 * @return the number of slots for this type, 1 or 2.
jlaskey@3 437 */
jlaskey@3 438 public int getSlots() {
jlaskey@3 439 return slots;
jlaskey@3 440 }
jlaskey@3 441 /**
jlaskey@3 442 * Returns the widest or most common of two types
jlaskey@3 443 *
jlaskey@3 444 * @param type0 type one
jlaskey@3 445 * @param type1 type two
jlaskey@3 446 *
jlaskey@3 447 * @return the widest type
jlaskey@3 448 */
jlaskey@3 449 public static Type widest(final Type type0, final Type type1) {
jlaskey@3 450 if (type0.isArray() && type1.isArray()) {
jlaskey@3 451 return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT;
jlaskey@3 452 } else if (type0.isArray() != type1.isArray()) {
jlaskey@3 453 return Type.OBJECT; //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense
jlaskey@3 454 }
jlaskey@3 455 return type0.weight() > type1.weight() ? type0 : type1;
jlaskey@3 456 }
jlaskey@3 457
jlaskey@3 458 /**
jlaskey@3 459 * Returns the narrowest or least common of two types
jlaskey@3 460 *
jlaskey@3 461 * @param type0 type one
jlaskey@3 462 * @param type1 type two
jlaskey@3 463 *
jlaskey@3 464 * @return the widest type
jlaskey@3 465 */
jlaskey@3 466 public static Type narrowest(final Type type0, final Type type1) {
jlaskey@3 467 return type0.weight() < type1.weight() ? type0 : type1;
jlaskey@3 468 }
jlaskey@3 469
jlaskey@3 470 /**
jlaskey@3 471 * Returns the widest or most common of two types, but no wider than "limit"
jlaskey@3 472 *
jlaskey@3 473 * @param type0 type one
jlaskey@3 474 * @param type1 type two
jlaskey@3 475 * @param limit limiting type
jlaskey@3 476 *
jlaskey@3 477 * @return the widest type, but no wider than limit
jlaskey@3 478 */
jlaskey@3 479 public static Type widest(final Type type0, final Type type1, final Type limit) {
jlaskey@3 480 final Type type = Type.widest(type0, type1);
jlaskey@3 481 if (type.weight() > limit.weight()) {
jlaskey@3 482 return limit;
jlaskey@3 483 }
jlaskey@3 484 return type;
jlaskey@3 485 }
jlaskey@3 486
jlaskey@3 487 /**
jlaskey@3 488 * Returns the widest or most common of two types, but no narrower than "limit"
jlaskey@3 489 *
jlaskey@3 490 * @param type0 type one
jlaskey@3 491 * @param type1 type two
jlaskey@3 492 * @param limit limiting type
jlaskey@3 493 *
jlaskey@3 494 * @return the widest type, but no wider than limit
jlaskey@3 495 */
jlaskey@3 496 public static Type narrowest(final Type type0, final Type type1, final Type limit) {
jlaskey@3 497 final Type type = type0.weight() < type1.weight() ? type0 : type1;
jlaskey@3 498 if (type.weight() < limit.weight()) {
jlaskey@3 499 return limit;
jlaskey@3 500 }
jlaskey@3 501 return type;
jlaskey@3 502 }
jlaskey@3 503
jlaskey@3 504 /**
jlaskey@3 505 * Returns the narrowest of this type and another
jlaskey@3 506 *
jlaskey@3 507 * @param other type to compare against
jlaskey@3 508 *
jlaskey@3 509 * @return the widest type
jlaskey@3 510 */
jlaskey@3 511 public Type narrowest(final Type other) {
jlaskey@3 512 return Type.narrowest(this, other);
jlaskey@3 513 }
jlaskey@3 514
jlaskey@3 515 /**
jlaskey@3 516 * Returns the widest of this type and another
jlaskey@3 517 *
jlaskey@3 518 * @param other type to compare against
jlaskey@3 519 *
jlaskey@3 520 * @return the widest type
jlaskey@3 521 */
jlaskey@3 522 public Type widest(final Type other) {
jlaskey@3 523 return Type.widest(this, other);
jlaskey@3 524 }
jlaskey@3 525
jlaskey@3 526 /**
jlaskey@3 527 * Returns the weight of a type, used for type comparison
jlaskey@3 528 * between wider and narrower types
jlaskey@3 529 *
jlaskey@3 530 * @return the weight
jlaskey@3 531 */
jlaskey@3 532 int weight() {
jlaskey@3 533 return weight;
jlaskey@3 534 }
jlaskey@3 535
jlaskey@3 536 /**
jlaskey@3 537 * Return the descriptor of a type, used for e.g. signature
jlaskey@3 538 * generation
jlaskey@3 539 *
jlaskey@3 540 * @return the descriptor
jlaskey@3 541 */
jlaskey@3 542 public String getDescriptor() {
jlaskey@3 543 return descriptor;
jlaskey@3 544 }
jlaskey@3 545
jlaskey@3 546 @Override
jlaskey@3 547 public String toString() {
jlaskey@3 548 return name;
jlaskey@3 549 }
jlaskey@3 550
jlaskey@3 551 /**
jlaskey@3 552 * Return the (possibly cached) Type object for this class
jlaskey@3 553 *
jlaskey@3 554 * @param clazz the class to check
jlaskey@3 555 *
jlaskey@3 556 * @return the Type representing this class
jlaskey@3 557 */
jlaskey@3 558 public static Type typeFor(final Class<?> clazz) {
jlaskey@3 559 Type type = cache.get(clazz);
jlaskey@3 560
jlaskey@3 561 if (type == null) {
jlaskey@3 562 assert !clazz.isPrimitive() || clazz == void.class;
jlaskey@3 563 if (clazz.isArray()) {
jlaskey@3 564 type = new ArrayType(clazz);
jlaskey@3 565 } else {
jlaskey@3 566 type = new ObjectType(clazz);
jlaskey@3 567 }
jlaskey@3 568 cache.put(clazz, type);
jlaskey@3 569 }
jlaskey@3 570
jlaskey@3 571 return type;
jlaskey@3 572 }
jlaskey@3 573
jlaskey@3 574 @Override
jlaskey@3 575 public int compareTo(final Type o) {
jlaskey@3 576 return o.weight() - weight();
jlaskey@3 577 }
jlaskey@3 578
jlaskey@3 579 /**
jlaskey@3 580 * Common logic for implementing dup for all types
jlaskey@3 581 *
jlaskey@3 582 * @param method method visitor
jlaskey@3 583 * @param depth dup depth
jlaskey@3 584 *
jlaskey@3 585 * @return the type at the top of the stack afterwards
jlaskey@3 586 */
jlaskey@3 587 @Override
jlaskey@3 588 public Type dup(final MethodVisitor method, final int depth) {
jlaskey@3 589 return Type.dup(method, this, depth);
jlaskey@3 590 }
jlaskey@3 591
jlaskey@3 592 /**
jlaskey@3 593 * Common logic for implementing swap for all types
jlaskey@3 594 *
jlaskey@3 595 * @param method method visitor
jlaskey@3 596 * @param other the type to swap with
jlaskey@3 597 *
jlaskey@3 598 * @return the type at the top of the stack afterwards, i.e. other
jlaskey@3 599 */
jlaskey@3 600 @Override
jlaskey@3 601 public Type swap(final MethodVisitor method, final Type other) {
jlaskey@3 602 Type.swap(method, this, other);
jlaskey@3 603 return other;
jlaskey@3 604 }
jlaskey@3 605
jlaskey@3 606 /**
jlaskey@3 607 * Common logic for implementing pop for all types
jlaskey@3 608 *
jlaskey@3 609 * @param method method visitor
jlaskey@3 610 *
jlaskey@3 611 * @return the type that was popped
jlaskey@3 612 */
jlaskey@3 613 @Override
jlaskey@3 614 public Type pop(final MethodVisitor method) {
jlaskey@3 615 Type.pop(method, this);
jlaskey@3 616 return this;
jlaskey@3 617 }
jlaskey@3 618
jlaskey@3 619 /**
jlaskey@3 620 * Superclass logic for pop for all types
jlaskey@3 621 *
jlaskey@3 622 * @param method method emitter
jlaskey@3 623 * @param type type to pop
jlaskey@3 624 */
jlaskey@3 625 protected static void pop(final MethodVisitor method, final Type type) {
jlaskey@3 626 method.visitInsn(type.isCategory2() ? POP2 : POP);
jlaskey@3 627 }
jlaskey@3 628
jlaskey@3 629 private static Type dup(final MethodVisitor method, final Type type, final int depth) {
jlaskey@3 630 final boolean cat2 = type.isCategory2();
jlaskey@3 631
jlaskey@3 632 switch (depth) {
jlaskey@3 633 case 0:
jlaskey@3 634 method.visitInsn(cat2 ? DUP2 : DUP);
jlaskey@3 635 break;
jlaskey@3 636 case 1:
jlaskey@3 637 method.visitInsn(cat2 ? DUP2_X1 : DUP_X1);
jlaskey@3 638 break;
jlaskey@3 639 case 2:
jlaskey@3 640 method.visitInsn(cat2 ? DUP2_X2 : DUP_X2);
jlaskey@3 641 break;
jlaskey@3 642 default:
jlaskey@3 643 return null; //invalid depth
jlaskey@3 644 }
jlaskey@3 645
jlaskey@3 646 return type;
jlaskey@3 647 }
jlaskey@3 648
jlaskey@3 649 private static void swap(final MethodVisitor method, final Type above, final Type below) {
jlaskey@3 650 if (below.isCategory2()) {
jlaskey@3 651 if (above.isCategory2()) {
lagergren@137 652 method.visitInsn(DUP2_X2);
lagergren@137 653 method.visitInsn(POP2);
jlaskey@3 654 } else {
lagergren@137 655 method.visitInsn(DUP_X2);
lagergren@137 656 method.visitInsn(POP);
jlaskey@3 657 }
jlaskey@3 658 } else {
jlaskey@3 659 if (above.isCategory2()) {
lagergren@137 660 method.visitInsn(DUP2_X1);
lagergren@137 661 method.visitInsn(POP2);
jlaskey@3 662 } else {
lagergren@137 663 method.visitInsn(SWAP);
jlaskey@3 664 }
jlaskey@3 665 }
jlaskey@3 666
jlaskey@3 667 }
jlaskey@3 668
jlaskey@3 669 /**
jlaskey@3 670 * This is the boolean singleton, used for all boolean types
jlaskey@3 671 */
jlaskey@3 672 public static final Type BOOLEAN = new BooleanType();
jlaskey@3 673
jlaskey@3 674 /**
jlaskey@3 675 * This is an integer type, i.e INT, INT32.
jlaskey@3 676 */
jlaskey@3 677 public static final Type INT = new IntType();
jlaskey@3 678
jlaskey@3 679 /**
jlaskey@3 680 * This is the number singleton, used for all number types
jlaskey@3 681 */
jlaskey@3 682 public static final Type NUMBER = new NumberType();
jlaskey@3 683
jlaskey@3 684 /**
jlaskey@3 685 * This is the long singleton, used for all long types
jlaskey@3 686 */
jlaskey@3 687 public static final Type LONG = new LongType();
jlaskey@3 688
jlaskey@3 689 /**
jlaskey@3 690 * A string singleton
jlaskey@3 691 */
jlaskey@3 692 public static final Type STRING = new ObjectType(String.class);
jlaskey@3 693
jlaskey@3 694 /**
jlaskey@3 695 * This is the object singleton, used for all object types
jlaskey@3 696 */
jlaskey@3 697 public static final Type OBJECT = new ObjectType();
jlaskey@3 698
jlaskey@3 699 /**
jlaskey@3 700 * This is the singleton for integer arrays
jlaskey@3 701 */
jlaskey@3 702 public static final ArrayType INT_ARRAY = new ArrayType(int[].class) {
jlaskey@3 703 @Override
jlaskey@3 704 public void astore(final MethodVisitor method) {
jlaskey@3 705 method.visitInsn(IASTORE);
jlaskey@3 706 }
jlaskey@3 707
jlaskey@3 708 @Override
jlaskey@3 709 public Type aload(final MethodVisitor method) {
jlaskey@3 710 method.visitInsn(IALOAD);
jlaskey@3 711 return INT;
jlaskey@3 712 }
jlaskey@3 713
jlaskey@3 714 @Override
jlaskey@3 715 public Type newarray(final MethodVisitor method) {
jlaskey@3 716 method.visitIntInsn(NEWARRAY, T_INT);
jlaskey@3 717 return this;
jlaskey@3 718 }
jlaskey@3 719
jlaskey@3 720 @Override
jlaskey@3 721 public Type getElementType() {
jlaskey@3 722 return INT;
jlaskey@3 723 }
jlaskey@3 724 };
jlaskey@3 725
jlaskey@3 726 /**
jlaskey@3 727 * This is the singleton for long arrays
jlaskey@3 728 */
jlaskey@3 729 public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) {
jlaskey@3 730 @Override
jlaskey@3 731 public void astore(final MethodVisitor method) {
jlaskey@3 732 method.visitInsn(LASTORE);
jlaskey@3 733 }
jlaskey@3 734
jlaskey@3 735 @Override
jlaskey@3 736 public Type aload(final MethodVisitor method) {
jlaskey@3 737 method.visitInsn(IALOAD);
jlaskey@3 738 return INT;
jlaskey@3 739 }
jlaskey@3 740
jlaskey@3 741 @Override
jlaskey@3 742 public Type newarray(final MethodVisitor method) {
jlaskey@3 743 method.visitIntInsn(NEWARRAY, T_INT);
jlaskey@3 744 return this;
jlaskey@3 745 }
jlaskey@3 746
jlaskey@3 747 @Override
jlaskey@3 748 public Type getElementType() {
jlaskey@3 749 return INT;
jlaskey@3 750 }
jlaskey@3 751 };
jlaskey@3 752
jlaskey@3 753 /**
jlaskey@3 754 * This is the singleton for numeric arrays
jlaskey@3 755 */
jlaskey@3 756 public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) {
jlaskey@3 757 @Override
jlaskey@3 758 public void astore(final MethodVisitor method) {
jlaskey@3 759 method.visitInsn(DASTORE);
jlaskey@3 760 }
jlaskey@3 761
jlaskey@3 762 @Override
jlaskey@3 763 public Type aload(final MethodVisitor method) {
jlaskey@3 764 method.visitInsn(DALOAD);
jlaskey@3 765 return NUMBER;
jlaskey@3 766 }
jlaskey@3 767
jlaskey@3 768 @Override
jlaskey@3 769 public Type newarray(final MethodVisitor method) {
jlaskey@3 770 method.visitIntInsn(NEWARRAY, T_DOUBLE);
jlaskey@3 771 return this;
jlaskey@3 772 }
jlaskey@3 773
jlaskey@3 774 @Override
jlaskey@3 775 public Type getElementType() {
jlaskey@3 776 return NUMBER;
jlaskey@3 777 }
jlaskey@3 778 };
jlaskey@3 779
jlaskey@3 780 /** Singleton for method handle arrays used for properties etc. */
attila@62 781 public static final ArrayType METHODHANDLE_ARRAY = new ArrayType(MethodHandle[].class);
jlaskey@3 782
jlaskey@3 783 /** This is the singleton for string arrays */
attila@62 784 public static final ArrayType STRING_ARRAY = new ArrayType(String[].class);
jlaskey@3 785
jlaskey@3 786 /** This is the singleton for object arrays */
attila@62 787 public static final ArrayType OBJECT_ARRAY = new ArrayType(Object[].class);
jlaskey@3 788
jlaskey@3 789 /** This type, always an object type, just a toString override */
jlaskey@3 790 public static final Type THIS = new ObjectType() {
jlaskey@3 791 @Override
jlaskey@3 792 public String toString() {
jlaskey@3 793 return "this";
jlaskey@3 794 }
jlaskey@3 795 };
jlaskey@3 796
jlaskey@3 797 /** Scope type, always an object type, just a toString override */
jlaskey@3 798 public static final Type SCOPE = new ObjectType() {
jlaskey@3 799 @Override
jlaskey@3 800 public String toString() {
jlaskey@3 801 return "scope";
jlaskey@3 802 }
jlaskey@3 803 };
jlaskey@3 804
jlaskey@3 805 private static interface Unknown {
jlaskey@3 806 // EMPTY - used as a class that is absolutely not compatible with a type to represent "unknown"
jlaskey@3 807 }
jlaskey@3 808
jlaskey@3 809 /**
jlaskey@3 810 * This is the unknown type which is used as initial type for type
jlaskey@3 811 * inference. It has the minimum type width
jlaskey@3 812 */
jlaskey@3 813 public static final Type UNKNOWN = new Type("<unknown>", Unknown.class, MIN_WEIGHT, 1) {
jlaskey@3 814
jlaskey@3 815 @Override
jlaskey@3 816 public String getDescriptor() {
jlaskey@3 817 return "<unknown>";
jlaskey@3 818 }
jlaskey@3 819
jlaskey@3 820 @Override
jlaskey@3 821 public Type load(final MethodVisitor method, final int slot) {
jlaskey@3 822 assert false : "unsupported operation";
jlaskey@3 823 return null;
jlaskey@3 824 }
jlaskey@3 825
jlaskey@3 826 @Override
jlaskey@3 827 public void store(final MethodVisitor method, final int slot) {
jlaskey@3 828 assert false : "unsupported operation";
jlaskey@3 829 }
jlaskey@3 830
jlaskey@3 831 @Override
jlaskey@3 832 public Type ldc(final MethodVisitor method, final Object c) {
jlaskey@3 833 assert false : "unsupported operation";
jlaskey@3 834 return null;
jlaskey@3 835 }
jlaskey@3 836
jlaskey@3 837 @Override
jlaskey@3 838 public Type loadUndefined(final MethodVisitor method) {
jlaskey@3 839 assert false : "unsupported operation";
jlaskey@3 840 return null;
jlaskey@3 841 }
jlaskey@3 842
jlaskey@3 843 @Override
jlaskey@3 844 public Type loadEmpty(final MethodVisitor method) {
jlaskey@3 845 assert false : "unsupported operation";
jlaskey@3 846 return null;
jlaskey@3 847 }
jlaskey@3 848
jlaskey@3 849 @Override
jlaskey@3 850 public Type convert(final MethodVisitor method, final Type to) {
jlaskey@3 851 assert false : "unsupported operation";
jlaskey@3 852 return null;
jlaskey@3 853 }
jlaskey@3 854
jlaskey@3 855 @Override
jlaskey@3 856 public void _return(final MethodVisitor method) {
jlaskey@3 857 assert false : "unsupported operation";
jlaskey@3 858 }
jlaskey@3 859
jlaskey@3 860 @Override
jlaskey@3 861 public Type add(final MethodVisitor method) {
jlaskey@3 862 assert false : "unsupported operation";
jlaskey@3 863 return null;
jlaskey@3 864 }
jlaskey@3 865 };
jlaskey@3 866
jlaskey@3 867 /** Mappings between java classes and their Type singletons */
jlaskey@3 868 private static final Map<Class<?>, Type> cache = Collections.synchronizedMap(new HashMap<Class<?>, Type>());
jlaskey@3 869
jlaskey@3 870 //TODO may need to be cleared, as all types are retained throughout code generation
jlaskey@3 871 static {
jlaskey@3 872 cache.put(BOOLEAN.getTypeClass(), BOOLEAN);
jlaskey@3 873 cache.put(INT.getTypeClass(), INT);
jlaskey@3 874 cache.put(LONG.getTypeClass(), LONG);
jlaskey@3 875 cache.put(NUMBER.getTypeClass(), NUMBER);
jlaskey@3 876 cache.put(STRING.getTypeClass(), STRING);
jlaskey@3 877 cache.put(OBJECT.getTypeClass(), OBJECT);
jlaskey@3 878 cache.put(OBJECT_ARRAY.getTypeClass(), OBJECT_ARRAY);
jlaskey@3 879 }
jlaskey@3 880
jlaskey@3 881 }

mercurial