Type.java revision 1088:7e62d98d4625
174462Salfred/* 274462Salfred * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 374462Salfred * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 474462Salfred * 574462Salfred * This code is free software; you can redistribute it and/or modify it 674462Salfred * under the terms of the GNU General Public License version 2 only, as 774462Salfred * published by the Free Software Foundation. Oracle designates this 874462Salfred * particular file as subject to the "Classpath" exception as provided 974462Salfred * by Oracle in the LICENSE file that accompanied this code. 1074462Salfred * 1174462Salfred * This code is distributed in the hope that it will be useful, but WITHOUT 1274462Salfred * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 1374462Salfred * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 1474462Salfred * version 2 for more details (a copy is included in the LICENSE file that 1574462Salfred * accompanied this code). 1674462Salfred * 1774462Salfred * You should have received a copy of the GNU General Public License version 1874462Salfred * 2 along with this work; if not, write to the Free Software Foundation, 1974462Salfred * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 2074462Salfred * 2174462Salfred * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 2274462Salfred * or visit www.oracle.com if you need additional information or have any 2374462Salfred * questions. 2474462Salfred */ 2574462Salfred 2674462Salfredpackage jdk.nashorn.internal.codegen.types; 2774462Salfred 2874462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DALOAD; 2974462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DASTORE; 3074462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP; 3174462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP2; 3274462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X1; 3374462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP2_X2; 3474462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP_X1; 3574462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.DUP_X2; 3674462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.H_INVOKESTATIC; 3774462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.IALOAD; 3874462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.IASTORE; 3974462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.INVOKESTATIC; 4074462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.LALOAD; 4174462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.LASTORE; 4274462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.NEWARRAY; 4374462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.POP; 4474462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.POP2; 4574462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.SWAP; 4674462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.T_DOUBLE; 47228990Suqsimport static jdk.internal.org.objectweb.asm.Opcodes.T_INT; 4874462Salfredimport static jdk.internal.org.objectweb.asm.Opcodes.T_LONG; 4974462Salfredimport static jdk.nashorn.internal.codegen.CompilerConstants.staticCallNoLookup; 5074462Salfred 5174462Salfredimport java.io.DataInput; 5274462Salfredimport java.io.DataOutput; 5374462Salfredimport java.io.IOException; 5474462Salfredimport java.io.Serializable; 5574462Salfredimport java.lang.invoke.CallSite; 5674462Salfredimport java.lang.invoke.MethodHandle; 5774462Salfredimport java.lang.invoke.MethodHandles; 5874462Salfredimport java.lang.invoke.MethodType; 5974462Salfredimport java.util.Collections; 6074462Salfredimport java.util.Map; 6174462Salfredimport java.util.TreeMap; 6274462Salfredimport java.util.WeakHashMap; 6374462Salfredimport java.util.concurrent.ConcurrentHashMap; 6474462Salfredimport java.util.concurrent.ConcurrentMap; 6574462Salfredimport jdk.internal.org.objectweb.asm.Handle; 6674462Salfredimport jdk.internal.org.objectweb.asm.MethodVisitor; 6774462Salfredimport jdk.nashorn.internal.codegen.CompilerConstants.Call; 6874462Salfredimport jdk.nashorn.internal.runtime.ScriptObject; 6974462Salfredimport jdk.nashorn.internal.runtime.Undefined; 7074462Salfredimport jdk.nashorn.internal.runtime.linker.Bootstrap; 7174462Salfred 7274462Salfred/** 7374462Salfred * This is the representation of a JavaScript type, disassociated from java 74173412Skevlo * Classes, with the basis for conversion weight, mapping to ASM types 7574462Salfred * and implementing the ByteCodeOps interface which tells this type 7674462Salfred * how to generate code for various operations. 7774462Salfred * 7874462Salfred * Except for ClassEmitter, this is the only class that has to know 7974462Salfred * about the underlying byte code generation system. 8074462Salfred * 8174462Salfred * The different types know how to generate bytecode for the different 8274462Salfred * operations, inherited from BytecodeOps, that they support. This avoids 8374462Salfred * if/else chains depending on type in several cases and allows for 8474462Salfred * more readable and shorter code 8574462Salfred * 8674462Salfred * The Type class also contains logic used by the type inference and 8774462Salfred * for comparing types against each other, as well as the concepts 8874462Salfred * of narrower to wider types. The widest type is an object. Ideally we 8974462Salfred * would like as narrow types as possible for code to be efficient, e.g 9074462Salfred * INTs rather than OBJECTs 9174462Salfred */ 9274462Salfred 9374462Salfredpublic abstract class Type implements Comparable<Type>, BytecodeOps, Serializable { 9474462Salfred private static final long serialVersionUID = 1L; 9574462Salfred 9674462Salfred /** Human readable name for type */ 9779722Siedowse private transient final String name; 9874462Salfred 9974462Salfred /** Descriptor for type */ 10074462Salfred private transient final String descriptor; 10174462Salfred 10274462Salfred /** The "weight" of the type. Used for picking widest/least specific common type */ 10374462Salfred private transient final int weight; 10474462Salfred 10579722Siedowse /** How many bytecode slots does this type occupy */ 10674462Salfred private transient final int slots; 10774462Salfred 10874462Salfred /** The class for this type */ 10974462Salfred private final Class<?> clazz; 11074462Salfred 11174462Salfred /** 112104592Salfred * Cache for internal types - this is a query that requires complex stringbuilding inside 11374462Salfred * ASM and it saves startup time to cache the type mappings 11474462Salfred */ 11574462Salfred private static final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> INTERNAL_TYPE_CACHE = 11674462Salfred Collections.synchronizedMap(new WeakHashMap<Class<?>, jdk.internal.org.objectweb.asm.Type>()); 11774462Salfred 11874462Salfred /** Internal ASM type for this Type - computed once at construction */ 11974462Salfred private transient final jdk.internal.org.objectweb.asm.Type internalType; 12096788Sjmallett 12174462Salfred /** Weights are used to decide which types are "wider" than other types */ 12274462Salfred protected static final int MIN_WEIGHT = -1; 12374462Salfred 12474462Salfred /** Set way below Integer.MAX_VALUE to prevent overflow when adding weights. Objects are still heaviest. */ 12574462Salfred protected static final int MAX_WEIGHT = 20; 12674462Salfred 12774462Salfred static final Call BOOTSTRAP = staticCallNoLookup(Bootstrap.class, "mathBootstrap", CallSite.class, MethodHandles.Lookup.class, String.class, MethodType.class, int.class); 12874462Salfred 12974462Salfred static final Handle MATHBOOTSTRAP = new Handle(H_INVOKESTATIC, BOOTSTRAP.className(), "mathBootstrap", BOOTSTRAP.descriptor()); 13074462Salfred 13174462Salfred /** 13274462Salfred * Constructor 13374462Salfred * 13474462Salfred * @param clazz class for type 13574462Salfred * @param weight weight - higher is more generic 13674462Salfred * @param slots how many bytecode slots the type takes up 13774462Salfred */ 13874462Salfred Type(final String name, final Class<?> clazz, final int weight, final int slots) { 13974462Salfred this.name = name; 14074462Salfred this.clazz = clazz; 14174462Salfred this.descriptor = jdk.internal.org.objectweb.asm.Type.getDescriptor(clazz); 14274462Salfred this.weight = weight; 14374462Salfred assert weight >= MIN_WEIGHT && weight <= MAX_WEIGHT : "illegal type weight: " + weight; 14474462Salfred this.slots = slots; 14574462Salfred this.internalType = getInternalType(clazz); 14674462Salfred } 14774462Salfred 14874462Salfred /** 14974462Salfred * Get the weight of this type - use this e.g. for sorting method descriptors 15074462Salfred * @return the weight 15174462Salfred */ 15274462Salfred public int getWeight() { 15374462Salfred return weight; 15474462Salfred } 15574462Salfred 15674462Salfred /** 15774462Salfred * Get the Class representing this type 15874462Salfred * @return the class for this type 15974462Salfred */ 16074462Salfred public Class<?> getTypeClass() { 16174462Salfred return clazz; 16274462Salfred } 16374462Salfred 16474462Salfred /** 16574462Salfred * For specialization, return the next, slightly more difficulty, type 16674462Salfred * to test. 16774462Salfred * 16874462Salfred * @return the next Type 16974462Salfred */ 17074462Salfred public Type nextWider() { 17174462Salfred return null; 17274462Salfred } 17374462Salfred 17474462Salfred /** 17574462Salfred * Get the boxed type for this class 17674462Salfred * @return the boxed version of this type or null if N/A 17774462Salfred */ 17874462Salfred public Class<?> getBoxedType() { 17974462Salfred assert !getTypeClass().isPrimitive(); 18074462Salfred return null; 18174462Salfred } 18274462Salfred 18374462Salfred /** 18474462Salfred * Returns the character describing the bytecode type for this value on the stack or local variable, identical to 18574462Salfred * what would be used as the prefix for a bytecode {@code LOAD} or {@code STORE} instruction, therefore it must be 18674462Salfred * one of {@code A, F, D, I, L}. Also, the special value {@code U} is used for local variable slots that haven't 18774462Salfred * been initialized yet (it can't appear for a value pushed to the operand stack, those always have known values). 18874462Salfred * Note that while we allow all JVM internal types, Nashorn doesn't necessarily use them all - currently we don't 18974462Salfred * have floats, only doubles, but that might change in the future. 19074462Salfred * @return the character describing the bytecode type for this value on the stack. 19174462Salfred */ 19274462Salfred public abstract char getBytecodeStackType(); 19374462Salfred 19474462Salfred /** 19574462Salfred * Generate a method descriptor given a return type and a param array 19674462Salfred * 19774462Salfred * @param returnType return type 19874462Salfred * @param types parameters 19974462Salfred * 20074462Salfred * @return a descriptor string 20174462Salfred */ 20274462Salfred public static String getMethodDescriptor(final Type returnType, final Type... types) { 20374462Salfred final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length]; 20474462Salfred for (int i = 0; i < types.length; i++) { 20574462Salfred itypes[i] = types[i].getInternalType(); 20674462Salfred } 20774462Salfred return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(returnType.getInternalType(), itypes); 20874462Salfred } 20974462Salfred 21074462Salfred /** 21174462Salfred * Generate a method descriptor given a return type and a param array 21274462Salfred * 21374462Salfred * @param returnType return type 21474462Salfred * @param types parameters 21574462Salfred * 21674462Salfred * @return a descriptor string 21774462Salfred */ 21874462Salfred public static String getMethodDescriptor(final Class<?> returnType, final Class<?>... types) { 21974462Salfred final jdk.internal.org.objectweb.asm.Type[] itypes = new jdk.internal.org.objectweb.asm.Type[types.length]; 22074462Salfred for (int i = 0; i < types.length; i++) { 22174462Salfred itypes[i] = getInternalType(types[i]); 22274462Salfred } 22374462Salfred return jdk.internal.org.objectweb.asm.Type.getMethodDescriptor(getInternalType(returnType), itypes); 22474462Salfred } 22574462Salfred 22674462Salfred /** 22774462Salfred * Return a character representing {@code type} in a method signature. 22874462Salfred * 22974462Salfred * @param type parameter type 23074462Salfred * @return descriptor character 23174462Salfred */ 232 public static char getShortSignatureDescriptor(final Type type) { 233 // Use 'Z' for boolean parameters as we need to distinguish from int 234 if (type instanceof BooleanType) { 235 return 'Z'; 236 } 237 return type.getBytecodeStackType(); 238 } 239 240 /** 241 * Return the type for an internal type, package private - do not use 242 * outside code gen 243 * 244 * @param itype internal type 245 * @return Nashorn type 246 */ 247 @SuppressWarnings("fallthrough") 248 static Type typeFor(final jdk.internal.org.objectweb.asm.Type itype) { 249 switch (itype.getSort()) { 250 case jdk.internal.org.objectweb.asm.Type.BOOLEAN: 251 return BOOLEAN; 252 case jdk.internal.org.objectweb.asm.Type.INT: 253 return INT; 254 case jdk.internal.org.objectweb.asm.Type.LONG: 255 return LONG; 256 case jdk.internal.org.objectweb.asm.Type.DOUBLE: 257 return NUMBER; 258 case jdk.internal.org.objectweb.asm.Type.OBJECT: 259 try { 260 return Type.typeFor(Class.forName(itype.getClassName())); 261 } catch(final ClassNotFoundException e) { 262 throw new AssertionError(e); 263 } 264 case jdk.internal.org.objectweb.asm.Type.VOID: 265 return null; 266 case jdk.internal.org.objectweb.asm.Type.ARRAY: 267 switch (itype.getElementType().getSort()) { 268 case jdk.internal.org.objectweb.asm.Type.DOUBLE: 269 return NUMBER_ARRAY; 270 case jdk.internal.org.objectweb.asm.Type.INT: 271 return INT_ARRAY; 272 case jdk.internal.org.objectweb.asm.Type.LONG: 273 return LONG_ARRAY; 274 default: 275 assert false; 276 case jdk.internal.org.objectweb.asm.Type.OBJECT: 277 return OBJECT_ARRAY; 278 } 279 280 default: 281 assert false : "Unknown itype : " + itype + " sort " + itype.getSort(); 282 break; 283 } 284 return null; 285 } 286 287 /** 288 * Get the return type for a method 289 * 290 * @param methodDescriptor method descriptor 291 * @return return type 292 */ 293 public static Type getMethodReturnType(final String methodDescriptor) { 294 return Type.typeFor(jdk.internal.org.objectweb.asm.Type.getReturnType(methodDescriptor)); 295 } 296 297 /** 298 * Get type array representing arguments of a method in order 299 * 300 * @param methodDescriptor method descriptor 301 * @return parameter type array 302 */ 303 public static Type[] getMethodArguments(final String methodDescriptor) { 304 final jdk.internal.org.objectweb.asm.Type itypes[] = jdk.internal.org.objectweb.asm.Type.getArgumentTypes(methodDescriptor); 305 final Type types[] = new Type[itypes.length]; 306 for (int i = 0; i < itypes.length; i++) { 307 types[i] = Type.typeFor(itypes[i]); 308 } 309 return types; 310 } 311 312 /** 313 * Write a map of {@code int} to {@code Type} to an output stream. This is used to store deoptimization state. 314 * 315 * @param typeMap the type map 316 * @param output data output 317 * @throws IOException if write cannot be completed 318 */ 319 public static void writeTypeMap(final Map<Integer, Type> typeMap, final DataOutput output) throws IOException { 320 if (typeMap == null) { 321 output.writeInt(0); 322 } else { 323 output.writeInt(typeMap.size()); 324 for(final Map.Entry<Integer, Type> e: typeMap.entrySet()) { 325 output.writeInt(e.getKey()); 326 final byte typeChar; 327 final Type type = e.getValue(); 328 if(type == Type.OBJECT) { 329 typeChar = 'L'; 330 } else if (type == Type.NUMBER) { 331 typeChar = 'D'; 332 } else if (type == Type.LONG) { 333 typeChar = 'J'; 334 } else { 335 throw new AssertionError(); 336 } 337 output.writeByte(typeChar); 338 } 339 } 340 } 341 342 /** 343 * Read a map of {@code int} to {@code Type} from an input stream. This is used to store deoptimization state. 344 * 345 * @param input data input 346 * @return type map 347 * @throws IOException if read cannot be completed 348 */ 349 public static Map<Integer, Type> readTypeMap(final DataInput input) throws IOException { 350 final int size = input.readInt(); 351 if (size <= 0) { 352 return null; 353 } 354 final Map<Integer, Type> map = new TreeMap<>(); 355 for(int i = 0; i < size; ++i) { 356 final int pp = input.readInt(); 357 final int typeChar = input.readByte(); 358 final Type type; 359 switch (typeChar) { 360 case 'L': type = Type.OBJECT; break; 361 case 'D': type = Type.NUMBER; break; 362 case 'J': type = Type.LONG; break; 363 default: continue; 364 } 365 map.put(pp, type); 366 } 367 return map; 368 } 369 370 static jdk.internal.org.objectweb.asm.Type getInternalType(final String className) { 371 return jdk.internal.org.objectweb.asm.Type.getType(className); 372 } 373 374 private jdk.internal.org.objectweb.asm.Type getInternalType() { 375 return internalType; 376 } 377 378 private static jdk.internal.org.objectweb.asm.Type lookupInternalType(final Class<?> type) { 379 final Map<Class<?>, jdk.internal.org.objectweb.asm.Type> c = INTERNAL_TYPE_CACHE; 380 jdk.internal.org.objectweb.asm.Type itype = c.get(type); 381 if (itype != null) { 382 return itype; 383 } 384 itype = jdk.internal.org.objectweb.asm.Type.getType(type); 385 c.put(type, itype); 386 return itype; 387 } 388 389 private static jdk.internal.org.objectweb.asm.Type getInternalType(final Class<?> type) { 390 return lookupInternalType(type); 391 } 392 393 static void invokestatic(final MethodVisitor method, final Call call) { 394 method.visitMethodInsn(INVOKESTATIC, call.className(), call.name(), call.descriptor(), false); 395 } 396 397 /** 398 * Get the internal JVM name of a type 399 * @return the internal name 400 */ 401 public String getInternalName() { 402 return jdk.internal.org.objectweb.asm.Type.getInternalName(getTypeClass()); 403 } 404 405 /** 406 * Get the internal JVM name of type type represented by a given Java class 407 * @param clazz the class 408 * @return the internal name 409 */ 410 public static String getInternalName(final Class<?> clazz) { 411 return jdk.internal.org.objectweb.asm.Type.getInternalName(clazz); 412 } 413 414 /** 415 * Determines whether a type is the UNKNOWN type, i.e. not set yet 416 * Used for type inference. 417 * 418 * @return true if UNKNOWN, false otherwise 419 */ 420 public boolean isUnknown() { 421 return this.equals(Type.UNKNOWN); 422 } 423 424 /** 425 * Determines whether this type represents an primitive type according to the ECMAScript specification, 426 * which includes Boolean, Number, and String. 427 * 428 * @return true if a JavaScript primitive type, false otherwise. 429 */ 430 public boolean isJSPrimitive() { 431 return !isObject() || isString(); 432 } 433 434 /** 435 * Determines whether a type is the BOOLEAN type 436 * @return true if BOOLEAN, false otherwise 437 */ 438 public boolean isBoolean() { 439 return this.equals(Type.BOOLEAN); 440 } 441 442 /** 443 * Determines whether a type is the INT type 444 * @return true if INTEGER, false otherwise 445 */ 446 public boolean isInteger() { 447 return this.equals(Type.INT); 448 } 449 450 /** 451 * Determines whether a type is the LONG type 452 * @return true if LONG, false otherwise 453 */ 454 public boolean isLong() { 455 return this.equals(Type.LONG); 456 } 457 458 /** 459 * Determines whether a type is the NUMBER type 460 * @return true if NUMBER, false otherwise 461 */ 462 public boolean isNumber() { 463 return this.equals(Type.NUMBER); 464 } 465 466 /** 467 * Determines whether a type is numeric, i.e. NUMBER, 468 * INT, LONG. 469 * 470 * @return true if numeric, false otherwise 471 */ 472 public boolean isNumeric() { 473 return this instanceof NumericType; 474 } 475 476 /** 477 * Determines whether a type is an array type, i.e. 478 * OBJECT_ARRAY or NUMBER_ARRAY (for now) 479 * 480 * @return true if an array type, false otherwise 481 */ 482 public boolean isArray() { 483 return this instanceof ArrayType; 484 } 485 486 /** 487 * Determines if a type takes up two bytecode slots or not 488 * 489 * @return true if type takes up two bytecode slots rather than one 490 */ 491 public boolean isCategory2() { 492 return getSlots() == 2; 493 } 494 495 /** 496 * Determines whether a type is an OBJECT type, e.g. OBJECT, STRING, 497 * NUMBER_ARRAY etc. 498 * 499 * @return true if object type, false otherwise 500 */ 501 public boolean isObject() { 502 return this instanceof ObjectType; 503 } 504 505 /** 506 * Is this a primitive type (e.g int, long, double, boolean) 507 * @return true if primitive 508 */ 509 public boolean isPrimitive() { 510 return !isObject(); 511 } 512 513 /** 514 * Determines whether a type is a STRING type 515 * 516 * @return true if object type, false otherwise 517 */ 518 public boolean isString() { 519 return this.equals(Type.STRING); 520 } 521 522 /** 523 * Determines whether a type is a CHARSEQUENCE type used internally strings 524 * 525 * @return true if CharSequence (internal string) type, false otherwise 526 */ 527 public boolean isCharSequence() { 528 return this.equals(Type.CHARSEQUENCE); 529 } 530 531 /** 532 * Determine if two types are equivalent, i.e. need no conversion 533 * 534 * @param type the second type to check 535 * 536 * @return true if types are equivalent, false otherwise 537 */ 538 public boolean isEquivalentTo(final Type type) { 539 return this.weight() == type.weight() || isObject() && type.isObject(); 540 } 541 542 /** 543 * Determine if a type can be assigned to from another 544 * 545 * @param type0 the first type to check 546 * @param type1 the second type to check 547 * 548 * @return true if type1 can be written to type2, false otherwise 549 */ 550 public static boolean isAssignableFrom(final Type type0, final Type type1) { 551 if (type0.isObject() && type1.isObject()) { 552 return type0.weight() >= type1.weight(); 553 } 554 555 return type0.weight() == type1.weight(); 556 } 557 558 /** 559 * Determine if this type is assignable from another type 560 * @param type the type to check against 561 * 562 * @return true if "type" can be written to this type, false otherwise 563 */ 564 public boolean isAssignableFrom(final Type type) { 565 return Type.isAssignableFrom(this, type); 566 } 567 568 /** 569 * Determines is this type is equivalent to another, i.e. needs no conversion 570 * to be assigned to it. 571 * 572 * @param type0 the first type to check 573 * @param type1 the second type to check 574 * 575 * @return true if this type is equivalent to type, false otherwise 576 */ 577 public static boolean areEquivalent(final Type type0, final Type type1) { 578 return type0.isEquivalentTo(type1); 579 } 580 581 /** 582 * Determine the number of bytecode slots a type takes up 583 * 584 * @return the number of slots for this type, 1 or 2. 585 */ 586 public int getSlots() { 587 return slots; 588 } 589 590 /** 591 * Returns the widest or most common of two types 592 * 593 * @param type0 type one 594 * @param type1 type two 595 * 596 * @return the widest type 597 */ 598 public static Type widest(final Type type0, final Type type1) { 599 if (type0.isArray() && type1.isArray()) { 600 return ((ArrayType)type0).getElementType() == ((ArrayType)type1).getElementType() ? type0 : Type.OBJECT; 601 } else if (type0.isArray() != type1.isArray()) { 602 //array and non array is always object, widest(Object[], int) NEVER returns Object[], which has most weight. that does not make sense 603 return Type.OBJECT; 604 } else if (type0.isObject() && type1.isObject() && type0.getTypeClass() != type1.getTypeClass()) { 605 // Object<type=String> and Object<type=ScriptFunction> will produce Object 606 // TODO: maybe find most specific common superclass? 607 return Type.OBJECT; 608 } 609 return type0.weight() > type1.weight() ? type0 : type1; 610 } 611 612 /** 613 * Returns the widest or most common of two types, given as classes 614 * 615 * @param type0 type one 616 * @param type1 type two 617 * 618 * @return the widest type 619 */ 620 public static Class<?> widest(final Class<?> type0, final Class<?> type1) { 621 return widest(Type.typeFor(type0), Type.typeFor(type1)).getTypeClass(); 622 } 623 624 /** 625 * When doing widening for return types of a function or a ternary operator, it is not valid to widen a boolean to 626 * anything other than object. Note that this wouldn't be necessary if {@code Type.widest} did not allow 627 * boolean-to-number widening. Eventually, we should address it there, but it affects too many other parts of the 628 * system and is sometimes legitimate (e.g. whenever a boolean value would undergo ToNumber conversion anyway). 629 * @param t1 type 1 630 * @param t2 type 2 631 * @return wider of t1 and t2, except if one is boolean and the other is neither boolean nor unknown, in which case 632 * {@code Type.OBJECT} is returned. 633 */ 634 public static Type widestReturnType(final Type t1, final Type t2) { 635 if (t1.isUnknown()) { 636 return t2; 637 } else if (t2.isUnknown()) { 638 return t1; 639 } else if(t1.isBoolean() != t2.isBoolean() || t1.isNumeric() != t2.isNumeric()) { 640 return Type.OBJECT; 641 } 642 return Type.widest(t1, t2); 643 } 644 645 /** 646 * Returns a generic version of the type. Basically, if the type {@link #isObject()}, returns {@link #OBJECT}, 647 * otherwise returns the type unchanged. 648 * @param type the type to generify 649 * @return the generified type 650 */ 651 public static Type generic(final Type type) { 652 return type.isObject() ? Type.OBJECT : type; 653 } 654 655 /** 656 * Returns the narrowest or least common of two types 657 * 658 * @param type0 type one 659 * @param type1 type two 660 * 661 * @return the widest type 662 */ 663 public static Type narrowest(final Type type0, final Type type1) { 664 return type0.narrowerThan(type1) ? type0 : type1; 665 } 666 667 /** 668 * Check whether this type is strictly narrower than another one 669 * @param type type to check against 670 * @return true if this type is strictly narrower 671 */ 672 public boolean narrowerThan(final Type type) { 673 return weight() < type.weight(); 674 } 675 676 /** 677 * Check whether this type is strictly wider than another one 678 * @param type type to check against 679 * @return true if this type is strictly wider 680 */ 681 public boolean widerThan(final Type type) { 682 return weight() > type.weight(); 683 } 684 685 /** 686 * Returns the widest or most common of two types, but no wider than "limit" 687 * 688 * @param type0 type one 689 * @param type1 type two 690 * @param limit limiting type 691 * 692 * @return the widest type, but no wider than limit 693 */ 694 public static Type widest(final Type type0, final Type type1, final Type limit) { 695 final Type type = Type.widest(type0, type1); 696 if (type.weight() > limit.weight()) { 697 return limit; 698 } 699 return type; 700 } 701 702 /** 703 * Returns the widest or most common of two types, but no narrower than "limit" 704 * 705 * @param type0 type one 706 * @param type1 type two 707 * @param limit limiting type 708 * 709 * @return the widest type, but no wider than limit 710 */ 711 public static Type narrowest(final Type type0, final Type type1, final Type limit) { 712 final Type type = type0.weight() < type1.weight() ? type0 : type1; 713 if (type.weight() < limit.weight()) { 714 return limit; 715 } 716 return type; 717 } 718 719 /** 720 * Returns the narrowest of this type and another 721 * 722 * @param other type to compare against 723 * 724 * @return the widest type 725 */ 726 public Type narrowest(final Type other) { 727 return Type.narrowest(this, other); 728 } 729 730 /** 731 * Returns the widest of this type and another 732 * 733 * @param other type to compare against 734 * 735 * @return the widest type 736 */ 737 public Type widest(final Type other) { 738 return Type.widest(this, other); 739 } 740 741 /** 742 * Returns the weight of a type, used for type comparison 743 * between wider and narrower types 744 * 745 * @return the weight 746 */ 747 int weight() { 748 return weight; 749 } 750 751 /** 752 * Return the descriptor of a type, used for e.g. signature 753 * generation 754 * 755 * @return the descriptor 756 */ 757 public String getDescriptor() { 758 return descriptor; 759 } 760 761 /** 762 * Return the descriptor of a type, short version 763 * Used mainly for debugging purposes 764 * 765 * @return the short descriptor 766 */ 767 public String getShortDescriptor() { 768 return descriptor; 769 } 770 771 @Override 772 public String toString() { 773 return name; 774 } 775 776 /** 777 * Return the (possibly cached) Type object for this class 778 * 779 * @param clazz the class to check 780 * 781 * @return the Type representing this class 782 */ 783 public static Type typeFor(final Class<?> clazz) { 784 final Type type = cache.get(clazz); 785 if(type != null) { 786 return type; 787 } 788 assert !clazz.isPrimitive() || clazz == void.class; 789 final Type newType; 790 if (clazz.isArray()) { 791 newType = new ArrayType(clazz); 792 } else { 793 newType = new ObjectType(clazz); 794 } 795 final Type existingType = cache.putIfAbsent(clazz, newType); 796 return existingType == null ? newType : existingType; 797 } 798 799 @Override 800 public int compareTo(final Type o) { 801 return o.weight() - weight(); 802 } 803 804 /** 805 * Common logic for implementing dup for all types 806 * 807 * @param method method visitor 808 * @param depth dup depth 809 * 810 * @return the type at the top of the stack afterwards 811 */ 812 @Override 813 public Type dup(final MethodVisitor method, final int depth) { 814 return Type.dup(method, this, depth); 815 } 816 817 /** 818 * Common logic for implementing swap for all types 819 * 820 * @param method method visitor 821 * @param other the type to swap with 822 * 823 * @return the type at the top of the stack afterwards, i.e. other 824 */ 825 @Override 826 public Type swap(final MethodVisitor method, final Type other) { 827 Type.swap(method, this, other); 828 return other; 829 } 830 831 /** 832 * Common logic for implementing pop for all types 833 * 834 * @param method method visitor 835 * 836 * @return the type that was popped 837 */ 838 @Override 839 public Type pop(final MethodVisitor method) { 840 Type.pop(method, this); 841 return this; 842 } 843 844 @Override 845 public Type loadEmpty(final MethodVisitor method) { 846 assert false : "unsupported operation"; 847 return null; 848 } 849 850 /** 851 * Superclass logic for pop for all types 852 * 853 * @param method method emitter 854 * @param type type to pop 855 */ 856 protected static void pop(final MethodVisitor method, final Type type) { 857 method.visitInsn(type.isCategory2() ? POP2 : POP); 858 } 859 860 private static Type dup(final MethodVisitor method, final Type type, final int depth) { 861 final boolean cat2 = type.isCategory2(); 862 863 switch (depth) { 864 case 0: 865 method.visitInsn(cat2 ? DUP2 : DUP); 866 break; 867 case 1: 868 method.visitInsn(cat2 ? DUP2_X1 : DUP_X1); 869 break; 870 case 2: 871 method.visitInsn(cat2 ? DUP2_X2 : DUP_X2); 872 break; 873 default: 874 return null; //invalid depth 875 } 876 877 return type; 878 } 879 880 private static void swap(final MethodVisitor method, final Type above, final Type below) { 881 if (below.isCategory2()) { 882 if (above.isCategory2()) { 883 method.visitInsn(DUP2_X2); 884 method.visitInsn(POP2); 885 } else { 886 method.visitInsn(DUP_X2); 887 method.visitInsn(POP); 888 } 889 } else { 890 if (above.isCategory2()) { 891 method.visitInsn(DUP2_X1); 892 method.visitInsn(POP2); 893 } else { 894 method.visitInsn(SWAP); 895 } 896 } 897 } 898 899 /** Mappings between java classes and their Type singletons */ 900 private static final ConcurrentMap<Class<?>, Type> cache = new ConcurrentHashMap<>(); 901 902 /** 903 * This is the boolean singleton, used for all boolean types 904 */ 905 public static final Type BOOLEAN = putInCache(new BooleanType()); 906 907 /** 908 * This is an integer type, i.e INT, INT32. 909 */ 910 public static final BitwiseType INT = putInCache(new IntType()); 911 912 /** 913 * This is the number singleton, used for all number types 914 */ 915 public static final NumericType NUMBER = putInCache(new NumberType()); 916 917 /** 918 * This is the long singleton, used for all long types 919 */ 920 public static final BitwiseType LONG = putInCache(new LongType()); 921 922 /** 923 * A string singleton 924 */ 925 public static final Type STRING = putInCache(new ObjectType(String.class)); 926 927 /** 928 * This is the CharSequence singleton used to represent JS strings internally 929 * (either a {@code java.lang.String} or {@code jdk.nashorn.internal.runtime.ConsString}. 930 */ 931 public static final Type CHARSEQUENCE = putInCache(new ObjectType(CharSequence.class)); 932 933 934 /** 935 * This is the object singleton, used for all object types 936 */ 937 public static final Type OBJECT = putInCache(new ObjectType()); 938 939 /** 940 * A undefined singleton 941 */ 942 public static final Type UNDEFINED = putInCache(new ObjectType(Undefined.class)); 943 944 /** 945 * This is the singleton for ScriptObjects 946 */ 947 public static final Type SCRIPT_OBJECT = putInCache(new ObjectType(ScriptObject.class)); 948 949 /** 950 * This is the singleton for integer arrays 951 */ 952 public static final ArrayType INT_ARRAY = new ArrayType(int[].class) { 953 private static final long serialVersionUID = 1L; 954 955 @Override 956 public void astore(final MethodVisitor method) { 957 method.visitInsn(IASTORE); 958 } 959 960 @Override 961 public Type aload(final MethodVisitor method) { 962 method.visitInsn(IALOAD); 963 return INT; 964 } 965 966 @Override 967 public Type newarray(final MethodVisitor method) { 968 method.visitIntInsn(NEWARRAY, T_INT); 969 return this; 970 } 971 972 @Override 973 public Type getElementType() { 974 return INT; 975 } 976 }; 977 978 /** 979 * This is the singleton for long arrays 980 */ 981 public static final ArrayType LONG_ARRAY = new ArrayType(long[].class) { 982 private static final long serialVersionUID = 1L; 983 984 @Override 985 public void astore(final MethodVisitor method) { 986 method.visitInsn(LASTORE); 987 } 988 989 @Override 990 public Type aload(final MethodVisitor method) { 991 method.visitInsn(LALOAD); 992 return LONG; 993 } 994 995 @Override 996 public Type newarray(final MethodVisitor method) { 997 method.visitIntInsn(NEWARRAY, T_LONG); 998 return this; 999 } 1000 1001 @Override 1002 public Type getElementType() { 1003 return LONG; 1004 } 1005 }; 1006 1007 /** 1008 * This is the singleton for numeric arrays 1009 */ 1010 public static final ArrayType NUMBER_ARRAY = new ArrayType(double[].class) { 1011 private static final long serialVersionUID = 1L; 1012 1013 @Override 1014 public void astore(final MethodVisitor method) { 1015 method.visitInsn(DASTORE); 1016 } 1017 1018 @Override 1019 public Type aload(final MethodVisitor method) { 1020 method.visitInsn(DALOAD); 1021 return NUMBER; 1022 } 1023 1024 @Override 1025 public Type newarray(final MethodVisitor method) { 1026 method.visitIntInsn(NEWARRAY, T_DOUBLE); 1027 return this; 1028 } 1029 1030 @Override 1031 public Type getElementType() { 1032 return NUMBER; 1033 } 1034 }; 1035 1036 /** Singleton for method handle arrays used for properties etc. */ 1037 public static final ArrayType METHODHANDLE_ARRAY = putInCache(new ArrayType(MethodHandle[].class)); 1038 1039 /** This is the singleton for string arrays */ 1040 public static final ArrayType STRING_ARRAY = putInCache(new ArrayType(String[].class)); 1041 1042 /** This is the singleton for object arrays */ 1043 public static final ArrayType OBJECT_ARRAY = putInCache(new ArrayType(Object[].class)); 1044 1045 /** This type, always an object type, just a toString override */ 1046 public static final Type THIS = new ObjectType() { 1047 private static final long serialVersionUID = 1L; 1048 1049 @Override 1050 public String toString() { 1051 return "this"; 1052 } 1053 }; 1054 1055 /** Scope type, always an object type, just a toString override */ 1056 public static final Type SCOPE = new ObjectType() { 1057 private static final long serialVersionUID = 1L; 1058 1059 @Override 1060 public String toString() { 1061 return "scope"; 1062 } 1063 }; 1064 1065 private static interface Unknown { 1066 // EMPTY - used as a class that is absolutely not compatible with a type to represent "unknown" 1067 } 1068 1069 private abstract static class ValueLessType extends Type { 1070 private static final long serialVersionUID = 1L; 1071 1072 ValueLessType(final String name) { 1073 super(name, Unknown.class, MIN_WEIGHT, 1); 1074 } 1075 1076 @Override 1077 public Type load(final MethodVisitor method, final int slot) { 1078 throw new UnsupportedOperationException("load " + slot); 1079 } 1080 1081 @Override 1082 public void store(final MethodVisitor method, final int slot) { 1083 throw new UnsupportedOperationException("store " + slot); 1084 } 1085 1086 @Override 1087 public Type ldc(final MethodVisitor method, final Object c) { 1088 throw new UnsupportedOperationException("ldc " + c); 1089 } 1090 1091 @Override 1092 public Type loadUndefined(final MethodVisitor method) { 1093 throw new UnsupportedOperationException("load undefined"); 1094 } 1095 1096 @Override 1097 public Type loadForcedInitializer(final MethodVisitor method) { 1098 throw new UnsupportedOperationException("load forced initializer"); 1099 } 1100 1101 @Override 1102 public Type convert(final MethodVisitor method, final Type to) { 1103 throw new UnsupportedOperationException("convert => " + to); 1104 } 1105 1106 @Override 1107 public void _return(final MethodVisitor method) { 1108 throw new UnsupportedOperationException("return"); 1109 } 1110 1111 @Override 1112 public Type add(final MethodVisitor method, final int programPoint) { 1113 throw new UnsupportedOperationException("add"); 1114 } 1115 } 1116 1117 /** 1118 * This is the unknown type which is used as initial type for type 1119 * inference. It has the minimum type width 1120 */ 1121 public static final Type UNKNOWN = new ValueLessType("<unknown>") { 1122 private static final long serialVersionUID = 1L; 1123 1124 @Override 1125 public String getDescriptor() { 1126 return "<unknown>"; 1127 } 1128 1129 @Override 1130 public char getBytecodeStackType() { 1131 return 'U'; 1132 } 1133 }; 1134 1135 /** 1136 * This is the unknown type which is used as initial type for type 1137 * inference. It has the minimum type width 1138 */ 1139 public static final Type SLOT_2 = new ValueLessType("<slot_2>") { 1140 private static final long serialVersionUID = 1L; 1141 1142 @Override 1143 public String getDescriptor() { 1144 return "<slot_2>"; 1145 } 1146 1147 @Override 1148 public char getBytecodeStackType() { 1149 throw new UnsupportedOperationException("getBytecodeStackType"); 1150 } 1151 }; 1152 1153 private static <T extends Type> T putInCache(final T type) { 1154 cache.put(type.getTypeClass(), type); 1155 return type; 1156 } 1157 1158 protected final Object readResolve() { 1159 return Type.typeFor(clazz); 1160 } 1161} 1162