ClassDesc.java 20 KB

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