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

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