KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > jbet > Type


1 /*
2  * JBET - Java Binary Enhancement Tool
3  * Copyright (c) 2003 Networks Associates Technology, Inc.
4  *
5  * This software was developed under DARPA/SPAWAR contract
6  * N66001-00-C-8602 "SPMA" as part of the
7  * DARPA OASIS research program.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the above copyright
13  * notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in the
16  * documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28  * SUCH DAMAGE.
29  */

30
31 /**
32  * A field or variable type. Simple types have canonical instances to
33  * save memory. pointer types are represented via the JNI name.
34  *
35  * Types form a boolean algebra (lattice) under the isa partial order.
36  * merge() computes the greatest lower bound operator on this lattice.
37  * This is used by DataFlow in the usual way.
38  *
39  *
40  * $Id: Type.java,v 1.13 2003/09/09 17:31:54 areisse Exp $
41  *
42  * @author Larry D'Anna
43  * @version 0.1
44  * @since JDK 1.1.8 */

45
46 package jbet;
47 import java.util.*;
48
49 public final class Type {
50     public static final int VM_INT = 1;
51     public static final int VM_ADDRESS = 2;
52     public static final int VM_FLOAT = 3;
53     public static final int VM_LONG = 4;
54     public static final int VM_DOUBLE = 5;
55     public static final int VM_RETADDR = 6;
56     
57     public char base; // the first letter of the JNI type string
58
public int arraydepth = 0; // the number of brackets in the JNI type string
59
public String JavaDoc cname = null; // the name of the class if base == 'L'
60
public Object JavaDoc extra = null; // extra field for dataflow to use
61

62     Instruction target() { return (Instruction) extra; }
63     Instruction setTarget(Instruction i) {
64     return (Instruction)( extra = i );
65     }
66
67     public static final Type VOID = new Type ('V');
68     public static final Type INT = new Type ('I');
69     public static final Type BOOLEAN = new Type ('Z');
70     public static final Type BYTE = new Type ('B');
71     public static final Type CHAR = new Type ('C');
72     public static final Type SHORT = new Type ('S');
73     public static final Type FLOAT = new Type ('F');
74     public static final Type LONG = new Type ('J');
75     public static final Type DOUBLE = new Type ('D');
76     public static final Type RETADDR = new Type ('R');
77     public static final Type DASH = new Type ('-'); // second half of double or long. used as a placemarker in dataflow
78
public static final Type NULL = new Type ('N');
79     public static final Type ARRAY = new Type ('-', 1); // "superclass" of all arrays.
80
public static final Type SHORTARRAY = newType ("[S");
81     public static final Type CHARARRAY = newType ("[C");
82     public static final Type INTARRAY = newType ("[I");
83     public static final Type BOOLARRAY = newType ("[Z");
84     public static final Type BYTEARRAY = newType ("[B");
85     public static final Type DOUBLEARRAY = newType ("[D");
86     public static final Type FLOATARRAY = newType ("[F");
87     public static final Type LONGARRAY = newType ("[J");
88     public static final Type STRING = newType ("Ljava/lang/String;");
89     public static final Type STRINGBUFFER= newType ("Ljava/lang/StringBuffer;");
90     public static final Type OBJECT = newType ("Ljava/lang/Object;");
91     public static final Type CLASS = newType ("Ljava/lang/Class;");
92     public static final Type THROWABLE = newType ("Ljava/lang/Throwable;");
93     public static final Type CLONEABLE = newType ("Ljava/lang/Cloneable;");
94     public static final Type SERIALIZABLE= newType ("Ljava/io/Serializable;");
95     public static final Type REFARRAY = newType ("[Ljava/lang/Object;");
96     public static final Type CLASSARRAY = newType ("[Ljava/lang/Class;");
97     public static final Type STRINGARRAY = newType ("[Ljava/lang/String;");
98     public static final Type PRINTSTREAM = newType ("Ljava/io/PrintStream;");
99
100     public String JavaDoc toClassRef() {
101     if (arraydepth != 0) return toString();
102     if (equals (NULL))
103         return "java/lang/Object";
104     if (base != 'L') throw new IllegalStateException JavaDoc
105         ("no classref for non-class type " + toString());
106     return cname;
107     }
108
109     // what goes in a java source file to declare this type
110
public String JavaDoc declaration() {
111     String JavaDoc b;
112
113     switch (base) {
114     case 'I': b = "int"; break;
115     case 'J': b = "long"; break;
116     case 'F': b = "float"; break;
117     case 'D': b = "double"; break;
118     case 'L': case 'l': b = Util.srcClassName (cname); break;
119     case 'V': b = "void"; break;
120     case 'Z': b = "boolean"; break;
121     case 'S': b = "short"; break;
122     case 'C': b = "char"; break;
123     case 'B': b = "byte"; break;
124     case 'N': b = "Object"; break;
125     default: throw new IllegalStateException JavaDoc ("can't declare a " + toString());
126     }
127     if (arraydepth == 0)
128         return b;
129     else {
130         StringBuffer JavaDoc out = new StringBuffer JavaDoc (b);
131         for (int i = 0; i < arraydepth; i++)
132         out.append ("[]");
133         return out.toString();
134     }
135     }
136
137     private static Type newType (String JavaDoc s) {
138     try {
139         return new Type (s);
140     } catch (ParseException e) {
141         throw new IllegalStateException JavaDoc ("bad type string: " + s);
142     }
143     }
144
145     private static Type newType (String JavaDoc s, int n) {
146     try {
147         return new Type (s, n);
148     } catch (ParseException e) {
149         throw new IllegalStateException JavaDoc ("bad type string: " + s);
150     }
151     }
152
153     public Type (ClassInfo cr) {
154     this('L', 0, cr.name());
155     }
156
157     public Type (char ch) {
158     base = ch;
159     }
160     
161     public Type (char ch, int d) {
162     this(ch);
163     arraydepth = d;
164     }
165
166     public Type (char ch, int d, String JavaDoc s) {
167     this(ch, d);
168     cname = s;
169     }
170
171     public Type (char ch, int d, String JavaDoc s, Object JavaDoc x) {
172     this(ch, d, s);
173     extra = x;
174     }
175
176     public Type (String JavaDoc s, int d) {
177     base = 'L';
178     cname = s;
179     arraydepth = d;
180     }
181
182     public Type (Type t) {
183     base = t.base;
184     arraydepth = t.arraydepth;
185     cname = t.cname;
186     extra = t.extra;
187     }
188
189     Type () {}
190
191     public Type (String JavaDoc s) throws ParseException {
192     parse(s);
193     }
194
195     public Type (Object JavaDoc o) {
196     String JavaDoc cn = o.getClass().getName().replace ('.','/');
197     
198     if (cn.equals ("java/lang/Integer")) { base = 'I'; arraydepth = 0; }
199     else if (cn.equals ("java/lang/Long")) { base = 'J'; arraydepth = 0; }
200     else if (cn.equals ("java/lang/Float")) { base = 'F'; arraydepth = 0; }
201     else if (cn.equals ("java/lang/Double")) { base = 'D'; arraydepth = 0; }
202     else if (cn.startsWith ("[")) {
203         throw new IllegalStateException JavaDoc ("not implemented yet");
204     } else {
205         cname = cn;
206         base = 'L';
207         arraydepth = 0;
208     }
209     }
210
211     /* Create a Type representing the type created by
212        the newarray(nat) jvm instruction. */

213
214     static Type newarray (int nat)
215     {
216     switch (nat) {
217     case Instruction.NAT_INT:
218         return Type.INTARRAY;
219     case Instruction.NAT_BYTE:
220         return Type.BYTEARRAY;
221     case Instruction.NAT_CHAR:
222         return Type.CHARARRAY;
223     case Instruction.NAT_BOOLEAN:
224         return Type.BOOLARRAY;
225         case Instruction.NAT_SHORT:
226             return Type.SHORTARRAY;
227
228     case Instruction.NAT_FLOAT:
229         return Type.FLOATARRAY;
230     case Instruction.NAT_DOUBLE:
231         return Type.DOUBLEARRAY;
232     case Instruction.NAT_LONG:
233         return Type.LONGARRAY;
234     }
235
236     throw new IllegalStateException JavaDoc ("invalid new array type " + nat);
237     }
238
239     /**
240      * Merges types, i.e. takes the lattice-wedge of them in the "isa"
241      * lattice. The greatest common denominator. The intersection.
242      * This is the basic operation used by dataflow.
243      **/

244     public static Type merge (Type a, Type b) throws ClassFileException {
245
246     if (a==null || b==null)
247         return null;
248
249     if (a.equals (Type.ARRAY) && b.arraydepth > 0)
250         return a;
251     if (b.equals (Type.ARRAY) && a.arraydepth > 0)
252         return b;
253
254     /* for uninitialized objects only merge them if they come from
255            the same new */

256     if (a.base == 'l' || b.base=='l') {
257         if (a.base==b.base && a.target()==b.target() &&
258         a.cname.equals(b.cname) && a.arraydepth==0 &&
259         b.arraydepth==0)
260         return a;
261         else
262         return null;
263     }
264
265     /* for a return address we keep track of where it points and
266          * insist that this can be staticly determined
267          * If they are equal, then return a, except for return-address
268          * types, where we return the canonical Type.RETADDR instead. */

269     if (a.equals(b)) {
270         if (a.equals(RETADDR))
271         if (a.target() == b.target())
272             return a;
273         else
274             return RETADDR;
275         return a;
276     }
277
278     /* nonequal primitives are not mergable */
279     if (a.isPrimitive() || b.isPrimitive())
280         return null;
281
282         /* nulls are assignable to any reference type */
283     if (a.equals(NULL))
284         return b;
285     if (b.equals(NULL))
286         return a;
287
288     if (a.equals(OBJECT) || b.equals(OBJECT))
289         return OBJECT;
290
291     if (a.arraydepth > 0 || b.arraydepth > 0) {
292
293         /* arrays are cloneable and serializeable */
294         if (a.equals(CLONEABLE) || a.equals(SERIALIZABLE))
295         return a;
296         if (b.equals(CLONEABLE) || b.equals(SERIALIZABLE))
297         return b;
298
299         /* If either is an array of
300          * primitives convert pointers to the last level of arrays
301          * to generic pointers to objects */

302
303         if (a.base != 'L')
304         a = new Type('L', a.arraydepth - 1, "java/lang/Object");
305         if (b.base != 'L')
306         b = new Type('L', b.arraydepth - 1, "java/lang/Object");
307
308         if (a.arraydepth == b.arraydepth) {
309         String JavaDoc newt = merge(a.cname, b.cname);
310         return new Type ('L', a.arraydepth, newt);
311         } else {
312         int arraydepth = a.arraydepth < b.arraydepth ? a.arraydepth :
313             b.arraydepth;
314         return new Type ('L', arraydepth, "java/lang/Object");
315         }
316     } else {
317         String JavaDoc newt = merge (a.cname, b.cname);
318         return new Type ('L', 0, newt);
319     }
320     }
321
322     /* Return the closest common superclass (or interface) of A and B. */
323
324     static String JavaDoc merge(String JavaDoc a, String JavaDoc b) throws ClassFileException {
325     /* these two will handle interfaces properly */
326     if ( ClassInfo.isAncestor(a, b) ) return b;
327     if ( ClassInfo.isAncestor(b, a) ) return a;
328     return ClassInfo.allCommonAncestors (a, b);
329     }
330
331     public boolean isa(Type t) throws ClassFileException {
332     Type r = merge(this, t);
333     if (r==null)
334         return false;
335
336     return r.equals(t);
337     }
338
339     public boolean isUninitialized() {
340     return base=='l' && arraydepth==0;
341     }
342
343     Type initialize ()
344     {
345     if (base != 'l' || arraydepth > 0)
346         throw new IllegalStateException JavaDoc ("can't initialize " + toString());
347     return new Type ('L', 0, cname);
348     }
349
350     public Type merge(Type t) throws ClassFileException {
351     return merge(this, t);
352     }
353
354     public static Type class2type(String JavaDoc cname) {
355     if (cname.startsWith("[")) // Array types
356
return new Type (cname);
357     else
358         return new Type (cname, 0);
359     }
360
361     public Type popbracket() throws RuntimeException JavaDoc {
362     if (arraydepth==0)
363         throw new RuntimeException JavaDoc("popbracket called on non-array");
364     Type ret = new Type(this);
365     ret.arraydepth--;
366     return ret;
367     }
368
369     public Type popbrackets()
370     {
371     if (arraydepth==0)
372         throw new RuntimeException JavaDoc("popbrackets called on non-array");
373     Type ret = new Type(this);
374     ret.arraydepth = 0;
375     return ret;
376     }
377
378     /**
379      * Rename this Type according to the substitution hashtable.
380      * @param subs A map of oldname-to-newname
381      */

382     void relocate(Hashtable subs) {
383         /* Primitives need not apply */
384     if (cname == null)
385             return;
386     String JavaDoc newname = (String JavaDoc) subs.get(cname);
387     if (newname==null || cname.equals(newname))
388             return;
389     cname = newname;
390     }
391
392     /**
393      * Create a new type renamed according to the substitution hashtable.
394      * Does not modify "this", unlike "relocate"
395      * @param subs A map of oldname-to-newname
396      */

397     Type relocate_new (Hashtable subs) {
398     Type t = new Type(this);
399     t.relocate(subs);
400     return t;
401     }
402
403
404     public boolean basicly_equalls(Type t) {
405     return base==t.base && arraydepth==t.arraydepth;
406     }
407
408     public boolean isPrimitive() {
409     return arraydepth==0 && base!='L' && base!='N';
410     }
411
412     public boolean isRef() {
413     return base=='N' || arraydepth!=0 || base=='L';
414     }
415     
416
417     public String JavaDoc wrapperClass () {
418     if ( arraydepth!=0 || base=='L' )
419         throw new RuntimeException JavaDoc("wrapperClass called for non " +
420                                        "primitive type");
421     switch (base) {
422     case 'Z':
423         return "java/lang/Boolean";
424     case 'C':
425         return "java/lang/Character";
426     case 'B':
427         return "java/lang/Byte";
428     case 'S':
429         return "java/lang/Short";
430     case 'I':
431         return "java/lang/Integer";
432     case 'J':
433         return "java/lang/Long";
434     case 'F':
435         return "java/lang/Float";
436     case 'D':
437         return "java/lang/Double";
438     }
439     return "unreachable code";
440     }
441
442     public Type refType () {
443     if (arraydepth != 0 || base == 'L')
444         return this;
445     else
446         return new Type ('L', 0, wrapperClass());
447     }
448
449     public String JavaDoc unpackMethod() {
450     if ( arraydepth!=0 || base=='L' )
451         throw new RuntimeException JavaDoc("getvalFunc called for non " +
452                                        "primitive type");
453     switch (base) {
454     case 'Z':
455         return "booleanValue";
456     case 'C':
457         return "charValue";
458     case 'B':
459         return "byteValue";
460     case 'S':
461         return "shortValue";
462     case 'I':
463         return "intValue";
464     case 'J':
465         return "longValue";
466     case 'F':
467         return "floatValue";
468     case 'D':
469         return "doubleValue";
470     }
471     return "unreachable code";
472     }
473
474     /* returns an int representing the vm type of this */
475     public int vmType () {
476     if (arraydepth > 0)
477         return VM_ADDRESS;
478     switch (base)
479         {
480         case 'Z':
481         case 'C':
482         case 'B':
483         case 'I':
484         case 'S':
485         return VM_INT;
486         case 'L':
487         case 'l':
488         case 'N':
489         return VM_ADDRESS;
490         case 'J':
491         return VM_LONG;
492         case 'D':
493         return VM_DOUBLE;
494         case 'F':
495         return VM_FLOAT;
496         case 'R':
497         return VM_RETADDR;
498         }
499
500     return 0;
501     }
502
503     /* returns a Type object corresponding to the vm type for this */
504     public Type compType () {
505     if (arraydepth > 0)
506         return this;
507     switch (base) {
508     case 'Z':
509     case 'C':
510     case 'B':
511     case 'I':
512     case 'S':
513         return INT;
514     case 'L':
515     case 'l':
516         return this;
517     case 'J':
518         return LONG;
519     case 'D':
520         return DOUBLE;
521     case 'F':
522         return FLOAT;
523     case 'R':
524         return RETADDR;
525     }
526     return this;
527     }
528
529     public Type rawType () {
530     if (arraydepth > 0)
531         return OBJECT;
532     switch (base) {
533     case 'Z':
534     case 'C':
535     case 'B':
536     case 'I':
537     case 'S':
538         return INT;
539     case 'L':
540     case 'l':
541     case 'N':
542         return OBJECT;
543     case 'J':
544         return LONG;
545     case 'D':
546         return DOUBLE;
547     case 'F':
548         return FLOAT;
549     case 'R':
550         return RETADDR;
551     default:
552         throw new IllegalStateException JavaDoc ("bad type: " + toString());
553     }
554     }
555
556     /* Stack slots. Does it take 1, 2, or is it the hole for the second slot.
557      * Used mostly by DataFlow. dist field uses this as well.
558      */

559     public int category() {
560     if ( equals(DASH) )
561         return -1;
562     if ( arraydepth==0 && (base=='J' || base=='D'))
563         return 2;
564     else if (base == 'V')
565         return 0;
566     else
567         return 1;
568     }
569   
570     // toString() fills this. "parse" invalidates it.
571
private String JavaDoc stringCache = null;
572
573     int parse (String JavaDoc s) throws ParseException {
574     return parse (s, 0);
575     }
576
577     /**
578      * Initializes the object's "cname" field.
579      * @param s A string containing the new munged type.
580      * @param i The point in the string to start from.
581      * @return Returns the length of the field.
582      */

583     int parse (String JavaDoc s, int i) throws ParseException {
584     stringCache = null;
585     int j = i;
586     while (s.charAt(i) == '[') {
587         arraydepth++;
588         i++;
589     }
590     base = s.charAt(i++);
591     switch (base) {
592     case 'B': case 'C': case 'D': case 'F': case 'I':
593     case 'J': case 'L': case 'S': case 'Z': case 'V':
594         break;
595     default:
596         throw new ParseException ("bad basetype: " + base);
597     }
598         
599     if (base == 'L' || base == 'l') {
600         StringBuffer JavaDoc cn = new StringBuffer JavaDoc();
601         while (s.charAt(i) != ';') {
602         if ( i >= s.length())
603             throw new ParseException ("unexpected end of string: " + s + "/" + cn.toString() +"/" + i + "/" + s.length());
604         cn.append (s.charAt(i++));
605         }
606         i++;
607
608         cname = cn.toString();
609     }
610     return i - j;
611     }
612
613     /**
614      * this should be the same function as "category"
615      *
616      * @see category
617      */

618     public int count() {
619     if (arraydepth == 0 && (base == 'J' || base == 'D'))
620         return 2;
621     else
622         return 1;
623     }
624
625     public String JavaDoc toString() {
626     if (stringCache == null) {
627         StringBuffer JavaDoc out = new StringBuffer JavaDoc();
628         for (int i = 0; i < arraydepth; i++)
629         out.append ('[');
630         out.append(base);
631         if (base == 'L' || base == 'l') {
632         out.append (cname);
633         out.append (';');
634         }
635         stringCache = out.toString();
636     }
637     return stringCache;
638     }
639
640     public boolean equals (Object JavaDoc o) {
641     if (! (o instanceof Type))
642         return false;
643
644     Type t = (Type) o;
645
646     if (base != t.base || arraydepth != t.arraydepth)
647         return false;
648     if (cname != null)
649         return cname.equals(t.cname);
650     else
651         return t.cname == null;
652     }
653
654     /**
655      * Returns the Java CLASSREF string type for a reference or array.
656      */

657     String JavaDoc ref (CPInterface cp) throws RuntimeException JavaDoc {
658     if (isPrimitive())
659         throw new RuntimeException JavaDoc("ref() called on a primitive type");
660     if (arraydepth == 0)
661         return cname;
662     else
663         return toString();
664     }
665
666     public int hashCode() {
667     return 37 * base + 11 * arraydepth +
668         (cname==null ? 0 : cname.hashCode());
669     }
670
671     public ClassInfo getClassInfo () throws ClassFileException
672     {
673     if ((base != 'L' && base != 'l') || arraydepth != 0)
674         throw new IllegalStateException JavaDoc (toString() + " has no class file");
675     return Jbet.loader.getClass (cname);
676     }
677
678     public Class JavaDoc realclass()
679     {
680     if (arraydepth > 0) {
681         int[] n = new int [arraydepth];
682         for (int i = 0; i < arraydepth; i++)
683         n[i] = 1;
684         Object JavaDoc dummy = java.lang.reflect.Array.newInstance (popbrackets().realclass(), n);
685         return dummy.getClass();
686     }
687     switch (base) {
688     case 'I':
689         return Integer.TYPE;
690     case 'J':
691         return Long.TYPE;
692     case 'F':
693         return Float.TYPE;
694     case 'D':
695         return Double.TYPE;
696     case 'L':
697         try {
698         return Class.forName (declaration());
699         } catch (ClassNotFoundException JavaDoc e) {
700         throw new IllegalStateException JavaDoc (e.getMessage());
701         }
702     default:
703         throw new IllegalStateException JavaDoc ("type is not usable");
704     }
705     }
706
707     /* generate a JNI type declaration for use in C source */
708
709     public String JavaDoc jniType ()
710     {
711     if (arraydepth == 1) {
712         switch (base) {
713         case 'B': return "jbyteArray";
714         case 'C': return "jcharArray";
715         case 'S': return "jshortArray";
716         case 'I': return "jintArray";
717         case 'Z': return "jbooleanArray";
718         case 'F': return "jfloatArray";
719         case 'J': return "jlongArray";
720         case 'D': return "jdoubleArray";
721         case 'L': return "jobjectArray";
722         default:
723         throw new IllegalStateException JavaDoc ("bad array basetype " + base);
724         }
725     }
726     else if (arraydepth != 0)
727         return "jobjectArray";
728
729     switch (base) {
730     case 'V': return "void";
731     case 'B': return "jbyte";
732     case 'S': return "jshort";
733     case 'C': return "jchar";
734     case 'Z': return "jboolean";
735     case 'I': return "jint";
736     case 'F': return "jfloat";
737     case 'J': return "jlong";
738     case 'D': return "jdouble";
739     case 'L':
740         if (cname.equals ("java/lang/Class"))
741         return "jclass";
742         else if (cname.equals ("java/lang/String"))
743         return "jstring";
744         else
745         return "jobject";
746     default:
747         throw new IllegalStateException JavaDoc ("bad basetype " + base);
748     }
749     }
750 }
751     
752
753
754
Popular Tags