ClassDesc.java 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. /**********************************************************************/
  2. /* Class Descriptor class for J2CPS */
  3. /* */
  4. /* (c) copyright QUT */
  5. /**********************************************************************/
  6. package J2CPS;
  7. import java.io.*;
  8. import java.util.ArrayList;
  9. import java.util.HashMap;
  10. import java.util.Iterator;
  11. public class ClassDesc extends TypeDesc {
  12. private static final int MAJOR_VERSION = 45;
  13. private static final int MINOR_VERSION = 3;
  14. private static final char qSepCh = '/';
  15. private static final char jSepCh = '.';
  16. private static final char nSepCh = '_';
  17. private static HashMap<String,ClassDesc> classList = new HashMap<String,ClassDesc>();
  18. private static final String jlString = "java.lang.String";
  19. private static final String jlObject = "java.lang.Object";
  20. private static final int noAtt = 0; // no record attribute in cp
  21. private static final int absR = 1; // ABSTRACT record in cp
  22. private static final int limR = 2; // LIMITED record in cp
  23. private static final int extR = 3; // EXTENSIBLE record in cp
  24. private static final int iFace = 4; // JAVA interface
  25. private static HashMap<String,String> resWords = CPWords.InitResWords();
  26. public static boolean verbose = false;
  27. public static boolean overloadedNames = true;
  28. ConstantPool cp;
  29. ClassDesc superClass;
  30. int access, outBaseTypeNum=0, superNum=0, numInts=0, intNums[];
  31. public String qualName, javaName, objName;
  32. ClassDesc interfaces[];
  33. FieldInfo fields[];
  34. MethodInfo methods[];
  35. boolean isInterface = false, read = false, done = false;
  36. public boolean hasNoArgConstructor = false;
  37. public ArrayList imports = new ArrayList();
  38. public ArrayList fieldList = new ArrayList();
  39. public ArrayList methodList = new ArrayList();
  40. HashMap scope = new HashMap();
  41. public ClassDesc() {
  42. typeOrd = TypeDesc.classT;
  43. }
  44. public static ClassDesc GetClassDesc(String name, PackageDesc pack) {
  45. if (name.indexOf(jSepCh) != -1) { name = name.replace(jSepCh,qSepCh); }
  46. ClassDesc aClass = (ClassDesc)classList.get(name);
  47. if (aClass == null)
  48. aClass = ClassDesc.MakeNewClassDesc(name,pack);
  49. return aClass;
  50. }
  51. public static ClassDesc MakeNewClassDesc(String name, PackageDesc pack) {
  52. ClassDesc desc = new ClassDesc(name, pack);
  53. desc.MakeJavaName();
  54. classList.put(desc.qualName, desc);
  55. return desc;
  56. }
  57. private ClassDesc(String thisName, PackageDesc pack) {
  58. typeOrd = TypeDesc.classT;
  59. qualName = thisName;
  60. if (pack == null)
  61. packageDesc = PackageDesc.getClassPackage(qualName);
  62. else
  63. packageDesc = pack;
  64. }
  65. public ClassDesc(int inNum) {
  66. inBaseTypeNum = inNum;
  67. }
  68. @Override
  69. public String getTypeMnemonic() {
  70. if (javaName.equals(jlString)) {
  71. return "S";
  72. } else if (javaName.equals(jlObject)) {
  73. return "O";
  74. } else {
  75. return "o";
  76. }
  77. }
  78. private boolean ReadClassFileDetails(DataInputStream stream)
  79. throws IOException {
  80. read = true;
  81. int count;
  82. ClassRef tmp;
  83. /* read and check the magic number */
  84. if (stream.readInt() != 0xCAFEBABE) {
  85. System.out.println("Bad magic number");
  86. System.exit(0);
  87. }
  88. /* read and check the minor and major version numbers */
  89. int minorVersion = stream.readUnsignedShort();
  90. // /* if (minorVersion > MINOR_VERSION) {
  91. // System.out.println("Unsupported Java minor version " +
  92. // String.valueOf(minorVersion));
  93. // System.exit(0);
  94. // }
  95. //*/
  96. int majorVersion = stream.readUnsignedShort();
  97. // /* if (majorVersion != MAJOR_VERSION) {
  98. // System.out.println("Unsupported Java major version " +
  99. // String.valueOf(majorVersion));
  100. // System.exit(0);
  101. // }
  102. //*/
  103. cp = new ConstantPool(stream);
  104. access = stream.readUnsignedShort();
  105. ClassRef thisClass = (ClassRef) cp.Get(stream.readUnsignedShort());
  106. String clName = thisClass.GetName();
  107. if (!qualName.equals(clName)) {
  108. if (clName.startsWith(packageDesc.name)) {
  109. if (verbose) { System.out.println(clName + " IS PART OF PACKAGE " +
  110. packageDesc.name + " but name is not "
  111. + qualName); }
  112. } else {
  113. if (verbose) { System.out.println(clName + " IS NOT PART OF PACKAGE " +
  114. packageDesc.name + " qualName = " + qualName); }
  115. packageDesc = PackageDesc.getClassPackage(qualName);
  116. return false;
  117. }
  118. classList.remove(qualName);
  119. qualName = clName;
  120. this.MakeJavaName();
  121. classList.put(qualName,this);
  122. }
  123. isInterface = ConstantPool.isInterface(access);
  124. int superIx = stream.readUnsignedShort();
  125. if (superIx > 0) {
  126. tmp = (ClassRef) cp.Get(superIx);
  127. superClass = tmp.GetClassDesc();
  128. }
  129. /* get the interfaces implemented by this class */
  130. count = stream.readUnsignedShort();
  131. interfaces = new ClassDesc[count];
  132. for (int i = 0; i < count; i++) {
  133. tmp = (ClassRef) cp.Get(stream.readUnsignedShort());
  134. interfaces[i] = tmp.GetClassDesc();
  135. AddImport(interfaces[i]);
  136. }
  137. /* get the fields for this class */
  138. count = stream.readUnsignedShort();
  139. if (verbose) {System.out.println("There are " + count + " fields");}
  140. fields = new FieldInfo[count];
  141. for (int i = 0; i < count; i++) {
  142. fields[i] = new FieldInfo(cp,stream,this);
  143. }
  144. /* get the methods for this class */
  145. count = stream.readUnsignedShort();
  146. if (verbose) { System.out.println("There are " + count + " methods"); }
  147. methods = new MethodInfo[count];
  148. for (int i = 0; i < count; i++) {
  149. methods[i] = new MethodInfo(cp,stream,this);
  150. }
  151. /* ignore the rest of the classfile (ie. the attributes) */
  152. if (verbose) { System.out.println("Finished reading class file"); }
  153. if (verbose) { PrintClassFile(); Diag(); }
  154. cp.EmptyConstantPool();
  155. cp = null;
  156. return true;
  157. }
  158. public void TryImport(TypeDesc type){
  159. if (type instanceof ClassDesc)
  160. this.AddImport((ClassDesc)type);
  161. else if (type instanceof ArrayDesc)
  162. this.TryImport(((ArrayDesc)type).elemType);
  163. else if (type instanceof PtrDesc)
  164. ((PtrDesc)type).AddImport(this);
  165. }
  166. public void AddImport(ClassDesc aClass) {
  167. if ((aClass != this) && (aClass.packageDesc != this.packageDesc) &&
  168. (!imports.contains(aClass.packageDesc))) {
  169. imports.add(aClass.packageDesc);
  170. }
  171. }
  172. public boolean ReadClassFile(File cFile) throws IOException {
  173. boolean result;
  174. DataInputStream in = new DataInputStream(new FileInputStream(cFile));
  175. if (verbose) { System.out.println("Reading Class File <"+qualName+">"); }
  176. result = ReadClassFileDetails(in);
  177. // close the file or run out of file handles!
  178. in.close();
  179. return result;
  180. }
  181. public void PrintClassFile() {
  182. int i;
  183. System.out.println("ClassFile for " + qualName);
  184. cp.PrintConstantPool();
  185. System.out.print("THIS CLASS = ");
  186. System.out.print(ConstantPool.GetAccessString(access));
  187. System.out.println(qualName);
  188. if (superClass != null) {
  189. System.out.println("SUPERCLASS = " + superClass.qualName);
  190. }
  191. System.out.println("INTERFACES IMPLEMENTED");
  192. for (i = 0; i < interfaces.length; i++) {
  193. System.out.println(" " + interfaces[i].qualName);
  194. }
  195. System.out.println("FIELDS");
  196. for (i=0; i < fields.length; i++) {
  197. System.out.println(" " + fields[i].toString() + ";");
  198. }
  199. System.out.println("METHODS");
  200. for (i=0; i < methods.length; i++) {
  201. System.out.println(" " + methods[i].toString());
  202. }
  203. System.out.println();
  204. }
  205. public void Diag() {
  206. System.out.println("CLASSDESC");
  207. System.out.println("name = " + name);
  208. System.out.println("javaName = " + javaName);
  209. System.out.println("qualName = " + qualName);
  210. System.out.println();
  211. }
  212. private static void AddField(FieldInfo f,HashMap scope) throws IOException {
  213. int fNo = 1;
  214. String origName = f.name;
  215. while (scope.containsKey(f.name)) {
  216. f.name = origName + String.valueOf(fNo);
  217. fNo++;
  218. }
  219. scope.put(f.name,f);
  220. }
  221. private static int HashSignature(MethodInfo meth) {
  222. int tot=0, sum=0, parNum = 1, end = meth.signature.indexOf(')');
  223. boolean inPar = false;
  224. for (int i=1; i < end; i++) {
  225. char c = meth.signature.charAt(i);
  226. sum += sum;
  227. if (sum < 0) { sum++; }
  228. sum += parNum * (int)c;
  229. if (!inPar) {
  230. if (c == 'L') { inPar = true; }
  231. else if (c != '[') { parNum++; tot += sum; }
  232. } else if (c == ';') { inPar = false; parNum++; tot += sum; }
  233. }
  234. int hash = tot % 4099;
  235. if (hash < 0) { hash = -hash; }
  236. return hash;
  237. }
  238. private static void MakeMethodName(MethodInfo meth) {
  239. boolean needHash = false;
  240. if (meth.isInitProc) { meth.userName = "Init";
  241. } else {
  242. meth.userName = meth.name;
  243. }
  244. if (overloadedNames) { return; }
  245. if (meth.parTypes.length > 0) { meth.userName += "_"; }
  246. for (int i=0; i < meth.parTypes.length; i++) {
  247. String next = meth.parTypes[i].getTypeMnemonic();
  248. if (next.endsWith("o")) { needHash = true; }
  249. meth.userName += next;
  250. }
  251. if (needHash) {
  252. int hash = HashSignature(meth);
  253. meth.userName += ("_" + String.valueOf(hash));
  254. }
  255. }
  256. private static void AddMethod(MethodInfo meth, HashMap<String,MethodInfo> scope)
  257. throws IOException {
  258. int methNo = 1;
  259. if (meth.userName == null) { MakeMethodName(meth); }
  260. String origName = meth.userName;
  261. while (scope.containsKey(meth.userName)) {
  262. meth.userName = origName + String.valueOf(methNo);
  263. methNo++;
  264. }
  265. scope.put(meth.userName,meth);
  266. }
  267. public void MakeJavaName() {
  268. javaName = qualName.replace(qSepCh,jSepCh);
  269. objName = javaName.substring(javaName.lastIndexOf(jSepCh)+1);
  270. name = javaName.replace(jSepCh,nSepCh);
  271. }
  272. private void AddInterfaceImports(ClassDesc aClass) {
  273. // if (interfaces.length > 0) {
  274. if (interfaces != null && interfaces.length > 0) {
  275. for (int i=0; i < interfaces.length; i++) {
  276. aClass.AddImport(interfaces[i]);
  277. interfaces[i].AddInterfaceImports(aClass);
  278. }
  279. }
  280. }
  281. public void GetSuperImports() {
  282. if (done) { return; }
  283. if (verbose) { System.out.println("GetSuperImports of " + javaName); }
  284. if (isInterface) { AddInterfaceImports(this); }
  285. if (superClass != null) {
  286. if (!superClass.done) { superClass.GetSuperImports(); }
  287. }
  288. if (methods != null) { // guard added
  289. for (int i=0; i < methods.length; i++) {
  290. MethodInfo mth = methods[i];
  291. MakeMethodName(mth);
  292. if (mth.isExported() && !mth.deprecated) {
  293. if ((!mth.isInitProc) && (!mth.isStatic())) {
  294. MethodInfo meth = GetOverridden(mth,mth.owner);
  295. if (meth != null) { mth.overridding = true; }
  296. }
  297. }
  298. }
  299. }
  300. done = true;
  301. }
  302. public void GetSuperFields(HashMap jScope) throws IOException {
  303. if (done) { return; }
  304. if (verbose) { System.out.println("GetSuperFields of " + javaName); }
  305. if (isInterface) { AddInterfaceImports(this); }
  306. if (superClass != null) {
  307. if (!superClass.done) { superClass.GetSuperFields(jScope); }
  308. Iterator<String> enum1 = superClass.scope.keySet().iterator();
  309. while (enum1.hasNext()) {
  310. String methName = (String)enum1.next();
  311. scope.put(methName, superClass.scope.get(methName));
  312. }
  313. }
  314. for (int i=0; i < fields.length; i++) {
  315. FieldInfo f = fields[i];
  316. if (f.isExported()) {
  317. AddField(f,scope);
  318. }
  319. }
  320. HashMap<String,MethodInfo> iScope = new HashMap<String,MethodInfo>();
  321. for (int i=0; i < methods.length; i++) {
  322. MethodInfo mth = methods[i];
  323. MakeMethodName(mth);
  324. if (mth.isExported() && !mth.deprecated) {
  325. if (mth.isInitProc) {
  326. AddMethod(mth,iScope);
  327. } else if (mth.isStatic()) {
  328. AddMethod(mth,scope);
  329. } else {
  330. //if (scope.containsKey(mth.name)) {
  331. if (scope.containsKey(mth.userName)) {
  332. MethodInfo meth = GetOverridden(mth,mth.owner);
  333. if (meth != null) {
  334. mth.overridding = true;
  335. mth.userName = meth.userName;
  336. scope.remove(mth.userName);
  337. scope.put(mth.userName,mth);
  338. } else {
  339. AddMethod(mth,scope);
  340. }
  341. } else {
  342. AddMethod(mth,scope);
  343. }
  344. }
  345. }
  346. }
  347. done = true;
  348. }
  349. private static MethodInfo GetOverridden(MethodInfo meth,ClassDesc thisClass) {
  350. ClassDesc aClass = thisClass;
  351. while (aClass.superClass != null) {
  352. aClass = aClass.superClass;
  353. if (aClass.methods != null) { // new guard
  354. for (int i=0; i < aClass.methods.length; i++) {
  355. if (aClass.methods[i].name.equals(meth.name)) {
  356. if ((aClass.methods[i].signature != null)&&(meth.signature != null)){
  357. if (aClass.methods[i].signature.equals(meth.signature)) {
  358. return aClass.methods[i];
  359. }
  360. } else if (aClass.methods[i].parTypes.length == meth.parTypes.length){
  361. boolean ok = true;
  362. for (int j=0; (j < aClass.methods[i].parTypes.length)& ok; j++){
  363. ok = aClass.methods[i].parTypes[j] == meth.parTypes[j];
  364. }
  365. if (ok) { return aClass.methods[i]; }
  366. }
  367. }
  368. }
  369. }
  370. }
  371. return null;
  372. }
  373. public void CheckAccess() {
  374. if (ConstantPool.isAbstract(access)) {
  375. System.out.println(" is abstract ");
  376. } else if (ConstantPool.isFinal(access)) {
  377. System.out.println(" is final ");
  378. } else {
  379. System.out.println(" is default");
  380. }
  381. }
  382. public void setRecAtt(int recAtt) {
  383. if (recAtt >= 8) { recAtt -= 8; } else { hasNoArgConstructor = true; }
  384. if (recAtt == absR) {
  385. if (!ConstantPool.isAbstract(access)) {
  386. access = access + ConstantPool.ACC_ABSTRACT;
  387. }
  388. } else if (recAtt == noAtt) {
  389. if (!ConstantPool.isFinal(access)) {
  390. access = access + ConstantPool.ACC_FINAL;
  391. }
  392. }
  393. }
  394. @Override
  395. public void writeType(DataOutputStream out,PackageDesc thisPack)
  396. throws IOException {
  397. if (objName == null) { this.MakeJavaName(); }
  398. if (this.packageDesc != thisPack) {
  399. out.writeByte(SymbolFile.fromS);
  400. // ------------
  401. if (this.packageDesc.impNum < 0) {
  402. System.out.println("impNum is " + this.packageDesc.impNum);
  403. System.out.println("packageDesc " + this.packageDesc.javaName);
  404. System.out.println("objName " + objName);
  405. this.packageDesc.impNum = 0;
  406. }
  407. // ------------
  408. SymbolFile.writeOrd(out,this.packageDesc.impNum);
  409. SymbolFile.writeName(out,access,objName);
  410. } else if (!ConstantPool.isPublic(access)) {
  411. out.writeByte(SymbolFile.fromS);
  412. SymbolFile.writeOrd(out,0);
  413. SymbolFile.writeName(out,access,objName);
  414. }
  415. if (!writeDetails) { return; }
  416. out.writeByte(SymbolFile.ptrSy);
  417. SymbolFile.writeOrd(out,outBaseTypeNum);
  418. out.writeByte(SymbolFile.tDefS);
  419. SymbolFile.writeOrd(out,outBaseTypeNum);
  420. out.writeByte(SymbolFile.recSy);
  421. int recAtt = 0;
  422. if (!hasNoArgConstructor) { recAtt = 8; }
  423. if (ConstantPool.isFinal(access)) {
  424. out.writeByte(noAtt+recAtt); }
  425. else if (isInterface) {
  426. out.writeByte(iFace+recAtt); }
  427. else if (ConstantPool.isAbstract(access)) {
  428. out.writeByte(absR+recAtt); }
  429. else {
  430. out.writeByte(extR+recAtt); }
  431. if (isInterface) { out.writeByte(SymbolFile.truSy); }
  432. else { out.writeByte(SymbolFile.falSy); }
  433. if (superClass != null) {
  434. out.writeByte(SymbolFile.basSy);
  435. SymbolFile.writeTypeOrd(out,superClass);
  436. }
  437. //if (interfaces.length > 0) {
  438. if (interfaces != null && interfaces.length > 0) {
  439. out.writeByte(SymbolFile.iFcSy);
  440. for (int i = 0; i < interfaces.length; i++) {
  441. out.writeByte(SymbolFile.basSy);
  442. SymbolFile.writeTypeOrd(out,interfaces[i]);
  443. }
  444. }
  445. for (int i=0; i < fields.length; i++) {
  446. if (fields[i].isExported() && !fields[i].isStatic()) {
  447. SymbolFile.writeName(out,fields[i].accessFlags,fields[i].name);
  448. SymbolFile.writeTypeOrd(out,fields[i].type);
  449. }
  450. }
  451. for (int i=0; i < methods.length; i++) {
  452. if (methods[i].isExported() && !methods[i].deprecated &&
  453. !methods[i].isStatic() && !methods[i].isInitProc &&
  454. !methods[i].isCLInitProc) {
  455. out.writeByte(SymbolFile.mthSy);
  456. // --------------------
  457. if (methods[i].userName == null) {
  458. System.out.println("packageDesc " + this.packageDesc.javaName);
  459. System.out.println("objName " + objName);
  460. for (int j=0; j < methods.length; j++) {
  461. System.out.println("Method " + j +
  462. (methods[i].userName == null ? " null" : methods[j].userName));
  463. }
  464. }
  465. // --------------------
  466. SymbolFile.writeName(out,methods[i].accessFlags,methods[i].userName);
  467. int attr = 0;
  468. if (!methods[i].overridding) { attr = 1; }
  469. if (methods[i].isAbstract()) { attr += 2; }
  470. else if (!methods[i].isFinal()){ attr += 6; }
  471. out.writeByte(attr);
  472. out.writeByte(0); /* all java receivers are value mode */
  473. SymbolFile.writeOrd(out,outTypeNum);
  474. SymbolFile.writeString(out,methods[i].name);
  475. SymbolFile.WriteFormalType(methods[i],out);
  476. }
  477. }
  478. for (int i=0; i < fields.length; i++) {
  479. if (fields[i].isConstant()) {
  480. out.writeByte(SymbolFile.conSy);
  481. SymbolFile.writeName(out,fields[i].accessFlags,fields[i].name);
  482. SymbolFile.writeLiteral(out,fields[i].GetConstVal());
  483. } else if (fields[i].isExported() && fields[i].isStatic()) {
  484. out.writeByte(SymbolFile.varSy);
  485. SymbolFile.writeName(out,fields[i].accessFlags,fields[i].name);
  486. SymbolFile.writeTypeOrd(out,fields[i].type);
  487. }
  488. }
  489. for (int i=0; i < methods.length; i++) {
  490. if (methods[i].isExported() && !methods[i].deprecated &&
  491. methods[i].isStatic() && !methods[i].isCLInitProc) {
  492. out.writeByte(SymbolFile.prcSy);
  493. SymbolFile.writeName(out,methods[i].accessFlags,methods[i].userName);
  494. SymbolFile.writeString(out,methods[i].name);
  495. if (methods[i].isInitProc) { out.writeByte(SymbolFile.truSy); }
  496. SymbolFile.WriteFormalType(methods[i],out);
  497. }
  498. }
  499. out.writeByte(SymbolFile.endRc);
  500. }
  501. }