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

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