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