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 28KB

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