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