1 /**********************************************************************/
2 /* Class Descriptor class for J2CPS */
4 /* (c) copyright QUT */
5 /**********************************************************************/
9 import java
.util
.ArrayList
;
10 import java
.util
.HashMap
;
11 import java
.util
.Iterator
;
13 public class ClassDesc
extends TypeDesc
{
15 private static final int MAJOR_VERSION
= 45;
16 private static final int MINOR_VERSION
= 3;
17 private static final char qSepCh
= '/';
18 private static final char jSepCh
= '.';
19 private static final char nSepCh
= '_';
20 private static HashMap
<String
,ClassDesc
> classList
= new HashMap
<String
,ClassDesc
>();
21 private static final String jlString
= "java.lang.String";
22 private static final String jlObject
= "java.lang.Object";
24 private static final int noAtt
= 0; // no record attribute in cp
25 private static final int absR
= 1; // ABSTRACT record in cp
26 private static final int limR
= 2; // LIMITED record in cp
27 private static final int extR
= 3; // EXTENSIBLE record in cp
28 private static final int iFace
= 4; // JAVA interface
29 private static HashMap
<String
,String
> resWords
= CPWords
.InitResWords();
31 public static boolean verbose
= false;
32 public static boolean overloadedNames
= true;
37 int access
, outBaseTypeNum
=0, superNum
=0, numInts
=0, intNums
[];
38 public String qualName
, javaName
, objName
;
39 ClassDesc interfaces
[];
42 boolean isInterface
= false, read
= false, done
= false;
43 public boolean hasNoArgConstructor
= false;
44 public ArrayList imports
= new ArrayList();
45 public ArrayList fieldList
= new ArrayList();
46 public ArrayList methodList
= new ArrayList();
47 HashMap scope
= new HashMap();
50 typeOrd
= TypeDesc
.classT
;
53 public static ClassDesc
GetClassDesc(String name
, PackageDesc pack
) {
54 if (name
.indexOf(jSepCh
) != -1) { name
= name
.replace(jSepCh
,qSepCh
); }
55 ClassDesc aClass
= (ClassDesc
)classList
.get(name
);
57 aClass
= ClassDesc
.MakeNewClassDesc(name
,pack
);
62 public static ClassDesc
MakeNewClassDesc(String name
, PackageDesc pack
) {
63 ClassDesc desc
= new ClassDesc(name
, pack
);
65 classList
.put(desc
.qualName
, desc
);
69 private ClassDesc(String thisName
, PackageDesc pack
) {
70 typeOrd
= TypeDesc
.classT
;
73 packageDesc
= PackageDesc
.getClassPackage(qualName
);
80 public ClassDesc(int inNum
) {
81 inBaseTypeNum
= inNum
;
85 public String
getTypeMnemonic() {
86 if (javaName
.equals(jlString
)) {
88 } else if (javaName
.equals(jlObject
)) {
95 private boolean ReadClassFileDetails(DataInputStream stream
)
100 /* read and check the magic number */
101 if (stream
.readInt() != 0xCAFEBABE) {
102 System
.out
.println("Bad magic number");
105 /* read and check the minor and major version numbers */
106 int minorVersion
= stream
.readUnsignedShort();
107 // /* if (minorVersion > MINOR_VERSION) {
108 // System.out.println("Unsupported Java minor version " +
109 // String.valueOf(minorVersion));
113 int majorVersion
= stream
.readUnsignedShort();
114 // /* if (majorVersion != MAJOR_VERSION) {
115 // System.out.println("Unsupported Java major version " +
116 // String.valueOf(majorVersion));
120 cp
= new ConstantPool(stream
);
121 access
= stream
.readUnsignedShort();
122 // Experimental code to only transform packages that
123 // are reachable from classes that are not private.
124 // Under consideration for next version, controlled
125 // by a command line option.
126 // if (!ConstantPool.isPublic(access) && !ConstantPool.isProtected(access)) {
127 // cp.EmptyConstantPool();
130 // End experimental code
131 ClassRef thisClass
= (ClassRef
) cp
.Get(stream
.readUnsignedShort());
132 String clName
= thisClass
.GetName();
133 if (!qualName
.equals(clName
)) {
134 if (clName
.startsWith(packageDesc
.name
)) {
135 if (verbose
) { System
.out
.println(clName
+ " IS PART OF PACKAGE " +
136 packageDesc
.name
+ " but name is not "
139 if (verbose
) { System
.out
.println(clName
+ " IS NOT PART OF PACKAGE " +
140 packageDesc
.name
+ " qualName = " + qualName
); }
141 packageDesc
= PackageDesc
.getClassPackage(qualName
);
144 classList
.remove(qualName
);
147 classList
.put(qualName
,this);
149 isInterface
= ConstantPool
.isInterface(access
);
150 int superIx
= stream
.readUnsignedShort();
152 tmp
= (ClassRef
) cp
.Get(superIx
);
153 superClass
= tmp
.GetClassDesc();
155 /* get the interfaces implemented by this class */
156 count
= stream
.readUnsignedShort();
157 interfaces
= new ClassDesc
[count
];
158 for (int i
= 0; i
< count
; i
++) {
159 tmp
= (ClassRef
) cp
.Get(stream
.readUnsignedShort());
160 interfaces
[i
] = tmp
.GetClassDesc();
161 AddImport(interfaces
[i
]);
163 /* get the fields for this class */
164 count
= stream
.readUnsignedShort();
165 if (verbose
) {System
.out
.println("There are " + count
+ " fields");}
166 fields
= new FieldInfo
[count
];
167 for (int i
= 0; i
< count
; i
++) {
168 fields
[i
] = new FieldInfo(cp
,stream
,this);
170 /* get the methods for this class */
171 count
= stream
.readUnsignedShort();
172 if (verbose
) { System
.out
.println("There are " + count
+ " methods"); }
173 methods
= new MethodInfo
[count
];
174 for (int i
= 0; i
< count
; i
++) {
175 methods
[i
] = new MethodInfo(cp
,stream
,this);
177 /* ignore the rest of the classfile (ie. the attributes) */
178 if (verbose
) { System
.out
.println("Finished reading class file"); }
179 if (verbose
) { PrintClassFile(); Diag(); }
180 cp
.EmptyConstantPool();
185 public void TryImport(TypeDesc type
){
186 if (type
instanceof ClassDesc
) {
187 this.AddImport((ClassDesc
)type
);
189 else if (type
instanceof ArrayDesc
) {
190 this.TryImport(((ArrayDesc
)type
).elemType
);
192 else if (type
instanceof PtrDesc
) {
193 ((PtrDesc
)type
).AddImport(this);
198 public void AddImport(ClassDesc aClass
) {
199 if ((aClass
!= this) && (aClass
.packageDesc
!= this.packageDesc
) &&
200 (!imports
.contains(aClass
.packageDesc
))) {
201 imports
.add(aClass
.packageDesc
);
205 public boolean ReadClassFile(File cFile
) throws IOException
{
207 DataInputStream in
= new DataInputStream(new FileInputStream(cFile
));
208 if (verbose
) { System
.out
.println("Reading Class File <"+qualName
+">"); }
209 result
= ReadClassFileDetails(in
);
210 // close the file or run out of file handles!
215 public void PrintClassFile() {
217 System
.out
.println("ClassFile for " + qualName
);
218 cp
.PrintConstantPool();
219 System
.out
.print("THIS CLASS = ");
220 System
.out
.print(ConstantPool
.GetAccessString(access
));
221 System
.out
.println(qualName
);
222 if (superClass
!= null) {
223 System
.out
.println("SUPERCLASS = " + superClass
.qualName
);
225 System
.out
.println("INTERFACES IMPLEMENTED");
226 for (i
= 0; i
< interfaces
.length
; i
++) {
227 System
.out
.println(" " + interfaces
[i
].qualName
);
229 System
.out
.println("FIELDS");
230 for (i
=0; i
< fields
.length
; i
++) {
231 System
.out
.println(" " + fields
[i
].toString() + ";");
233 System
.out
.println("METHODS");
234 for (i
=0; i
< methods
.length
; i
++) {
235 System
.out
.println(" " + methods
[i
].toString());
237 System
.out
.println();
241 System
.out
.println("CLASSDESC");
242 System
.out
.println("name = " + name
);
243 System
.out
.println("javaName = " + javaName
);
244 System
.out
.println("qualName = " + qualName
);
245 System
.out
.println();
248 private static void AddField(FieldInfo f
,HashMap scope
) throws IOException
{
250 String origName
= f
.name
;
251 while (scope
.containsKey(f
.name
)) {
252 f
.name
= origName
+ String
.valueOf(fNo
);
258 private static int HashSignature(MethodInfo meth
) {
259 int tot
=0, sum
=0, parNum
= 1, end
= meth
.signature
.indexOf(')');
260 boolean inPar
= false;
261 for (int i
=1; i
< end
; i
++) {
262 char c
= meth
.signature
.charAt(i
);
264 if (sum
< 0) { sum
++; }
265 sum
+= parNum
* (int)c
;
267 if (c
== 'L') { inPar
= true; }
268 else if (c
!= '[') { parNum
++; tot
+= sum
; }
269 } else if (c
== ';') { inPar
= false; parNum
++; tot
+= sum
; }
271 int hash
= tot
% 4099;
272 if (hash
< 0) { hash
= -hash
; }
276 private static void MakeMethodName(MethodInfo meth
) {
277 boolean needHash
= false;
278 if (meth
.isInitProc
) { meth
.userName
= "Init";
280 meth
.userName
= meth
.name
;
282 if (overloadedNames
) { return; }
283 if (meth
.parTypes
.length
> 0) { meth
.userName
+= "_"; }
284 for (int i
=0; i
< meth
.parTypes
.length
; i
++) {
285 String next
= meth
.parTypes
[i
].getTypeMnemonic();
286 if (next
.endsWith("o")) { needHash
= true; }
287 meth
.userName
+= next
;
290 int hash
= HashSignature(meth
);
291 meth
.userName
+= ("_" + String
.valueOf(hash
));
295 private static void AddMethod(MethodInfo meth
, HashMap
<String
,MethodInfo
> scope
)
298 if (meth
.userName
== null) { MakeMethodName(meth
); }
299 String origName
= meth
.userName
;
300 while (scope
.containsKey(meth
.userName
)) {
301 meth
.userName
= origName
+ String
.valueOf(methNo
);
304 scope
.put(meth
.userName
,meth
);
307 public void MakeJavaName() {
308 javaName
= qualName
.replace(qSepCh
,jSepCh
);
309 objName
= javaName
.substring(javaName
.lastIndexOf(jSepCh
)+1);
310 name
= javaName
.replace(jSepCh
,nSepCh
);
313 private void AddInterfaceImports(ClassDesc aClass
) {
314 // if (interfaces.length > 0) {
315 if (interfaces
!= null && interfaces
.length
> 0) {
316 for (int i
=0; i
< interfaces
.length
; i
++) {
317 aClass
.AddImport(interfaces
[i
]);
318 interfaces
[i
].AddInterfaceImports(aClass
);
323 public void GetSuperImports() {
324 if (done
) { return; }
325 if (verbose
) { System
.out
.println("GetSuperImports of " + javaName
); }
326 if (isInterface
) { AddInterfaceImports(this); }
327 if (superClass
!= null) {
328 if (!superClass
.done
) { superClass
.GetSuperImports(); }
330 if (methods
!= null) { // guard added
331 for (int i
=0; i
< methods
.length
; i
++) {
332 MethodInfo mth
= methods
[i
];
334 if (mth
.isExported() && !mth
.deprecated
) {
335 if ((!mth
.isInitProc
) && (!mth
.isStatic())) {
336 MethodInfo meth
= GetOverridden(mth
,mth
.owner
);
337 if (meth
!= null) { mth
.overridding
= true; }
345 public void GetSuperFields(HashMap jScope
) throws IOException
{
346 if (done
) { return; }
347 if (verbose
) { System
.out
.println("GetSuperFields of " + javaName
); }
348 if (isInterface
) { AddInterfaceImports(this); }
349 if (superClass
!= null) {
350 if (!superClass
.done
) { superClass
.GetSuperFields(jScope
); }
351 Iterator
<String
> enum1
= superClass
.scope
.keySet().iterator();
352 while (enum1
.hasNext()) {
353 String methName
= (String
)enum1
.next();
354 scope
.put(methName
, superClass
.scope
.get(methName
));
357 for (int i
=0; i
< fields
.length
; i
++) {
358 FieldInfo f
= fields
[i
];
359 if (f
.isExported()) {
363 HashMap
<String
,MethodInfo
> iScope
= new HashMap
<String
,MethodInfo
>();
364 for (int i
=0; i
< methods
.length
; i
++) {
365 MethodInfo mth
= methods
[i
];
367 if (mth
.isExported() && !mth
.deprecated
) {
368 if (mth
.isInitProc
) {
369 AddMethod(mth
,iScope
);
370 } else if (mth
.isStatic()) {
371 AddMethod(mth
,scope
);
373 //if (scope.containsKey(mth.name)) {
374 if (scope
.containsKey(mth
.userName
)) {
375 MethodInfo meth
= GetOverridden(mth
,mth
.owner
);
377 mth
.overridding
= true;
378 mth
.userName
= meth
.userName
;
379 scope
.remove(mth
.userName
);
380 scope
.put(mth
.userName
,mth
);
382 AddMethod(mth
,scope
);
385 AddMethod(mth
,scope
);
393 private static MethodInfo
GetOverridden(MethodInfo meth
,ClassDesc thisClass
) {
394 ClassDesc aClass
= thisClass
;
395 while (aClass
.superClass
!= null) {
396 aClass
= aClass
.superClass
;
397 if (aClass
.methods
!= null) { // new guard
398 for (int i
=0; i
< aClass
.methods
.length
; i
++) {
399 if (aClass
.methods
[i
].name
.equals(meth
.name
)) {
400 if ((aClass
.methods
[i
].signature
!= null)&&(meth
.signature
!= null)){
401 if (aClass
.methods
[i
].signature
.equals(meth
.signature
)) {
402 return aClass
.methods
[i
];
404 } else if (aClass
.methods
[i
].parTypes
.length
== meth
.parTypes
.length
){
406 for (int j
=0; (j
< aClass
.methods
[i
].parTypes
.length
)& ok
; j
++){
407 ok
= aClass
.methods
[i
].parTypes
[j
] == meth
.parTypes
[j
];
409 if (ok
) { return aClass
.methods
[i
]; }
418 public void CheckAccess() {
419 if (ConstantPool
.isAbstract(access
)) {
420 System
.out
.println(" is abstract ");
421 } else if (ConstantPool
.isFinal(access
)) {
422 System
.out
.println(" is final ");
424 System
.out
.println(" is default");
428 public void setRecAtt(int recAtt
) {
429 if (recAtt
>= 8) { recAtt
-= 8; } else { hasNoArgConstructor
= true; }
430 if (recAtt
== absR
) {
431 if (!ConstantPool
.isAbstract(access
)) {
432 access
= access
+ ConstantPool
.ACC_ABSTRACT
;
434 } else if (recAtt
== noAtt
) {
435 if (!ConstantPool
.isFinal(access
)) {
436 access
= access
+ ConstantPool
.ACC_FINAL
;
442 public void writeType(DataOutputStream out
,PackageDesc thisPack
)
444 if (objName
== null) { this.MakeJavaName(); }
445 if (this.packageDesc
!= thisPack
) {
446 out
.writeByte(SymbolFile
.fromS
);
448 // if (this.packageDesc.impNum < 0) {
449 // System.out.println("impNum is " + this.packageDesc.impNum);
450 // System.out.println("packageDesc " + this.packageDesc.javaName);
451 // System.out.println("objName " + objName);
452 // this.packageDesc.impNum = 0;
455 SymbolFile
.writeOrd(out
,this.packageDesc
.impNum
);
456 SymbolFile
.writeName(out
,access
,objName
);
457 } else if (!ConstantPool
.isPublic(access
)) {
458 out
.writeByte(SymbolFile
.fromS
);
459 SymbolFile
.writeOrd(out
,0);
460 SymbolFile
.writeName(out
,access
,objName
);
462 if (!writeDetails
) { return; }
463 out
.writeByte(SymbolFile
.ptrSy
);
464 SymbolFile
.writeOrd(out
,outBaseTypeNum
);
465 out
.writeByte(SymbolFile
.tDefS
);
466 SymbolFile
.writeOrd(out
,outBaseTypeNum
);
467 out
.writeByte(SymbolFile
.recSy
);
469 if (!hasNoArgConstructor
) { recAtt
= 8; }
470 if (ConstantPool
.isFinal(access
)) {
471 out
.writeByte(noAtt
+recAtt
); }
472 else if (isInterface
) {
473 out
.writeByte(iFace
+recAtt
); }
474 else if (ConstantPool
.isAbstract(access
)) {
475 out
.writeByte(absR
+recAtt
); }
477 out
.writeByte(extR
+recAtt
); }
478 if (isInterface
) { out
.writeByte(SymbolFile
.truSy
); }
479 else { out
.writeByte(SymbolFile
.falSy
); }
480 if (superClass
!= null) {
481 out
.writeByte(SymbolFile
.basSy
);
482 SymbolFile
.writeTypeOrd(out
,superClass
);
484 //if (interfaces.length > 0) {
485 if (interfaces
!= null && interfaces
.length
> 0) {
486 out
.writeByte(SymbolFile
.iFcSy
);
487 for (int i
= 0; i
< interfaces
.length
; i
++) {
488 out
.writeByte(SymbolFile
.basSy
);
489 SymbolFile
.writeTypeOrd(out
,interfaces
[i
]);
492 if (fields
!= null && fields
.length
> 0) {
493 for (int i
=0; i
< fields
.length
; i
++) {
494 if (fields
[i
].isExported() && !fields
[i
].isStatic()) {
495 SymbolFile
.writeName(out
,fields
[i
].accessFlags
,fields
[i
].name
);
496 SymbolFile
.writeTypeOrd(out
,fields
[i
].type
);
500 if (methods
!= null && methods
.length
> 0) {
501 for (int i
=0; i
< methods
.length
; i
++) {
502 if (methods
[i
].isExported() && !methods
[i
].deprecated
&&
503 !methods
[i
].isStatic() && !methods
[i
].isInitProc
&&
504 !methods
[i
].isCLInitProc
) {
505 out
.writeByte(SymbolFile
.mthSy
);
506 // --------------------
507 // if (methods[i].userName == null) {
508 // System.out.println("packageDesc " + this.packageDesc.javaName);
509 // System.out.println("objName " + objName);
510 // for (int j=0; j < methods.length; j++) {
511 // System.out.println("Method " + j +
512 // (methods[i].userName == null ? " null" : methods[j].userName));
515 // --------------------
516 SymbolFile
.writeName(out
,methods
[i
].accessFlags
,methods
[i
].userName
);
518 if (!methods
[i
].overridding
) { attr
= 1; }
519 if (methods
[i
].isAbstract()) { attr
+= 2; }
520 else if (!methods
[i
].isFinal()){ attr
+= 6; }
522 out
.writeByte(0); /* all java receivers are value mode */
523 SymbolFile
.writeOrd(out
,outTypeNum
);
524 SymbolFile
.writeString(out
,methods
[i
].name
);
525 SymbolFile
.WriteFormalType(methods
[i
],out
);
529 if (fields
!= null && fields
.length
> 0) {
530 for (int i
=0; i
< fields
.length
; i
++) {
531 if (fields
[i
].isConstant()) {
532 out
.writeByte(SymbolFile
.conSy
);
533 SymbolFile
.writeName(out
,fields
[i
].accessFlags
,fields
[i
].name
);
534 SymbolFile
.writeLiteral(out
,fields
[i
].GetConstVal());
535 } else if (fields
[i
].isExported() && fields
[i
].isStatic()) {
536 out
.writeByte(SymbolFile
.varSy
);
537 SymbolFile
.writeName(out
,fields
[i
].accessFlags
,fields
[i
].name
);
538 SymbolFile
.writeTypeOrd(out
,fields
[i
].type
);
542 if (methods
!= null && methods
.length
> 0) {
543 for (int i
=0; i
< methods
.length
; i
++) {
544 if (methods
[i
].isExported() && !methods
[i
].deprecated
&&
545 methods
[i
].isStatic() && !methods
[i
].isCLInitProc
) {
546 out
.writeByte(SymbolFile
.prcSy
);
547 SymbolFile
.writeName(out
,methods
[i
].accessFlags
,methods
[i
].userName
);
548 SymbolFile
.writeString(out
,methods
[i
].name
);
549 if (methods
[i
].isInitProc
) { out
.writeByte(SymbolFile
.truSy
); }
550 SymbolFile
.WriteFormalType(methods
[i
],out
);
554 out
.writeByte(SymbolFile
.endRc
);