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.

CtBehavior.java 42KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999- 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. * or the Apache License Version 2.0.
  10. *
  11. * Software distributed under the License is distributed on an "AS IS" basis,
  12. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  13. * for the specific language governing rights and limitations under the
  14. * License.
  15. */
  16. package javassist;
  17. import javassist.bytecode.*;
  18. import javassist.compiler.Javac;
  19. import javassist.compiler.CompileError;
  20. import javassist.expr.ExprEditor;
  21. /**
  22. * <code>CtBehavior</code> represents a method, a constructor,
  23. * or a static constructor (class initializer).
  24. * It is the abstract super class of
  25. * <code>CtMethod</code> and <code>CtConstructor</code>.
  26. */
  27. public abstract class CtBehavior extends CtMember {
  28. protected MethodInfo methodInfo;
  29. protected CtBehavior(CtClass clazz, MethodInfo minfo) {
  30. super(clazz);
  31. methodInfo = minfo;
  32. }
  33. /**
  34. * @param isCons true if this is a constructor.
  35. */
  36. void copy(CtBehavior src, boolean isCons, ClassMap map)
  37. throws CannotCompileException
  38. {
  39. CtClass declaring = declaringClass;
  40. MethodInfo srcInfo = src.methodInfo;
  41. CtClass srcClass = src.getDeclaringClass();
  42. ConstPool cp = declaring.getClassFile2().getConstPool();
  43. map = new ClassMap(map);
  44. map.put(srcClass.getName(), declaring.getName());
  45. try {
  46. boolean patch = false;
  47. CtClass srcSuper = srcClass.getSuperclass();
  48. CtClass destSuper = declaring.getSuperclass();
  49. String destSuperName = null;
  50. if (srcSuper != null && destSuper != null) {
  51. String srcSuperName = srcSuper.getName();
  52. destSuperName = destSuper.getName();
  53. if (!srcSuperName.equals(destSuperName))
  54. if (srcSuperName.equals(CtClass.javaLangObject))
  55. patch = true;
  56. else
  57. map.putIfNone(srcSuperName, destSuperName);
  58. }
  59. // a stack map table is copied from srcInfo.
  60. methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map);
  61. if (isCons && patch)
  62. methodInfo.setSuperclass(destSuperName);
  63. }
  64. catch (NotFoundException e) {
  65. throw new CannotCompileException(e);
  66. }
  67. catch (BadBytecode e) {
  68. throw new CannotCompileException(e);
  69. }
  70. }
  71. protected void extendToString(StringBuffer buffer) {
  72. buffer.append(' ');
  73. buffer.append(getName());
  74. buffer.append(' ');
  75. buffer.append(methodInfo.getDescriptor());
  76. }
  77. /**
  78. * Returns the method or constructor name followed by parameter types
  79. * such as <code>javassist.CtBehavior.stBody(String)</code>.
  80. *
  81. * @since 3.5
  82. */
  83. public abstract String getLongName();
  84. /**
  85. * Returns the MethodInfo representing this method/constructor in the
  86. * class file.
  87. */
  88. public MethodInfo getMethodInfo() {
  89. declaringClass.checkModify();
  90. return methodInfo;
  91. }
  92. /**
  93. * Returns the MethodInfo representing the method/constructor in the
  94. * class file (read only).
  95. * Normal applications do not need calling this method. Use
  96. * <code>getMethodInfo()</code>.
  97. *
  98. * <p>The <code>MethodInfo</code> object obtained by this method
  99. * is read only. Changes to this object might not be reflected
  100. * on a class file generated by <code>toBytecode()</code>,
  101. * <code>toClass()</code>, etc in <code>CtClass</code>.
  102. *
  103. * <p>This method is available even if the <code>CtClass</code>
  104. * containing this method is frozen. However, if the class is
  105. * frozen, the <code>MethodInfo</code> might be also pruned.
  106. *
  107. * @see #getMethodInfo()
  108. * @see CtClass#isFrozen()
  109. * @see CtClass#prune()
  110. */
  111. public MethodInfo getMethodInfo2() { return methodInfo; }
  112. /**
  113. * Obtains the modifiers of the method/constructor.
  114. *
  115. * @return modifiers encoded with
  116. * <code>javassist.Modifier</code>.
  117. * @see Modifier
  118. */
  119. public int getModifiers() {
  120. return AccessFlag.toModifier(methodInfo.getAccessFlags());
  121. }
  122. /**
  123. * Sets the encoded modifiers of the method/constructor.
  124. *
  125. * <p>Changing the modifiers may cause a problem.
  126. * For example, if a non-static method is changed to static,
  127. * the method will be rejected by the bytecode verifier.
  128. *
  129. * @see Modifier
  130. */
  131. public void setModifiers(int mod) {
  132. declaringClass.checkModify();
  133. methodInfo.setAccessFlags(AccessFlag.of(mod));
  134. }
  135. /**
  136. * Returns true if the class has the specified annotation class.
  137. *
  138. * @param clz the annotation class.
  139. * @return <code>true</code> if the annotation is found,
  140. * otherwise <code>false</code>.
  141. * @since 3.11
  142. */
  143. public boolean hasAnnotation(Class clz) {
  144. MethodInfo mi = getMethodInfo2();
  145. AnnotationsAttribute ainfo = (AnnotationsAttribute)
  146. mi.getAttribute(AnnotationsAttribute.invisibleTag);
  147. AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
  148. mi.getAttribute(AnnotationsAttribute.visibleTag);
  149. return CtClassType.hasAnnotationType(clz,
  150. getDeclaringClass().getClassPool(),
  151. ainfo, ainfo2);
  152. }
  153. /**
  154. * Returns the annotation if the class has the specified annotation class.
  155. * For example, if an annotation <code>@Author</code> is associated
  156. * with this method/constructor, an <code>Author</code> object is returned.
  157. * The member values can be obtained by calling methods on
  158. * the <code>Author</code> object.
  159. *
  160. * @param clz the annotation class.
  161. * @return the annotation if found, otherwise <code>null</code>.
  162. * @since 3.11
  163. */
  164. public Object getAnnotation(Class clz) throws ClassNotFoundException {
  165. MethodInfo mi = getMethodInfo2();
  166. AnnotationsAttribute ainfo = (AnnotationsAttribute)
  167. mi.getAttribute(AnnotationsAttribute.invisibleTag);
  168. AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
  169. mi.getAttribute(AnnotationsAttribute.visibleTag);
  170. return CtClassType.getAnnotationType(clz,
  171. getDeclaringClass().getClassPool(),
  172. ainfo, ainfo2);
  173. }
  174. /**
  175. * Returns the annotations associated with this method or constructor.
  176. *
  177. * @return an array of annotation-type objects.
  178. * @see #getAvailableAnnotations()
  179. * @since 3.1
  180. */
  181. public Object[] getAnnotations() throws ClassNotFoundException {
  182. return getAnnotations(false);
  183. }
  184. /**
  185. * Returns the annotations associated with this method or constructor.
  186. * If any annotations are not on the classpath, they are not included
  187. * in the returned array.
  188. *
  189. * @return an array of annotation-type objects.
  190. * @see #getAnnotations()
  191. * @since 3.3
  192. */
  193. public Object[] getAvailableAnnotations(){
  194. try{
  195. return getAnnotations(true);
  196. }
  197. catch (ClassNotFoundException e){
  198. throw new RuntimeException("Unexpected exception", e);
  199. }
  200. }
  201. private Object[] getAnnotations(boolean ignoreNotFound)
  202. throws ClassNotFoundException
  203. {
  204. MethodInfo mi = getMethodInfo2();
  205. AnnotationsAttribute ainfo = (AnnotationsAttribute)
  206. mi.getAttribute(AnnotationsAttribute.invisibleTag);
  207. AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
  208. mi.getAttribute(AnnotationsAttribute.visibleTag);
  209. return CtClassType.toAnnotationType(ignoreNotFound,
  210. getDeclaringClass().getClassPool(),
  211. ainfo, ainfo2);
  212. }
  213. /**
  214. * Returns the parameter annotations associated with this method or constructor.
  215. *
  216. * @return an array of annotation-type objects. The length of the returned array is
  217. * equal to the number of the formal parameters. If each parameter has no
  218. * annotation, the elements of the returned array are empty arrays.
  219. *
  220. * @see #getAvailableParameterAnnotations()
  221. * @see #getAnnotations()
  222. * @since 3.1
  223. */
  224. public Object[][] getParameterAnnotations() throws ClassNotFoundException {
  225. return getParameterAnnotations(false);
  226. }
  227. /**
  228. * Returns the parameter annotations associated with this method or constructor.
  229. * If any annotations are not on the classpath, they are not included in the
  230. * returned array.
  231. *
  232. * @return an array of annotation-type objects. The length of the returned array is
  233. * equal to the number of the formal parameters. If each parameter has no
  234. * annotation, the elements of the returned array are empty arrays.
  235. *
  236. * @see #getParameterAnnotations()
  237. * @see #getAvailableAnnotations()
  238. * @since 3.3
  239. */
  240. public Object[][] getAvailableParameterAnnotations(){
  241. try {
  242. return getParameterAnnotations(true);
  243. }
  244. catch(ClassNotFoundException e) {
  245. throw new RuntimeException("Unexpected exception", e);
  246. }
  247. }
  248. Object[][] getParameterAnnotations(boolean ignoreNotFound)
  249. throws ClassNotFoundException
  250. {
  251. MethodInfo mi = getMethodInfo2();
  252. ParameterAnnotationsAttribute ainfo = (ParameterAnnotationsAttribute)
  253. mi.getAttribute(ParameterAnnotationsAttribute.invisibleTag);
  254. ParameterAnnotationsAttribute ainfo2 = (ParameterAnnotationsAttribute)
  255. mi.getAttribute(ParameterAnnotationsAttribute.visibleTag);
  256. return CtClassType.toAnnotationType(ignoreNotFound,
  257. getDeclaringClass().getClassPool(),
  258. ainfo, ainfo2, mi);
  259. }
  260. /**
  261. * Obtains parameter types of this method/constructor.
  262. */
  263. public CtClass[] getParameterTypes() throws NotFoundException {
  264. return Descriptor.getParameterTypes(methodInfo.getDescriptor(),
  265. declaringClass.getClassPool());
  266. }
  267. /**
  268. * Obtains the type of the returned value.
  269. */
  270. CtClass getReturnType0() throws NotFoundException {
  271. return Descriptor.getReturnType(methodInfo.getDescriptor(),
  272. declaringClass.getClassPool());
  273. }
  274. /**
  275. * Returns the method signature (the parameter types
  276. * and the return type).
  277. * The method signature is represented by a character string
  278. * called method descriptor, which is defined in the JVM specification.
  279. * If two methods/constructors have
  280. * the same parameter types
  281. * and the return type, <code>getSignature()</code> returns the
  282. * same string (the return type of constructors is <code>void</code>).
  283. *
  284. * <p>Note that the returned string is not the type signature
  285. * contained in the <code>SignatureAttirbute</code>. It is
  286. * a descriptor. To obtain a type signature, call the following
  287. * methods:
  288. *
  289. * <ul><pre>getMethodInfo().getAttribute(SignatureAttribute.tag)
  290. * </pre></ul>
  291. *
  292. * @see javassist.bytecode.Descriptor
  293. * @see javassist.bytecode.SignatureAttribute
  294. */
  295. public String getSignature() {
  296. return methodInfo.getDescriptor();
  297. }
  298. /**
  299. * Obtains exceptions that this method/constructor may throw.
  300. *
  301. * @return a zero-length array if there is no throws clause.
  302. */
  303. public CtClass[] getExceptionTypes() throws NotFoundException {
  304. String[] exceptions;
  305. ExceptionsAttribute ea = methodInfo.getExceptionsAttribute();
  306. if (ea == null)
  307. exceptions = null;
  308. else
  309. exceptions = ea.getExceptions();
  310. return declaringClass.getClassPool().get(exceptions);
  311. }
  312. /**
  313. * Sets exceptions that this method/constructor may throw.
  314. */
  315. public void setExceptionTypes(CtClass[] types) throws NotFoundException {
  316. declaringClass.checkModify();
  317. if (types == null || types.length == 0) {
  318. methodInfo.removeExceptionsAttribute();
  319. return;
  320. }
  321. String[] names = new String[types.length];
  322. for (int i = 0; i < types.length; ++i)
  323. names[i] = types[i].getName();
  324. ExceptionsAttribute ea = methodInfo.getExceptionsAttribute();
  325. if (ea == null) {
  326. ea = new ExceptionsAttribute(methodInfo.getConstPool());
  327. methodInfo.setExceptionsAttribute(ea);
  328. }
  329. ea.setExceptions(names);
  330. }
  331. /**
  332. * Returns true if the body is empty.
  333. */
  334. public abstract boolean isEmpty();
  335. /**
  336. * Sets a method/constructor body.
  337. *
  338. * @param src the source code representing the body.
  339. * It must be a single statement or block.
  340. * If it is <code>null</code>, the substituted
  341. * body does nothing except returning zero or null.
  342. */
  343. public void setBody(String src) throws CannotCompileException {
  344. setBody(src, null, null);
  345. }
  346. /**
  347. * Sets a method/constructor body.
  348. *
  349. * @param src the source code representing the body.
  350. * It must be a single statement or block.
  351. * If it is <code>null</code>, the substituted
  352. * body does nothing except returning zero or null.
  353. * @param delegateObj the source text specifying the object
  354. * that is called on by <code>$proceed()</code>.
  355. * @param delegateMethod the name of the method
  356. * that is called by <code>$proceed()</code>.
  357. */
  358. public void setBody(String src,
  359. String delegateObj, String delegateMethod)
  360. throws CannotCompileException
  361. {
  362. CtClass cc = declaringClass;
  363. cc.checkModify();
  364. try {
  365. Javac jv = new Javac(cc);
  366. if (delegateMethod != null)
  367. jv.recordProceed(delegateObj, delegateMethod);
  368. Bytecode b = jv.compileBody(this, src);
  369. methodInfo.setCodeAttribute(b.toCodeAttribute());
  370. methodInfo.setAccessFlags(methodInfo.getAccessFlags()
  371. & ~AccessFlag.ABSTRACT);
  372. methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
  373. declaringClass.rebuildClassFile();
  374. }
  375. catch (CompileError e) {
  376. throw new CannotCompileException(e);
  377. } catch (BadBytecode e) {
  378. throw new CannotCompileException(e);
  379. }
  380. }
  381. static void setBody0(CtClass srcClass, MethodInfo srcInfo,
  382. CtClass destClass, MethodInfo destInfo,
  383. ClassMap map)
  384. throws CannotCompileException
  385. {
  386. destClass.checkModify();
  387. map = new ClassMap(map);
  388. map.put(srcClass.getName(), destClass.getName());
  389. try {
  390. CodeAttribute cattr = srcInfo.getCodeAttribute();
  391. if (cattr != null) {
  392. ConstPool cp = destInfo.getConstPool();
  393. CodeAttribute ca = (CodeAttribute)cattr.copy(cp, map);
  394. destInfo.setCodeAttribute(ca);
  395. // a stack map table is copied to destInfo.
  396. }
  397. }
  398. catch (CodeAttribute.RuntimeCopyException e) {
  399. /* the exception may be thrown by copy() in CodeAttribute.
  400. */
  401. throw new CannotCompileException(e);
  402. }
  403. destInfo.setAccessFlags(destInfo.getAccessFlags()
  404. & ~AccessFlag.ABSTRACT);
  405. destClass.rebuildClassFile();
  406. }
  407. /**
  408. * Obtains an attribute with the given name.
  409. * If that attribute is not found in the class file, this
  410. * method returns null.
  411. *
  412. * <p>Note that an attribute is a data block specified by
  413. * the class file format. It is not an annotation.
  414. * See {@link javassist.bytecode.AttributeInfo}.
  415. *
  416. * @param name attribute name
  417. */
  418. public byte[] getAttribute(String name) {
  419. AttributeInfo ai = methodInfo.getAttribute(name);
  420. if (ai == null)
  421. return null;
  422. else
  423. return ai.get();
  424. }
  425. /**
  426. * Adds an attribute. The attribute is saved in the class file.
  427. *
  428. * <p>Note that an attribute is a data block specified by
  429. * the class file format. It is not an annotation.
  430. * See {@link javassist.bytecode.AttributeInfo}.
  431. *
  432. * @param name attribute name
  433. * @param data attribute value
  434. */
  435. public void setAttribute(String name, byte[] data) {
  436. declaringClass.checkModify();
  437. methodInfo.addAttribute(new AttributeInfo(methodInfo.getConstPool(),
  438. name, data));
  439. }
  440. /**
  441. * Declares to use <code>$cflow</code> for this method/constructor.
  442. * If <code>$cflow</code> is used, the class files modified
  443. * with Javassist requires a support class
  444. * <code>javassist.runtime.Cflow</code> at runtime
  445. * (other Javassist classes are not required at runtime).
  446. *
  447. * <p>Every <code>$cflow</code> variable is given a unique name.
  448. * For example, if the given name is <code>"Point.paint"</code>,
  449. * then the variable is indicated by <code>$cflow(Point.paint)</code>.
  450. *
  451. * @param name <code>$cflow</code> name. It can include
  452. * alphabets, numbers, <code>_</code>,
  453. * <code>$</code>, and <code>.</code> (dot).
  454. *
  455. * @see javassist.runtime.Cflow
  456. */
  457. public void useCflow(String name) throws CannotCompileException {
  458. CtClass cc = declaringClass;
  459. cc.checkModify();
  460. ClassPool pool = cc.getClassPool();
  461. String fname;
  462. int i = 0;
  463. while (true) {
  464. fname = "_cflow$" + i++;
  465. try {
  466. cc.getDeclaredField(fname);
  467. }
  468. catch(NotFoundException e) {
  469. break;
  470. }
  471. }
  472. pool.recordCflow(name, declaringClass.getName(), fname);
  473. try {
  474. CtClass type = pool.get("javassist.runtime.Cflow");
  475. CtField field = new CtField(type, fname, cc);
  476. field.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
  477. cc.addField(field, CtField.Initializer.byNew(type));
  478. insertBefore(fname + ".enter();", false);
  479. String src = fname + ".exit();";
  480. insertAfter(src, true);
  481. }
  482. catch (NotFoundException e) {
  483. throw new CannotCompileException(e);
  484. }
  485. }
  486. /**
  487. * Declares a new local variable. The scope of this variable is the
  488. * whole method body. The initial value of that variable is not set.
  489. * The declared variable can be accessed in the code snippet inserted
  490. * by <code>insertBefore()</code>, <code>insertAfter()</code>, etc.
  491. *
  492. * <p>If the second parameter <code>asFinally</code> to
  493. * <code>insertAfter()</code> is true, the declared local variable
  494. * is not visible from the code inserted by <code>insertAfter()</code>.
  495. *
  496. * @param name the name of the variable
  497. * @param type the type of the variable
  498. * @see #insertBefore(String)
  499. * @see #insertAfter(String)
  500. */
  501. public void addLocalVariable(String name, CtClass type)
  502. throws CannotCompileException
  503. {
  504. declaringClass.checkModify();
  505. ConstPool cp = methodInfo.getConstPool();
  506. CodeAttribute ca = methodInfo.getCodeAttribute();
  507. if (ca == null)
  508. throw new CannotCompileException("no method body");
  509. LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute(
  510. LocalVariableAttribute.tag);
  511. if (va == null) {
  512. va = new LocalVariableAttribute(cp);
  513. ca.getAttributes().add(va);
  514. }
  515. int maxLocals = ca.getMaxLocals();
  516. String desc = Descriptor.of(type);
  517. va.addEntry(0, ca.getCodeLength(),
  518. cp.addUtf8Info(name), cp.addUtf8Info(desc), maxLocals);
  519. ca.setMaxLocals(maxLocals + Descriptor.dataSize(desc));
  520. }
  521. /**
  522. * Inserts a new parameter, which becomes the first parameter.
  523. */
  524. public void insertParameter(CtClass type)
  525. throws CannotCompileException
  526. {
  527. declaringClass.checkModify();
  528. String desc = methodInfo.getDescriptor();
  529. String desc2 = Descriptor.insertParameter(type, desc);
  530. try {
  531. addParameter2(Modifier.isStatic(getModifiers()) ? 0 : 1, type, desc);
  532. }
  533. catch (BadBytecode e) {
  534. throw new CannotCompileException(e);
  535. }
  536. methodInfo.setDescriptor(desc2);
  537. }
  538. /**
  539. * Appends a new parameter, which becomes the last parameter.
  540. */
  541. public void addParameter(CtClass type)
  542. throws CannotCompileException
  543. {
  544. declaringClass.checkModify();
  545. String desc = methodInfo.getDescriptor();
  546. String desc2 = Descriptor.appendParameter(type, desc);
  547. int offset = Modifier.isStatic(getModifiers()) ? 0 : 1;
  548. try {
  549. addParameter2(offset + Descriptor.paramSize(desc), type, desc);
  550. }
  551. catch (BadBytecode e) {
  552. throw new CannotCompileException(e);
  553. }
  554. methodInfo.setDescriptor(desc2);
  555. }
  556. private void addParameter2(int where, CtClass type, String desc)
  557. throws BadBytecode
  558. {
  559. CodeAttribute ca = methodInfo.getCodeAttribute();
  560. if (ca != null) {
  561. int size = 1;
  562. char typeDesc = 'L';
  563. int classInfo = 0;
  564. if (type.isPrimitive()) {
  565. CtPrimitiveType cpt = (CtPrimitiveType)type;
  566. size = cpt.getDataSize();
  567. typeDesc = cpt.getDescriptor();
  568. }
  569. else
  570. classInfo = methodInfo.getConstPool().addClassInfo(type);
  571. ca.insertLocalVar(where, size);
  572. LocalVariableAttribute va
  573. = (LocalVariableAttribute)
  574. ca.getAttribute(LocalVariableAttribute.tag);
  575. if (va != null)
  576. va.shiftIndex(where, size);
  577. StackMapTable smt = (StackMapTable)ca.getAttribute(StackMapTable.tag);
  578. if (smt != null)
  579. smt.insertLocal(where, StackMapTable.typeTagOf(typeDesc), classInfo);
  580. StackMap sm = (StackMap)ca.getAttribute(StackMap.tag);
  581. if (sm != null)
  582. sm.insertLocal(where, StackMapTable.typeTagOf(typeDesc), classInfo);
  583. }
  584. }
  585. /**
  586. * Modifies the method/constructor body.
  587. *
  588. * @param converter specifies how to modify.
  589. */
  590. public void instrument(CodeConverter converter)
  591. throws CannotCompileException
  592. {
  593. declaringClass.checkModify();
  594. ConstPool cp = methodInfo.getConstPool();
  595. converter.doit(getDeclaringClass(), methodInfo, cp);
  596. }
  597. /**
  598. * Modifies the method/constructor body.
  599. *
  600. * @param editor specifies how to modify.
  601. */
  602. public void instrument(ExprEditor editor)
  603. throws CannotCompileException
  604. {
  605. // if the class is not frozen,
  606. // does not turn the modified flag on.
  607. if (declaringClass.isFrozen())
  608. declaringClass.checkModify();
  609. if (editor.doit(declaringClass, methodInfo))
  610. declaringClass.checkModify();
  611. }
  612. /**
  613. * Inserts bytecode at the beginning of the body.
  614. *
  615. * <p>If this object represents a constructor,
  616. * the bytecode is inserted before
  617. * a constructor in the super class or this class is called.
  618. * Therefore, the inserted bytecode is subject to constraints described
  619. * in Section 4.8.2 of The Java Virtual Machine Specification (2nd ed).
  620. * For example, it cannot access instance fields or methods although
  621. * it may assign a value to an instance field directly declared in this
  622. * class. Accessing static fields and methods is allowed.
  623. * Use <code>insertBeforeBody()</code> in <code>CtConstructor</code>.
  624. *
  625. * @param src the source code representing the inserted bytecode.
  626. * It must be a single statement or block.
  627. * @see CtConstructor#insertBeforeBody(String)
  628. */
  629. public void insertBefore(String src) throws CannotCompileException {
  630. insertBefore(src, true);
  631. }
  632. private void insertBefore(String src, boolean rebuild)
  633. throws CannotCompileException
  634. {
  635. CtClass cc = declaringClass;
  636. cc.checkModify();
  637. CodeAttribute ca = methodInfo.getCodeAttribute();
  638. if (ca == null)
  639. throw new CannotCompileException("no method body");
  640. CodeIterator iterator = ca.iterator();
  641. Javac jv = new Javac(cc);
  642. try {
  643. int nvars = jv.recordParams(getParameterTypes(),
  644. Modifier.isStatic(getModifiers()));
  645. jv.recordParamNames(ca, nvars);
  646. jv.recordLocalVariables(ca, 0);
  647. jv.recordType(getReturnType0());
  648. jv.compileStmnt(src);
  649. Bytecode b = jv.getBytecode();
  650. int stack = b.getMaxStack();
  651. int locals = b.getMaxLocals();
  652. if (stack > ca.getMaxStack())
  653. ca.setMaxStack(stack);
  654. if (locals > ca.getMaxLocals())
  655. ca.setMaxLocals(locals);
  656. int pos = iterator.insertEx(b.get());
  657. iterator.insert(b.getExceptionTable(), pos);
  658. if (rebuild)
  659. methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
  660. }
  661. catch (NotFoundException e) {
  662. throw new CannotCompileException(e);
  663. }
  664. catch (CompileError e) {
  665. throw new CannotCompileException(e);
  666. }
  667. catch (BadBytecode e) {
  668. throw new CannotCompileException(e);
  669. }
  670. }
  671. /**
  672. * Inserts bytecode at the end of the body.
  673. * The bytecode is inserted just before every return insturction.
  674. * It is not executed when an exception is thrown.
  675. *
  676. * @param src the source code representing the inserted bytecode.
  677. * It must be a single statement or block.
  678. */
  679. public void insertAfter(String src)
  680. throws CannotCompileException
  681. {
  682. insertAfter(src, false);
  683. }
  684. /**
  685. * Inserts bytecode at the end of the body.
  686. * The bytecode is inserted just before every return insturction.
  687. *
  688. * @param src the source code representing the inserted bytecode.
  689. * It must be a single statement or block.
  690. * @param asFinally true if the inserted bytecode is executed
  691. * not only when the control normally returns
  692. * but also when an exception is thrown.
  693. * If this parameter is true, the inserted code cannot
  694. * access local variables.
  695. */
  696. public void insertAfter(String src, boolean asFinally)
  697. throws CannotCompileException
  698. {
  699. CtClass cc = declaringClass;
  700. cc.checkModify();
  701. ConstPool pool = methodInfo.getConstPool();
  702. CodeAttribute ca = methodInfo.getCodeAttribute();
  703. if (ca == null)
  704. throw new CannotCompileException("no method body");
  705. CodeIterator iterator = ca.iterator();
  706. int retAddr = ca.getMaxLocals();
  707. Bytecode b = new Bytecode(pool, 0, retAddr + 1);
  708. b.setStackDepth(ca.getMaxStack() + 1);
  709. Javac jv = new Javac(b, cc);
  710. try {
  711. int nvars = jv.recordParams(getParameterTypes(),
  712. Modifier.isStatic(getModifiers()));
  713. jv.recordParamNames(ca, nvars);
  714. CtClass rtype = getReturnType0();
  715. int varNo = jv.recordReturnType(rtype, true);
  716. jv.recordLocalVariables(ca, 0);
  717. // finally clause for exceptions
  718. int handlerLen = insertAfterHandler(asFinally, b, rtype, varNo,
  719. jv, src);
  720. // finally clause for normal termination
  721. insertAfterAdvice(b, jv, src, pool, rtype, varNo);
  722. ca.setMaxStack(b.getMaxStack());
  723. ca.setMaxLocals(b.getMaxLocals());
  724. int gapPos = iterator.append(b.get());
  725. iterator.append(b.getExceptionTable(), gapPos);
  726. if (asFinally)
  727. ca.getExceptionTable().add(getStartPosOfBody(ca), gapPos, gapPos, 0);
  728. int gapLen = iterator.getCodeLength() - gapPos - handlerLen;
  729. int subr = iterator.getCodeLength() - gapLen;
  730. while (iterator.hasNext()) {
  731. int pos = iterator.next();
  732. if (pos >= subr)
  733. break;
  734. int c = iterator.byteAt(pos);
  735. if (c == Opcode.ARETURN || c == Opcode.IRETURN
  736. || c == Opcode.FRETURN || c == Opcode.LRETURN
  737. || c == Opcode.DRETURN || c == Opcode.RETURN) {
  738. insertGoto(iterator, subr, pos);
  739. subr = iterator.getCodeLength() - gapLen;
  740. }
  741. }
  742. methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
  743. }
  744. catch (NotFoundException e) {
  745. throw new CannotCompileException(e);
  746. }
  747. catch (CompileError e) {
  748. throw new CannotCompileException(e);
  749. }
  750. catch (BadBytecode e) {
  751. throw new CannotCompileException(e);
  752. }
  753. }
  754. private void insertAfterAdvice(Bytecode code, Javac jv, String src,
  755. ConstPool cp, CtClass rtype, int varNo)
  756. throws CompileError
  757. {
  758. if (rtype == CtClass.voidType) {
  759. code.addOpcode(Opcode.ACONST_NULL);
  760. code.addAstore(varNo);
  761. jv.compileStmnt(src);
  762. code.addOpcode(Opcode.RETURN);
  763. if (code.getMaxLocals() < 1)
  764. code.setMaxLocals(1);
  765. }
  766. else {
  767. code.addStore(varNo, rtype);
  768. jv.compileStmnt(src);
  769. code.addLoad(varNo, rtype);
  770. if (rtype.isPrimitive())
  771. code.addOpcode(((CtPrimitiveType)rtype).getReturnOp());
  772. else
  773. code.addOpcode(Opcode.ARETURN);
  774. }
  775. }
  776. /*
  777. * assert subr > pos
  778. */
  779. private void insertGoto(CodeIterator iterator, int subr, int pos)
  780. throws BadBytecode
  781. {
  782. iterator.setMark(subr);
  783. // the gap length might be a multiple of 4.
  784. iterator.writeByte(Opcode.NOP, pos);
  785. boolean wide = subr + 2 - pos > Short.MAX_VALUE;
  786. pos = iterator.insertGapAt(pos, wide ? 4 : 2, false).position;
  787. int offset = iterator.getMark() - pos;
  788. if (wide) {
  789. iterator.writeByte(Opcode.GOTO_W, pos);
  790. iterator.write32bit(offset, pos + 1);
  791. }
  792. else if (offset <= Short.MAX_VALUE) {
  793. iterator.writeByte(Opcode.GOTO, pos);
  794. iterator.write16bit(offset, pos + 1);
  795. }
  796. else {
  797. pos = iterator.insertGapAt(pos, 2, false).position;
  798. iterator.writeByte(Opcode.GOTO_W, pos);
  799. iterator.write32bit(iterator.getMark() - pos, pos + 1);
  800. }
  801. }
  802. /* insert a finally clause
  803. */
  804. private int insertAfterHandler(boolean asFinally, Bytecode b,
  805. CtClass rtype, int returnVarNo,
  806. Javac javac, String src)
  807. throws CompileError
  808. {
  809. if (!asFinally)
  810. return 0;
  811. int var = b.getMaxLocals();
  812. b.incMaxLocals(1);
  813. int pc = b.currentPc();
  814. b.addAstore(var); // store an exception
  815. if (rtype.isPrimitive()) {
  816. char c = ((CtPrimitiveType)rtype).getDescriptor();
  817. if (c == 'D') {
  818. b.addDconst(0.0);
  819. b.addDstore(returnVarNo);
  820. }
  821. else if (c == 'F') {
  822. b.addFconst(0);
  823. b.addFstore(returnVarNo);
  824. }
  825. else if (c == 'J') {
  826. b.addLconst(0);
  827. b.addLstore(returnVarNo);
  828. }
  829. else if (c == 'V') {
  830. b.addOpcode(Opcode.ACONST_NULL);
  831. b.addAstore(returnVarNo);
  832. }
  833. else { // int, boolean, char, short, ...
  834. b.addIconst(0);
  835. b.addIstore(returnVarNo);
  836. }
  837. }
  838. else {
  839. b.addOpcode(Opcode.ACONST_NULL);
  840. b.addAstore(returnVarNo);
  841. }
  842. javac.compileStmnt(src);
  843. b.addAload(var);
  844. b.addOpcode(Opcode.ATHROW);
  845. return b.currentPc() - pc;
  846. }
  847. /* -- OLD version --
  848. public void insertAfter(String src) throws CannotCompileException {
  849. declaringClass.checkModify();
  850. CodeAttribute ca = methodInfo.getCodeAttribute();
  851. CodeIterator iterator = ca.iterator();
  852. Bytecode b = new Bytecode(methodInfo.getConstPool(),
  853. ca.getMaxStack(), ca.getMaxLocals());
  854. b.setStackDepth(ca.getMaxStack());
  855. Javac jv = new Javac(b, declaringClass);
  856. try {
  857. jv.recordParams(getParameterTypes(),
  858. Modifier.isStatic(getModifiers()));
  859. CtClass rtype = getReturnType0();
  860. int varNo = jv.recordReturnType(rtype, true);
  861. boolean isVoid = rtype == CtClass.voidType;
  862. if (isVoid) {
  863. b.addOpcode(Opcode.ACONST_NULL);
  864. b.addAstore(varNo);
  865. jv.compileStmnt(src);
  866. }
  867. else {
  868. b.addStore(varNo, rtype);
  869. jv.compileStmnt(src);
  870. b.addLoad(varNo, rtype);
  871. }
  872. byte[] code = b.get();
  873. ca.setMaxStack(b.getMaxStack());
  874. ca.setMaxLocals(b.getMaxLocals());
  875. while (iterator.hasNext()) {
  876. int pos = iterator.next();
  877. int c = iterator.byteAt(pos);
  878. if (c == Opcode.ARETURN || c == Opcode.IRETURN
  879. || c == Opcode.FRETURN || c == Opcode.LRETURN
  880. || c == Opcode.DRETURN || c == Opcode.RETURN)
  881. iterator.insert(pos, code);
  882. }
  883. }
  884. catch (NotFoundException e) {
  885. throw new CannotCompileException(e);
  886. }
  887. catch (CompileError e) {
  888. throw new CannotCompileException(e);
  889. }
  890. catch (BadBytecode e) {
  891. throw new CannotCompileException(e);
  892. }
  893. }
  894. */
  895. /**
  896. * Adds a catch clause that handles an exception thrown in the
  897. * body. The catch clause must end with a return or throw statement.
  898. *
  899. * @param src the source code representing the catch clause.
  900. * It must be a single statement or block.
  901. * @param exceptionType the type of the exception handled by the
  902. * catch clause.
  903. */
  904. public void addCatch(String src, CtClass exceptionType)
  905. throws CannotCompileException
  906. {
  907. addCatch(src, exceptionType, "$e");
  908. }
  909. /**
  910. * Adds a catch clause that handles an exception thrown in the
  911. * body. The catch clause must end with a return or throw statement.
  912. *
  913. * @param src the source code representing the catch clause.
  914. * It must be a single statement or block.
  915. * @param exceptionType the type of the exception handled by the
  916. * catch clause.
  917. * @param exceptionName the name of the variable containing the
  918. * caught exception, for example,
  919. * <code>$e</code>.
  920. */
  921. public void addCatch(String src, CtClass exceptionType,
  922. String exceptionName)
  923. throws CannotCompileException
  924. {
  925. CtClass cc = declaringClass;
  926. cc.checkModify();
  927. ConstPool cp = methodInfo.getConstPool();
  928. CodeAttribute ca = methodInfo.getCodeAttribute();
  929. CodeIterator iterator = ca.iterator();
  930. Bytecode b = new Bytecode(cp, ca.getMaxStack(), ca.getMaxLocals());
  931. b.setStackDepth(1);
  932. Javac jv = new Javac(b, cc);
  933. try {
  934. jv.recordParams(getParameterTypes(),
  935. Modifier.isStatic(getModifiers()));
  936. int var = jv.recordVariable(exceptionType, exceptionName);
  937. b.addAstore(var);
  938. jv.compileStmnt(src);
  939. int stack = b.getMaxStack();
  940. int locals = b.getMaxLocals();
  941. if (stack > ca.getMaxStack())
  942. ca.setMaxStack(stack);
  943. if (locals > ca.getMaxLocals())
  944. ca.setMaxLocals(locals);
  945. int len = iterator.getCodeLength();
  946. int pos = iterator.append(b.get());
  947. ca.getExceptionTable().add(getStartPosOfBody(ca), len, len,
  948. cp.addClassInfo(exceptionType));
  949. iterator.append(b.getExceptionTable(), pos);
  950. methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
  951. }
  952. catch (NotFoundException e) {
  953. throw new CannotCompileException(e);
  954. }
  955. catch (CompileError e) {
  956. throw new CannotCompileException(e);
  957. } catch (BadBytecode e) {
  958. throw new CannotCompileException(e);
  959. }
  960. }
  961. /* CtConstructor overrides this method.
  962. */
  963. int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException {
  964. return 0;
  965. }
  966. /**
  967. * Inserts bytecode at the specified line in the body.
  968. * It is equivalent to:
  969. *
  970. * <br><code>insertAt(lineNum, true, src)</code>
  971. *
  972. * <br>See this method as well.
  973. *
  974. * @param lineNum the line number. The bytecode is inserted at the
  975. * beginning of the code at the line specified by this
  976. * line number.
  977. * @param src the source code representing the inserted bytecode.
  978. * It must be a single statement or block.
  979. * @return the line number at which the bytecode has been inserted.
  980. *
  981. * @see CtBehavior#insertAt(int,boolean,String)
  982. */
  983. public int insertAt(int lineNum, String src)
  984. throws CannotCompileException
  985. {
  986. return insertAt(lineNum, true, src);
  987. }
  988. /**
  989. * Inserts bytecode at the specified line in the body.
  990. *
  991. * <p>If there is not
  992. * a statement at the specified line, the bytecode might be inserted
  993. * at the line including the first statement after that line specified.
  994. * For example, if there is only a closing brace at that line, the
  995. * bytecode would be inserted at another line below.
  996. * To know exactly where the bytecode will be inserted, call with
  997. * <code>modify</code> set to <code>false</code>.
  998. *
  999. * @param lineNum the line number. The bytecode is inserted at the
  1000. * beginning of the code at the line specified by this
  1001. * line number.
  1002. * @param modify if false, this method does not insert the bytecode.
  1003. * It instead only returns the line number at which
  1004. * the bytecode would be inserted.
  1005. * @param src the source code representing the inserted bytecode.
  1006. * It must be a single statement or block.
  1007. * If modify is false, the value of src can be null.
  1008. * @return the line number at which the bytecode has been inserted.
  1009. */
  1010. public int insertAt(int lineNum, boolean modify, String src)
  1011. throws CannotCompileException
  1012. {
  1013. CodeAttribute ca = methodInfo.getCodeAttribute();
  1014. if (ca == null)
  1015. throw new CannotCompileException("no method body");
  1016. LineNumberAttribute ainfo
  1017. = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
  1018. if (ainfo == null)
  1019. throw new CannotCompileException("no line number info");
  1020. LineNumberAttribute.Pc pc = ainfo.toNearPc(lineNum);
  1021. lineNum = pc.line;
  1022. int index = pc.index;
  1023. if (!modify)
  1024. return lineNum;
  1025. CtClass cc = declaringClass;
  1026. cc.checkModify();
  1027. CodeIterator iterator = ca.iterator();
  1028. Javac jv = new Javac(cc);
  1029. try {
  1030. jv.recordLocalVariables(ca, index);
  1031. jv.recordParams(getParameterTypes(),
  1032. Modifier.isStatic(getModifiers()));
  1033. jv.setMaxLocals(ca.getMaxLocals());
  1034. jv.compileStmnt(src);
  1035. Bytecode b = jv.getBytecode();
  1036. int locals = b.getMaxLocals();
  1037. int stack = b.getMaxStack();
  1038. ca.setMaxLocals(locals);
  1039. /* We assume that there is no values in the operand stack
  1040. * at the position where the bytecode is inserted.
  1041. */
  1042. if (stack > ca.getMaxStack())
  1043. ca.setMaxStack(stack);
  1044. index = iterator.insertAt(index, b.get());
  1045. iterator.insert(b.getExceptionTable(), index);
  1046. methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2());
  1047. return lineNum;
  1048. }
  1049. catch (NotFoundException e) {
  1050. throw new CannotCompileException(e);
  1051. }
  1052. catch (CompileError e) {
  1053. throw new CannotCompileException(e);
  1054. }
  1055. catch (BadBytecode e) {
  1056. throw new CannotCompileException(e);
  1057. }
  1058. }
  1059. }