您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

CtBehavior.java 51KB

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