You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

CtClassType.java 32KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2004 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist;
  16. import javassist.bytecode.*;
  17. import javassist.compiler.Javac;
  18. import javassist.compiler.CompileError;
  19. import javassist.compiler.AccessorMaker;
  20. import javassist.expr.ExprEditor;
  21. import java.io.InputStream;
  22. import java.io.BufferedInputStream;
  23. import java.io.DataInputStream;
  24. import java.io.DataOutputStream;
  25. import java.io.IOException;
  26. import java.net.URL;
  27. import java.util.ArrayList;
  28. import java.util.HashMap;
  29. import java.util.Hashtable;
  30. import java.util.Enumeration;
  31. import java.util.List;
  32. /**
  33. * Class types.
  34. */
  35. class CtClassType extends CtClass {
  36. ClassPool classPool;
  37. boolean wasChanged;
  38. private boolean wasFrozen;
  39. boolean wasPruned;
  40. ClassFile classfile;
  41. private CtField fieldsCache;
  42. private CtConstructor constructorsCache;
  43. private CtConstructor classInitializerCache;
  44. private CtMethod methodsCache;
  45. private AccessorMaker accessors;
  46. private FieldInitLink fieldInitializers;
  47. private Hashtable hiddenMethods; // must be synchronous
  48. private int uniqueNumberSeed;
  49. private boolean doPruning = true;
  50. int getCounter;
  51. private static int readCounter = 0;
  52. private static final int READ_THRESHOLD = 100; // see getClassFile2()
  53. CtClassType(String name, ClassPool cp) {
  54. super(name);
  55. classPool = cp;
  56. wasChanged = wasFrozen = wasPruned = false;
  57. classfile = null;
  58. accessors = null;
  59. fieldInitializers = null;
  60. hiddenMethods = null;
  61. uniqueNumberSeed = 0;
  62. eraseCache();
  63. getCounter = 0;
  64. }
  65. CtClassType(InputStream ins, ClassPool cp) throws IOException {
  66. this((String)null, cp);
  67. classfile = new ClassFile(new DataInputStream(ins));
  68. qualifiedName = classfile.getName();
  69. }
  70. protected void extendToString(StringBuffer buffer) {
  71. if (wasChanged)
  72. buffer.append("changed ");
  73. if (wasFrozen)
  74. buffer.append("frozen ");
  75. if (wasPruned)
  76. buffer.append("pruned ");
  77. buffer.append(Modifier.toString(getModifiers()));
  78. buffer.append(" class ");
  79. buffer.append(getName());
  80. try {
  81. CtClass ext = getSuperclass();
  82. if (ext != null) {
  83. String name =ext.getName();
  84. if (!name.equals("java.lang.Object"))
  85. buffer.append(" extends " + ext.getName());
  86. }
  87. }
  88. catch (NotFoundException e) {
  89. buffer.append(" extends ??");
  90. }
  91. try {
  92. CtClass[] intf = getInterfaces();
  93. if (intf.length > 0)
  94. buffer.append(" implements ");
  95. for (int i = 0; i < intf.length; ++i) {
  96. buffer.append(intf[i].getName());
  97. buffer.append(", ");
  98. }
  99. }
  100. catch (NotFoundException e) {
  101. buffer.append(" extends ??");
  102. }
  103. CtField field = getFieldsCache();
  104. buffer.append(" fields=");
  105. while (field != null) {
  106. buffer.append(field);
  107. buffer.append(", ");
  108. field = field.next;
  109. }
  110. CtConstructor c = getConstructorsCache();
  111. buffer.append(" constructors=");
  112. while (c != null) {
  113. buffer.append(c);
  114. buffer.append(", ");
  115. c = c.next;
  116. }
  117. CtMethod m = getMethodsCache();
  118. buffer.append(" methods=");
  119. while (m != null) {
  120. buffer.append(m);
  121. buffer.append(", ");
  122. m = m.next;
  123. }
  124. }
  125. protected void eraseCache() {
  126. fieldsCache = null;
  127. constructorsCache = null;
  128. classInitializerCache = null;
  129. methodsCache = null;
  130. }
  131. public AccessorMaker getAccessorMaker() {
  132. if (accessors == null)
  133. accessors = new AccessorMaker(this);
  134. return accessors;
  135. }
  136. public ClassFile getClassFile2() {
  137. if (classfile != null)
  138. return classfile;
  139. if (readCounter++ > READ_THRESHOLD) {
  140. doCompaction();
  141. readCounter = 0;
  142. }
  143. InputStream fin = null;
  144. try {
  145. fin = classPool.openClassfile(getName());
  146. if (fin == null)
  147. throw new NotFoundException(getName());
  148. fin = new BufferedInputStream(fin);
  149. classfile = new ClassFile(new DataInputStream(fin));
  150. return classfile;
  151. }
  152. catch (NotFoundException e) {
  153. throw new RuntimeException(e.toString());
  154. }
  155. catch (IOException e) {
  156. throw new RuntimeException(e.toString());
  157. }
  158. finally {
  159. if (fin != null)
  160. try {
  161. fin.close();
  162. }
  163. catch (IOException e) {}
  164. }
  165. }
  166. /* Inherited from CtClass. Called by get() in ClassPool.
  167. *
  168. * @see javassist.CtClass#incGetCounter()
  169. */
  170. void incGetCounter() { ++getCounter; }
  171. private void doCompaction() {
  172. Enumeration e = classPool.classes.elements();
  173. while (e.hasMoreElements()) {
  174. Object obj = e.nextElement();
  175. if (obj instanceof CtClassType) {
  176. CtClassType cct = (CtClassType)obj;
  177. if (cct.getCounter < 2 && !cct.isModified()) {
  178. cct.eraseCache();
  179. cct.classfile = null;
  180. }
  181. cct.getCounter = 0;
  182. }
  183. }
  184. }
  185. public ClassPool getClassPool() { return classPool; }
  186. void setClassPool(ClassPool cp) { classPool = cp; }
  187. public URL getURL() throws NotFoundException {
  188. URL url = classPool.find(getName());
  189. if (url == null)
  190. throw new NotFoundException(getName());
  191. else
  192. return url;
  193. }
  194. public boolean isModified() { return wasChanged; }
  195. public boolean isFrozen() { return wasFrozen; }
  196. void freeze() { wasFrozen = true; }
  197. void checkModify() throws RuntimeException {
  198. super.checkModify();
  199. wasChanged = true;
  200. }
  201. public void defrost() {
  202. checkPruned("defrost");
  203. wasFrozen = false;
  204. }
  205. public boolean subtypeOf(CtClass clazz) throws NotFoundException {
  206. int i;
  207. String cname = clazz.getName();
  208. if (this == clazz || getName().equals(cname))
  209. return true;
  210. ClassFile file = getClassFile2();
  211. String supername = file.getSuperclass();
  212. if (supername != null && supername.equals(cname))
  213. return true;
  214. String[] ifs = file.getInterfaces();
  215. int num = ifs.length;
  216. for (i = 0; i < num; ++i)
  217. if (ifs[i].equals(cname))
  218. return true;
  219. if (supername != null && classPool.get(supername).subtypeOf(clazz))
  220. return true;
  221. for (i = 0; i < num; ++i)
  222. if (classPool.get(ifs[i]).subtypeOf(clazz))
  223. return true;
  224. return false;
  225. }
  226. public void setName(String name) throws RuntimeException {
  227. String oldname = getName();
  228. if (name.equals(oldname))
  229. return;
  230. // check this in advance although classNameChanged() below does.
  231. classPool.checkNotFrozen(name);
  232. ClassFile cf = getClassFile2();
  233. super.setName(name);
  234. cf.setName(name);
  235. eraseCache();
  236. classPool.classNameChanged(oldname, this);
  237. }
  238. public void replaceClassName(ClassMap classnames)
  239. throws RuntimeException
  240. {
  241. String oldClassName = getName();
  242. String newClassName
  243. = (String)classnames.get(Descriptor.toJvmName(oldClassName));
  244. if (newClassName != null) {
  245. newClassName = Descriptor.toJavaName(newClassName);
  246. // check this in advance although classNameChanged() below does.
  247. classPool.checkNotFrozen(newClassName);
  248. }
  249. super.replaceClassName(classnames);
  250. ClassFile cf = getClassFile2();
  251. cf.renameClass(classnames);
  252. eraseCache();
  253. if (newClassName != null) {
  254. super.setName(newClassName);
  255. classPool.classNameChanged(oldClassName, this);
  256. }
  257. }
  258. public void replaceClassName(String oldname, String newname)
  259. throws RuntimeException
  260. {
  261. String thisname = getName();
  262. if (thisname.equals(oldname))
  263. setName(newname);
  264. else {
  265. super.replaceClassName(oldname, newname);
  266. getClassFile2().renameClass(oldname, newname);
  267. eraseCache();
  268. }
  269. }
  270. public boolean isInterface() {
  271. return Modifier.isInterface(getModifiers());
  272. }
  273. public int getModifiers() {
  274. int acc = getClassFile2().getAccessFlags();
  275. acc = AccessFlag.clear(acc, AccessFlag.SUPER);
  276. return AccessFlag.toModifier(acc);
  277. }
  278. public void setModifiers(int mod) {
  279. checkModify();
  280. int acc = AccessFlag.of(mod) | AccessFlag.SUPER;
  281. getClassFile2().setAccessFlags(acc);
  282. }
  283. public boolean subclassOf(CtClass superclass) {
  284. if (superclass == null)
  285. return false;
  286. String superName = superclass.getName();
  287. CtClass curr = this;
  288. try {
  289. while (curr != null) {
  290. if (curr.getName().equals(superName))
  291. return true;
  292. curr = curr.getSuperclass();
  293. }
  294. }
  295. catch (Exception ignored) {}
  296. return false;
  297. }
  298. public CtClass getSuperclass() throws NotFoundException {
  299. String supername = getClassFile2().getSuperclass();
  300. if (supername == null)
  301. return null;
  302. else
  303. return classPool.get(supername);
  304. }
  305. public void setSuperclass(CtClass clazz) throws CannotCompileException {
  306. checkModify();
  307. if (isInterface())
  308. addInterface(clazz);
  309. else
  310. getClassFile2().setSuperclass(clazz.getName());
  311. }
  312. public CtClass[] getInterfaces() throws NotFoundException {
  313. String[] ifs = getClassFile2().getInterfaces();
  314. int num = ifs.length;
  315. CtClass[] ifc = new CtClass[num];
  316. for (int i = 0; i < num; ++i)
  317. ifc[i] = classPool.get(ifs[i]);
  318. return ifc;
  319. }
  320. public void setInterfaces(CtClass[] list) {
  321. checkModify();
  322. String[] ifs;
  323. if (list == null)
  324. ifs = new String[0];
  325. else {
  326. int num = list.length;
  327. ifs = new String[num];
  328. for (int i = 0; i < num; ++i)
  329. ifs[i] = list[i].getName();
  330. }
  331. getClassFile2().setInterfaces(ifs);
  332. }
  333. public void addInterface(CtClass anInterface) {
  334. checkModify();
  335. if (anInterface != null)
  336. getClassFile2().addInterface(anInterface.getName());
  337. }
  338. public CtClass getDeclaringClass() throws NotFoundException {
  339. ClassFile cf = getClassFile2();
  340. InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
  341. InnerClassesAttribute.tag);
  342. if (ica == null)
  343. return null;
  344. String name = getName();
  345. int n = ica.tableLength();
  346. for (int i = 0; i < n; ++i)
  347. if (name.equals(ica.innerClass(i)))
  348. return classPool.get(ica.outerClass(i));
  349. return null;
  350. }
  351. public CtClass makeNestedClass(String name, boolean isStatic) {
  352. if (!isStatic)
  353. throw new RuntimeException(
  354. "sorry, only nested static class is supported");
  355. checkModify();
  356. CtClass c = classPool.makeNestedClass(getName() + "$" + name);
  357. ClassFile cf = getClassFile2();
  358. InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute(
  359. InnerClassesAttribute.tag);
  360. if (ica == null) {
  361. ica = new InnerClassesAttribute(cf.getConstPool());
  362. cf.addAttribute(ica);
  363. }
  364. ica.append(c.getName(), this.getName(), name, AccessFlag.STATIC);
  365. ClassFile cf2 = c.getClassFile2();
  366. cf2.addAttribute(ica.copy(cf2.getConstPool(), null));
  367. return c;
  368. }
  369. public CtField[] getFields() {
  370. ArrayList alist = new ArrayList();
  371. getFields(alist, this);
  372. return (CtField[])alist.toArray(new CtField[alist.size()]);
  373. }
  374. private static void getFields(ArrayList alist, CtClass cc) {
  375. int i, num;
  376. if (cc == null)
  377. return;
  378. try {
  379. getFields(alist, cc.getSuperclass());
  380. }
  381. catch (NotFoundException e) {}
  382. try {
  383. CtClass[] ifs = cc.getInterfaces();
  384. num = ifs.length;
  385. for (i = 0; i < num; ++i)
  386. getFields(alist, ifs[i]);
  387. }
  388. catch (NotFoundException e) {}
  389. CtField cf = ((CtClassType)cc).getFieldsCache();
  390. while (cf != null) {
  391. if (Modifier.isPublic(cf.getModifiers()))
  392. alist.add(cf);
  393. cf = cf.next;
  394. }
  395. }
  396. public CtField getField(String name) throws NotFoundException {
  397. CtField f = getField2(name);
  398. if (f == null)
  399. throw new NotFoundException("field: " + name + " in " + getName());
  400. else
  401. return f;
  402. }
  403. CtField getField2(String name) {
  404. CtField df = getDeclaredField2(name);
  405. if (df != null)
  406. return df;
  407. try {
  408. CtClass[] ifs = getInterfaces();
  409. int num = ifs.length;
  410. for (int i = 0; i < num; ++i) {
  411. CtField f = ifs[i].getField2(name);
  412. if (f != null)
  413. return f;
  414. }
  415. CtClass s = getSuperclass();
  416. if (s != null)
  417. return s.getField2(name);
  418. }
  419. catch (NotFoundException e) {}
  420. return null;
  421. }
  422. public CtField[] getDeclaredFields() {
  423. CtField cf = getFieldsCache();
  424. int num = CtField.count(cf);
  425. CtField[] cfs = new CtField[num];
  426. int i = 0;
  427. while (cf != null) {
  428. cfs[i++] = cf;
  429. cf = cf.next;
  430. }
  431. return cfs;
  432. }
  433. protected CtField getFieldsCache() {
  434. if (fieldsCache == null) {
  435. List list = getClassFile2().getFields();
  436. int n = list.size();
  437. for (int i = 0; i < n; ++i) {
  438. FieldInfo finfo = (FieldInfo)list.get(i);
  439. fieldsCache = CtField.append(fieldsCache,
  440. new CtField(finfo, this));
  441. }
  442. }
  443. return fieldsCache;
  444. }
  445. public CtField getDeclaredField(String name) throws NotFoundException {
  446. CtField f = getDeclaredField2(name);
  447. if (f == null)
  448. throw new NotFoundException("field: " + name + " in " + getName());
  449. else
  450. return f;
  451. }
  452. private CtField getDeclaredField2(String name) {
  453. CtField cf = getFieldsCache();
  454. while (cf != null) {
  455. if (cf.getName().equals(name))
  456. return cf;
  457. cf = cf.next;
  458. }
  459. return null;
  460. }
  461. public CtBehavior[] getDeclaredBehaviors() {
  462. CtConstructor cc = getConstructorsCache();
  463. CtMethod cm = getMethodsCache();
  464. int num = CtMethod.count(cm) + CtConstructor.count(cc);
  465. CtBehavior[] cb = new CtBehavior[num];
  466. int i = 0;
  467. while (cc != null) {
  468. cb[i++] = cc;
  469. cc = cc.next;
  470. }
  471. while (cm != null) {
  472. cb[i++] = cm;
  473. cm = cm.next;
  474. }
  475. return cb;
  476. }
  477. public CtConstructor[] getConstructors() {
  478. CtConstructor[] cons = getDeclaredConstructors();
  479. if (cons.length == 0)
  480. return cons;
  481. int n = 0;
  482. int i = cons.length;
  483. while (--i >= 0)
  484. if (Modifier.isPublic(cons[i].getModifiers()))
  485. ++n;
  486. CtConstructor[] result = new CtConstructor[n];
  487. n = 0;
  488. i = cons.length;
  489. while (--i >= 0) {
  490. CtConstructor c = cons[i];
  491. if (Modifier.isPublic(c.getModifiers()))
  492. result[n++] = c;
  493. }
  494. return result;
  495. }
  496. public CtConstructor getConstructor(String desc)
  497. throws NotFoundException
  498. {
  499. CtConstructor cc = getConstructorsCache();
  500. while (cc != null) {
  501. if (cc.getMethodInfo2().getDescriptor().equals(desc))
  502. return cc;
  503. cc = cc.next;
  504. }
  505. return super.getConstructor(desc);
  506. }
  507. public CtConstructor[] getDeclaredConstructors() {
  508. CtConstructor cc = getConstructorsCache();
  509. int num = CtConstructor.count(cc);
  510. CtConstructor[] ccs = new CtConstructor[num];
  511. int i = 0;
  512. while (cc != null) {
  513. ccs[i++] = cc;
  514. cc = cc.next;
  515. }
  516. return ccs;
  517. }
  518. protected CtConstructor getConstructorsCache() {
  519. if (constructorsCache == null) {
  520. List list = getClassFile2().getMethods();
  521. int n = list.size();
  522. for (int i = 0; i < n; ++i) {
  523. MethodInfo minfo = (MethodInfo)list.get(i);
  524. if (minfo.isConstructor())
  525. constructorsCache
  526. = CtConstructor.append(constructorsCache,
  527. new CtConstructor(minfo, this));
  528. }
  529. }
  530. return constructorsCache;
  531. }
  532. public CtConstructor getClassInitializer() {
  533. if (classInitializerCache == null) {
  534. MethodInfo minfo = getClassFile2().getStaticInitializer();
  535. if (minfo != null)
  536. classInitializerCache = new CtConstructor(minfo, this);
  537. }
  538. return classInitializerCache;
  539. }
  540. public CtMethod[] getMethods() {
  541. HashMap h = new HashMap();
  542. getMethods0(h, this);
  543. return (CtMethod[])h.values().toArray(new CtMethod[0]);
  544. }
  545. private static void getMethods0(HashMap h, CtClass cc) {
  546. try {
  547. CtClass[] ifs = cc.getInterfaces();
  548. int size = ifs.length;
  549. for (int i = 0; i < size; ++i)
  550. getMethods0(h, ifs[i]);
  551. }
  552. catch (NotFoundException e) {}
  553. try {
  554. CtClass s = cc.getSuperclass();
  555. if (s != null)
  556. getMethods0(h, s);
  557. }
  558. catch (NotFoundException e) {}
  559. if (cc instanceof CtClassType) {
  560. CtMethod cm = ((CtClassType)cc).getMethodsCache();
  561. while (cm != null) {
  562. if (Modifier.isPublic(cm.getModifiers()))
  563. h.put(cm.getStringRep(), cm);
  564. cm = cm.next;
  565. }
  566. }
  567. }
  568. public CtMethod getMethod(String name, String desc)
  569. throws NotFoundException
  570. {
  571. CtMethod m = getMethod0(this, name, desc);
  572. if (m != null)
  573. return m;
  574. else
  575. throw new NotFoundException(name + "(..) is not found in "
  576. + getName());
  577. }
  578. private static CtMethod getMethod0(CtClass cc,
  579. String name, String desc) {
  580. if (cc instanceof CtClassType) {
  581. CtMethod cm = ((CtClassType)cc).getMethodsCache();
  582. while (cm != null) {
  583. if (cm.getName().equals(name)
  584. && cm.getMethodInfo2().getDescriptor().equals(desc))
  585. return cm;
  586. cm = cm.next;
  587. }
  588. }
  589. try {
  590. CtClass s = cc.getSuperclass();
  591. if (s != null) {
  592. CtMethod m = getMethod0(s, name, desc);
  593. if (m != null)
  594. return m;
  595. }
  596. }
  597. catch (NotFoundException e) {}
  598. try {
  599. CtClass[] ifs = cc.getInterfaces();
  600. int size = ifs.length;
  601. for (int i = 0; i < size; ++i) {
  602. CtMethod m = getMethod0(ifs[i], name, desc);
  603. if (m != null)
  604. return m;
  605. }
  606. }
  607. catch (NotFoundException e) {}
  608. return null;
  609. }
  610. public CtMethod[] getDeclaredMethods() {
  611. CtMethod cm = getMethodsCache();
  612. int num = CtMethod.count(cm);
  613. CtMethod[] cms = new CtMethod[num];
  614. int i = 0;
  615. while (cm != null) {
  616. cms[i++] = cm;
  617. cm = cm.next;
  618. }
  619. return cms;
  620. }
  621. public CtMethod getDeclaredMethod(String name) throws NotFoundException {
  622. CtMethod m = getMethodsCache();
  623. while (m != null) {
  624. if (m.getName().equals(name))
  625. return m;
  626. m = m.next;
  627. }
  628. throw new NotFoundException(name + "(..) is not found in "
  629. + getName());
  630. }
  631. public CtMethod getDeclaredMethod(String name, CtClass[] params)
  632. throws NotFoundException
  633. {
  634. String desc = Descriptor.ofParameters(params);
  635. CtMethod m = getMethodsCache();
  636. while (m != null) {
  637. if (m.getName().equals(name)
  638. && m.getMethodInfo2().getDescriptor().startsWith(desc))
  639. return m;
  640. m = m.next;
  641. }
  642. throw new NotFoundException(name + "(..) is not found in "
  643. + getName());
  644. }
  645. protected CtMethod getMethodsCache() {
  646. if (methodsCache == null) {
  647. List list = getClassFile2().getMethods();
  648. int n = list.size();
  649. for (int i = 0; i < n; ++i) {
  650. MethodInfo minfo = (MethodInfo)list.get(i);
  651. if (minfo.isMethod())
  652. methodsCache = CtMethod.append(methodsCache,
  653. new CtMethod(minfo, this));
  654. }
  655. }
  656. return methodsCache;
  657. }
  658. public void addField(CtField f, String init)
  659. throws CannotCompileException
  660. {
  661. addField(f, CtField.Initializer.byExpr(init));
  662. }
  663. public void addField(CtField f, CtField.Initializer init)
  664. throws CannotCompileException
  665. {
  666. checkModify();
  667. if (f.getDeclaringClass() != this)
  668. throw new CannotCompileException("cannot add");
  669. if (init == null)
  670. init = f.getInit();
  671. getFieldsCache();
  672. fieldsCache = CtField.append(fieldsCache, f);
  673. getClassFile2().addField(f.getFieldInfo2());
  674. if (init != null) {
  675. FieldInitLink fil = new FieldInitLink(f, init);
  676. FieldInitLink link = fieldInitializers;
  677. if (link == null)
  678. fieldInitializers = fil;
  679. else {
  680. while (link.next != null)
  681. link = link.next;
  682. link.next = fil;
  683. }
  684. }
  685. }
  686. public CtConstructor makeClassInitializer()
  687. throws CannotCompileException
  688. {
  689. CtConstructor clinit = getClassInitializer();
  690. if (clinit != null)
  691. return clinit;
  692. checkModify();
  693. ClassFile cf = getClassFile2();
  694. Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
  695. modifyClassConstructor(cf, code, 0, 0);
  696. return getClassInitializer();
  697. }
  698. public void addConstructor(CtConstructor c)
  699. throws CannotCompileException
  700. {
  701. checkModify();
  702. if (c.getDeclaringClass() != this)
  703. throw new CannotCompileException("cannot add");
  704. getConstructorsCache();
  705. constructorsCache = CtConstructor.append(constructorsCache, c);
  706. getClassFile2().addMethod(c.getMethodInfo2());
  707. }
  708. public void addMethod(CtMethod m) throws CannotCompileException {
  709. checkModify();
  710. if (m.getDeclaringClass() != this)
  711. throw new CannotCompileException("cannot add");
  712. getMethodsCache();
  713. methodsCache = CtMethod.append(methodsCache, m);
  714. getClassFile2().addMethod(m.getMethodInfo2());
  715. if ((m.getModifiers() & Modifier.ABSTRACT) != 0)
  716. setModifiers(getModifiers() | Modifier.ABSTRACT);
  717. }
  718. public byte[] getAttribute(String name) {
  719. AttributeInfo ai = getClassFile2().getAttribute(name);
  720. if (ai == null)
  721. return null;
  722. else
  723. return ai.get();
  724. }
  725. public void setAttribute(String name, byte[] data) {
  726. checkModify();
  727. ClassFile cf = getClassFile2();
  728. cf.addAttribute(new AttributeInfo(cf.getConstPool(), name, data));
  729. }
  730. public void instrument(CodeConverter converter)
  731. throws CannotCompileException
  732. {
  733. checkModify();
  734. ClassFile cf = getClassFile2();
  735. ConstPool cp = cf.getConstPool();
  736. List list = cf.getMethods();
  737. int n = list.size();
  738. for (int i = 0; i < n; ++i) {
  739. MethodInfo minfo = (MethodInfo)list.get(i);
  740. converter.doit(this, minfo, cp);
  741. }
  742. }
  743. public void instrument(ExprEditor editor)
  744. throws CannotCompileException
  745. {
  746. checkModify();
  747. ClassFile cf = getClassFile2();
  748. List list = cf.getMethods();
  749. int n = list.size();
  750. for (int i = 0; i < n; ++i) {
  751. MethodInfo minfo = (MethodInfo)list.get(i);
  752. editor.doit(this, minfo);
  753. }
  754. }
  755. public void toBytecode(DataOutputStream out)
  756. throws CannotCompileException, IOException
  757. {
  758. try {
  759. if (isModified()) {
  760. checkPruned("toBytecode");
  761. ClassFile cf = getClassFile2();
  762. modifyClassConstructor(cf);
  763. modifyConstructors(cf);
  764. cf.write(out);
  765. out.flush();
  766. fieldInitializers = null;
  767. if (doPruning) {
  768. // to save memory
  769. cf.prune();
  770. wasPruned = true;
  771. }
  772. }
  773. else {
  774. classPool.writeClassfile(getName(), out);
  775. // to save memory
  776. eraseCache();
  777. classfile = null;
  778. }
  779. wasFrozen = true;
  780. }
  781. catch (NotFoundException e) {
  782. throw new CannotCompileException(e);
  783. }
  784. catch (IOException e) {
  785. throw new CannotCompileException(e);
  786. }
  787. }
  788. private void checkPruned(String method) {
  789. if (wasPruned)
  790. throw new RuntimeException(method + "(): " + getName()
  791. + " was pruned.");
  792. }
  793. public void stopPruning(boolean stop) {
  794. doPruning = !stop;
  795. }
  796. private void modifyClassConstructor(ClassFile cf)
  797. throws CannotCompileException, NotFoundException
  798. {
  799. if (fieldInitializers == null)
  800. return;
  801. Bytecode code = new Bytecode(cf.getConstPool(), 0, 0);
  802. Javac jv = new Javac(code, this);
  803. int stacksize = 0;
  804. boolean doInit = false;
  805. for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
  806. CtField f = fi.field;
  807. if (Modifier.isStatic(f.getModifiers())) {
  808. doInit = true;
  809. int s = fi.init.compileIfStatic(f.getType(), f.getName(),
  810. code, jv);
  811. if (stacksize < s)
  812. stacksize = s;
  813. }
  814. }
  815. if (doInit) // need an initializer for static fileds.
  816. modifyClassConstructor(cf, code, stacksize, 0);
  817. }
  818. private void modifyClassConstructor(ClassFile cf, Bytecode code,
  819. int stacksize, int localsize)
  820. throws CannotCompileException
  821. {
  822. MethodInfo m = cf.getStaticInitializer();
  823. if (m == null) {
  824. code.add(Bytecode.RETURN);
  825. code.setMaxStack(stacksize);
  826. code.setMaxLocals(localsize);
  827. m = new MethodInfo(cf.getConstPool(), "<clinit>", "()V");
  828. m.setAccessFlags(AccessFlag.STATIC);
  829. m.setCodeAttribute(code.toCodeAttribute());
  830. cf.addMethod(m);
  831. }
  832. else {
  833. CodeAttribute codeAttr = m.getCodeAttribute();
  834. if (codeAttr == null)
  835. throw new CannotCompileException("empty <clinit>");
  836. try {
  837. CodeIterator it = codeAttr.iterator();
  838. int pos = it.insertEx(code.get());
  839. it.insert(code.getExceptionTable(), pos);
  840. int maxstack = codeAttr.getMaxStack();
  841. if (maxstack < stacksize)
  842. codeAttr.setMaxStack(stacksize);
  843. int maxlocals = codeAttr.getMaxLocals();
  844. if (maxlocals < localsize)
  845. codeAttr.setMaxLocals(localsize);
  846. }
  847. catch (BadBytecode e) {
  848. throw new CannotCompileException(e);
  849. }
  850. }
  851. }
  852. private void modifyConstructors(ClassFile cf)
  853. throws CannotCompileException, NotFoundException
  854. {
  855. if (fieldInitializers == null)
  856. return;
  857. ConstPool cp = cf.getConstPool();
  858. List list = cf.getMethods();
  859. int n = list.size();
  860. for (int i = 0; i < n; ++i) {
  861. MethodInfo minfo = (MethodInfo)list.get(i);
  862. if (minfo.isConstructor()) {
  863. CodeAttribute codeAttr = minfo.getCodeAttribute();
  864. if (codeAttr != null)
  865. try {
  866. Bytecode init = new Bytecode(cp, 0,
  867. codeAttr.getMaxLocals());
  868. CtClass[] params
  869. = Descriptor.getParameterTypes(
  870. minfo.getDescriptor(),
  871. classPool);
  872. int stacksize = makeFieldInitializer(init, params);
  873. insertAuxInitializer(codeAttr, init, stacksize);
  874. }
  875. catch (BadBytecode e) {
  876. throw new CannotCompileException(e);
  877. }
  878. }
  879. }
  880. }
  881. private static void insertAuxInitializer(CodeAttribute codeAttr,
  882. Bytecode initializer,
  883. int stacksize)
  884. throws BadBytecode
  885. {
  886. CodeIterator it = codeAttr.iterator();
  887. int index = it.skipSuperConstructor();
  888. if (index < 0) {
  889. index = it.skipThisConstructor();
  890. if (index >= 0)
  891. return; // this() is called.
  892. // Neither this() or super() is called.
  893. }
  894. int pos = it.insertEx(initializer.get());
  895. it.insert(initializer.getExceptionTable(), pos);
  896. int maxstack = codeAttr.getMaxStack();
  897. if (maxstack < stacksize)
  898. codeAttr.setMaxStack(stacksize);
  899. }
  900. private int makeFieldInitializer(Bytecode code, CtClass[] parameters)
  901. throws CannotCompileException, NotFoundException
  902. {
  903. int stacksize = 0;
  904. Javac jv = new Javac(code, this);
  905. try {
  906. jv.recordParams(parameters, false);
  907. }
  908. catch (CompileError e) {
  909. throw new CannotCompileException(e);
  910. }
  911. for (FieldInitLink fi = fieldInitializers; fi != null; fi = fi.next) {
  912. CtField f = fi.field;
  913. if (!Modifier.isStatic(f.getModifiers())) {
  914. int s = fi.init.compile(f.getType(), f.getName(), code,
  915. parameters, jv);
  916. if (stacksize < s)
  917. stacksize = s;
  918. }
  919. }
  920. return stacksize;
  921. }
  922. // Methods used by CtNewWrappedMethod
  923. Hashtable getHiddenMethods() {
  924. if (hiddenMethods == null)
  925. hiddenMethods = new Hashtable();
  926. return hiddenMethods;
  927. }
  928. int getUniqueNumber() { return uniqueNumberSeed++; }
  929. }
  930. class FieldInitLink {
  931. FieldInitLink next;
  932. CtField field;
  933. CtField.Initializer init;
  934. FieldInitLink(CtField f, CtField.Initializer i) {
  935. next = null;
  936. field = f;
  937. init = i;
  938. }
  939. }