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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916
  1. /*
  2. * Javassist, a Java-bytecode translator toolkit.
  3. * Copyright (C) 1999-2005 Shigeru Chiba. All Rights Reserved.
  4. *
  5. * The contents of this file are subject to the Mozilla Public License Version
  6. * 1.1 (the "License"); you may not use this file except in compliance with
  7. * the License. Alternatively, the contents of this file may be used under
  8. * the terms of the GNU Lesser General Public License Version 2.1 or later.
  9. *
  10. * Software distributed under the License is distributed on an "AS IS" basis,
  11. * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  12. * for the specific language governing rights and limitations under the
  13. * License.
  14. */
  15. package javassist;
  16. import javassist.bytecode.*;
  17. import javassist.compiler.Javac;
  18. import javassist.compiler.CompileError;
  19. import javassist.expr.ExprEditor;
  20. /**
  21. * <code>CtBehavior</code> represents a method, a constructor,
  22. * or a static constructor (class initializer).
  23. * It is the abstract super class of
  24. * <code>CtMethod</code> and <code>CtConstructor</code>.
  25. */
  26. public abstract class CtBehavior extends CtMember {
  27. protected MethodInfo methodInfo;
  28. protected CtBehavior(CtClass clazz, MethodInfo minfo) {
  29. super(clazz);
  30. methodInfo = minfo;
  31. }
  32. /**
  33. * @param isCons true if this is a constructor.
  34. */
  35. void copy(CtBehavior src, boolean isCons, ClassMap map)
  36. throws CannotCompileException
  37. {
  38. CtClass declaring = declaringClass;
  39. MethodInfo srcInfo = src.methodInfo;
  40. CtClass srcClass = src.getDeclaringClass();
  41. ConstPool cp = declaring.getClassFile2().getConstPool();
  42. if (map == null)
  43. map = new ClassMap();
  44. map.put(srcClass.getName(), declaring.getName());
  45. try {
  46. boolean patch = false;
  47. CtClass srcSuper = srcClass.getSuperclass();
  48. String destSuperName = declaring.getSuperclass().getName();
  49. if (srcSuper != null) {
  50. String srcSuperName = srcSuper.getName();
  51. if (!srcSuperName.equals(destSuperName))
  52. if (srcSuperName.equals(CtClass.javaLangObject))
  53. patch = true;
  54. else
  55. map.put(srcSuperName, destSuperName);
  56. }
  57. methodInfo = new MethodInfo(cp, srcInfo.getName(), srcInfo, map);
  58. if (isCons && patch)
  59. methodInfo.setSuperclass(destSuperName);
  60. }
  61. catch (NotFoundException e) {
  62. throw new CannotCompileException(e);
  63. }
  64. catch (BadBytecode e) {
  65. throw new CannotCompileException(e);
  66. }
  67. }
  68. protected void extendToString(StringBuffer buffer) {
  69. buffer.append(' ');
  70. buffer.append(getName());
  71. buffer.append(' ');
  72. buffer.append(methodInfo.getDescriptor());
  73. }
  74. /**
  75. * Returns the MethodInfo representing this method/constructor in the
  76. * class file.
  77. */
  78. public MethodInfo getMethodInfo() {
  79. declaringClass.checkModify();
  80. return methodInfo;
  81. }
  82. /**
  83. * Returns the MethodInfo representing the method/constructor in the
  84. * class file (read only).
  85. * Normal applications do not need calling this method. Use
  86. * <code>getMethodInfo()</code>.
  87. *
  88. * <p>The <code>MethodInfo</code> object obtained by this method
  89. * is read only. Changes to this object might not be reflected
  90. * on a class file generated by <code>toBytecode()</code>,
  91. * <code>toClass()</code>, etc in <code>CtClass</code>.
  92. *
  93. * <p>This method is available even if the <code>CtClass</code>
  94. * containing this method is frozen. However, if the class is
  95. * frozen, the <code>MethodInfo</code> might be also pruned.
  96. *
  97. * @see #getMethodInfo()
  98. * @see CtClass#isFrozen()
  99. * @see CtClass#prune()
  100. */
  101. public MethodInfo getMethodInfo2() { return methodInfo; }
  102. /**
  103. * Obtains the modifiers of the method/constructor.
  104. *
  105. * @return modifiers encoded with
  106. * <code>javassist.Modifier</code>.
  107. * @see Modifier
  108. */
  109. public int getModifiers() {
  110. return AccessFlag.toModifier(methodInfo.getAccessFlags());
  111. }
  112. /**
  113. * Sets the encoded modifiers of the method/constructor.
  114. *
  115. * <p>Changing the modifiers may cause a problem.
  116. * For example, if a non-static method is changed to static,
  117. * the method will be rejected by the bytecode verifier.
  118. *
  119. * @see Modifier
  120. */
  121. public void setModifiers(int mod) {
  122. declaringClass.checkModify();
  123. methodInfo.setAccessFlags(AccessFlag.of(mod));
  124. }
  125. /**
  126. * Returns the annotations associated with this method or constructor.
  127. *
  128. * @return an array of annotation-type objects.
  129. * @see CtMember#getAnnotations()
  130. * @since 3.1
  131. */
  132. public Object[] getAnnotations() throws ClassNotFoundException {
  133. MethodInfo mi = getMethodInfo2();
  134. AnnotationsAttribute ainfo = (AnnotationsAttribute)
  135. mi.getAttribute(AnnotationsAttribute.invisibleTag);
  136. AnnotationsAttribute ainfo2 = (AnnotationsAttribute)
  137. mi.getAttribute(AnnotationsAttribute.visibleTag);
  138. return CtClassType.toAnnotationType(getDeclaringClass().getClassPool(),
  139. ainfo, ainfo2);
  140. }
  141. /**
  142. * Obtains parameter types of this method/constructor.
  143. */
  144. public CtClass[] getParameterTypes() throws NotFoundException {
  145. return Descriptor.getParameterTypes(methodInfo.getDescriptor(),
  146. declaringClass.getClassPool());
  147. }
  148. /**
  149. * Obtains the type of the returned value.
  150. */
  151. CtClass getReturnType0() throws NotFoundException {
  152. return Descriptor.getReturnType(methodInfo.getDescriptor(),
  153. declaringClass.getClassPool());
  154. }
  155. /**
  156. * Returns the character string representing the parameter types
  157. * and the return type. If two methods/constructors have
  158. * the same parameter types
  159. * and the return type, <code>getSignature()</code> returns the
  160. * same string (the return type of constructors is <code>void</code>).
  161. */
  162. public String getSignature() {
  163. return methodInfo.getDescriptor();
  164. }
  165. /**
  166. * Obtains exceptions that this method/constructor may throw.
  167. *
  168. * @return a zero-length array if there is no throws clause.
  169. */
  170. public CtClass[] getExceptionTypes() throws NotFoundException {
  171. String[] exceptions;
  172. ExceptionsAttribute ea = methodInfo.getExceptionsAttribute();
  173. if (ea == null)
  174. exceptions = null;
  175. else
  176. exceptions = ea.getExceptions();
  177. return declaringClass.getClassPool().get(exceptions);
  178. }
  179. /**
  180. * Sets exceptions that this method/constructor may throw.
  181. */
  182. public void setExceptionTypes(CtClass[] types) throws NotFoundException {
  183. declaringClass.checkModify();
  184. if (types == null || types.length == 0) {
  185. methodInfo.removeExceptionsAttribute();
  186. return;
  187. }
  188. String[] names = new String[types.length];
  189. for (int i = 0; i < types.length; ++i)
  190. names[i] = types[i].getName();
  191. ExceptionsAttribute ea = methodInfo.getExceptionsAttribute();
  192. if (ea == null) {
  193. ea = new ExceptionsAttribute(methodInfo.getConstPool());
  194. methodInfo.setExceptionsAttribute(ea);
  195. }
  196. ea.setExceptions(names);
  197. }
  198. /**
  199. * Returns true if the body is empty.
  200. */
  201. public abstract boolean isEmpty();
  202. /**
  203. * Sets a method/constructor body.
  204. *
  205. * @param src the source code representing the body.
  206. * It must be a single statement or block.
  207. * If it is <code>null</code>, the substituted
  208. * body does nothing except returning zero or null.
  209. */
  210. public void setBody(String src) throws CannotCompileException {
  211. setBody(src, null, null);
  212. }
  213. /**
  214. * Sets a method/constructor body.
  215. *
  216. * @param src the source code representing the body.
  217. * It must be a single statement or block.
  218. * If it is <code>null</code>, the substituted
  219. * body does nothing except returning zero or null.
  220. * @param delegateObj the source text specifying the object
  221. * that is called on by <code>$proceed()</code>.
  222. * @param delegateMethod the name of the method
  223. * that is called by <code>$proceed()</code>.
  224. */
  225. public void setBody(String src,
  226. String delegateObj, String delegateMethod)
  227. throws CannotCompileException
  228. {
  229. declaringClass.checkModify();
  230. try {
  231. Javac jv = new Javac(declaringClass);
  232. if (delegateMethod != null)
  233. jv.recordProceed(delegateObj, delegateMethod);
  234. Bytecode b = jv.compileBody(this, src);
  235. methodInfo.setCodeAttribute(b.toCodeAttribute());
  236. methodInfo.setAccessFlags(methodInfo.getAccessFlags()
  237. & ~AccessFlag.ABSTRACT);
  238. }
  239. catch (CompileError e) {
  240. throw new CannotCompileException(e);
  241. }
  242. }
  243. static void setBody0(CtClass srcClass, MethodInfo srcInfo,
  244. CtClass destClass, MethodInfo destInfo,
  245. ClassMap map)
  246. throws CannotCompileException
  247. {
  248. destClass.checkModify();
  249. if (map == null)
  250. map = new ClassMap();
  251. map.put(srcClass.getName(), destClass.getName());
  252. try {
  253. CodeAttribute cattr = srcInfo.getCodeAttribute();
  254. if (cattr != null) {
  255. ConstPool cp = destInfo.getConstPool();
  256. CodeAttribute ca = (CodeAttribute)cattr.copy(cp, map);
  257. destInfo.setCodeAttribute(ca);
  258. }
  259. }
  260. catch (CodeAttribute.RuntimeCopyException e) {
  261. /* the exception may be thrown by copy() in CodeAttribute.
  262. */
  263. throw new CannotCompileException(e);
  264. }
  265. destInfo.setAccessFlags(destInfo.getAccessFlags()
  266. & ~AccessFlag.ABSTRACT);
  267. }
  268. /**
  269. * Obtains an attribute with the given name.
  270. * If that attribute is not found in the class file, this
  271. * method returns null.
  272. *
  273. * <p>Note that an attribute is a data block specified by
  274. * the class file format.
  275. * See {@link javassist.bytecode.AttributeInfo}.
  276. *
  277. * @param name attribute name
  278. */
  279. public byte[] getAttribute(String name) {
  280. AttributeInfo ai = methodInfo.getAttribute(name);
  281. if (ai == null)
  282. return null;
  283. else
  284. return ai.get();
  285. }
  286. /**
  287. * Adds an attribute. The attribute is saved in the class file.
  288. *
  289. * <p>Note that an attribute is a data block specified by
  290. * the class file format.
  291. * See {@link javassist.bytecode.AttributeInfo}.
  292. *
  293. * @param name attribute name
  294. * @param data attribute value
  295. */
  296. public void setAttribute(String name, byte[] data) {
  297. declaringClass.checkModify();
  298. methodInfo.addAttribute(new AttributeInfo(methodInfo.getConstPool(),
  299. name, data));
  300. }
  301. /**
  302. * Declares to use <code>$cflow</code> for this method/constructor.
  303. * If <code>$cflow</code> is used, the class files modified
  304. * with Javassist requires a support class
  305. * <code>javassist.runtime.Cflow</code> at runtime
  306. * (other Javassist classes are not required at runtime).
  307. *
  308. * <p>Every <code>$cflow</code> variable is given a unique name.
  309. * For example, if the given name is <code>"Point.paint"</code>,
  310. * then the variable is indicated by <code>$cflow(Point.paint)</code>.
  311. *
  312. * @param name <code>$cflow</code> name. It can include
  313. * alphabets, numbers, <code>_</code>,
  314. * <code>$</code>, and <code>.</code> (dot).
  315. *
  316. * @see javassist.runtime.Cflow
  317. */
  318. public void useCflow(String name) throws CannotCompileException {
  319. CtClass cc = declaringClass;
  320. cc.checkModify();
  321. ClassPool pool = cc.getClassPool();
  322. String fname;
  323. int i = 0;
  324. while (true) {
  325. fname = "_cflow$" + i++;
  326. try {
  327. cc.getDeclaredField(fname);
  328. }
  329. catch(NotFoundException e) {
  330. break;
  331. }
  332. }
  333. pool.recordCflow(name, declaringClass.getName(), fname);
  334. try {
  335. CtClass type = pool.get("javassist.runtime.Cflow");
  336. CtField field = new CtField(type, fname, cc);
  337. field.setModifiers(Modifier.PUBLIC | Modifier.STATIC);
  338. cc.addField(field, CtField.Initializer.byNew(type));
  339. insertBefore(fname + ".enter();");
  340. String src = fname + ".exit();";
  341. insertAfter(src, true);
  342. }
  343. catch (NotFoundException e) {
  344. throw new CannotCompileException(e);
  345. }
  346. }
  347. /**
  348. * Declares a new local variable. The scope of this variable is the
  349. * whole method body. The initial value of that variable is not set.
  350. * The declared variable can be accessed in the code snippet inserted
  351. * by <code>insertBefore()</code>, <code>insertAfter()</code>, etc.
  352. *
  353. * <p>If the second parameter <code>asFinally</code> to
  354. * <code>insertAfter()</code> is true, the declared local variable
  355. * is not visible from the code inserted by <code>insertAfter()</code>.
  356. *
  357. * @param name the name of the variable
  358. * @param type the type of the variable
  359. * @see #insertBefore(String)
  360. * @see #insertAfter(String)
  361. */
  362. public void addLocalVariable(String name, CtClass type)
  363. throws CannotCompileException
  364. {
  365. declaringClass.checkModify();
  366. ConstPool cp = methodInfo.getConstPool();
  367. CodeAttribute ca = methodInfo.getCodeAttribute();
  368. if (ca == null)
  369. throw new CannotCompileException("no method body");
  370. LocalVariableAttribute va = (LocalVariableAttribute)ca.getAttribute(
  371. LocalVariableAttribute.tag);
  372. if (va == null) {
  373. va = new LocalVariableAttribute(cp);
  374. ca.getAttributes().add(va);
  375. }
  376. int maxLocals = ca.getMaxLocals();
  377. String desc = Descriptor.of(type);
  378. va.addEntry(0, ca.getCodeLength(),
  379. cp.addUtf8Info(name), cp.addUtf8Info(desc), maxLocals);
  380. ca.setMaxLocals(maxLocals + Descriptor.dataSize(desc));
  381. }
  382. /**
  383. * Modifies the method/constructor body.
  384. *
  385. * @param converter specifies how to modify.
  386. */
  387. public void instrument(CodeConverter converter)
  388. throws CannotCompileException
  389. {
  390. declaringClass.checkModify();
  391. ConstPool cp = methodInfo.getConstPool();
  392. converter.doit(getDeclaringClass(), methodInfo, cp);
  393. }
  394. /**
  395. * Modifies the method/constructor body.
  396. *
  397. * @param editor specifies how to modify.
  398. */
  399. public void instrument(ExprEditor editor)
  400. throws CannotCompileException
  401. {
  402. // if the class is not frozen,
  403. // does not turn the modified flag on.
  404. if (declaringClass.isFrozen())
  405. declaringClass.checkModify();
  406. if (editor.doit(declaringClass, methodInfo))
  407. declaringClass.checkModify();
  408. }
  409. /**
  410. * Inserts bytecode at the beginning of the body.
  411. *
  412. * <p>If this object represents a constructor,
  413. * the bytecode is inserted before
  414. * a constructor in the super class or this class is called.
  415. * Therefore, the inserted bytecode is subject to constraints described
  416. * in Section 4.8.2 of The Java Virtual Machine Specification (2nd ed).
  417. * For example, it cannot access instance fields or methods although
  418. * it may assign a value to an instance field directly declared in this
  419. * class. Accessing static fields and methods is allowed.
  420. * Use <code>insertBeforeBody()</code> in <code>CtConstructor</code>.
  421. *
  422. * @param src the source code representing the inserted bytecode.
  423. * It must be a single statement or block.
  424. * @see CtConstructor#insertBeforeBody(String)
  425. */
  426. public void insertBefore(String src) throws CannotCompileException {
  427. declaringClass.checkModify();
  428. CodeAttribute ca = methodInfo.getCodeAttribute();
  429. if (ca == null)
  430. throw new CannotCompileException("no method body");
  431. CodeIterator iterator = ca.iterator();
  432. Javac jv = new Javac(declaringClass);
  433. try {
  434. int nvars = jv.recordParams(getParameterTypes(),
  435. Modifier.isStatic(getModifiers()));
  436. jv.recordParamNames(ca, nvars);
  437. jv.recordLocalVariables(ca, 0);
  438. jv.compileStmnt(src);
  439. Bytecode b = jv.getBytecode();
  440. int stack = b.getMaxStack();
  441. int locals = b.getMaxLocals();
  442. if (stack > ca.getMaxStack())
  443. ca.setMaxStack(stack);
  444. if (locals > ca.getMaxLocals())
  445. ca.setMaxLocals(locals);
  446. int pos = iterator.insertEx(b.get());
  447. iterator.insert(b.getExceptionTable(), pos);
  448. }
  449. catch (NotFoundException e) {
  450. throw new CannotCompileException(e);
  451. }
  452. catch (CompileError e) {
  453. throw new CannotCompileException(e);
  454. }
  455. catch (BadBytecode e) {
  456. throw new CannotCompileException(e);
  457. }
  458. }
  459. /**
  460. * Inserts bytecode at the end of the body.
  461. * The bytecode is inserted just before every return insturction.
  462. * It is not executed when an exception is thrown.
  463. *
  464. * @param src the source code representing the inserted bytecode.
  465. * It must be a single statement or block.
  466. */
  467. public void insertAfter(String src)
  468. throws CannotCompileException
  469. {
  470. insertAfter(src, false);
  471. }
  472. /**
  473. * Inserts bytecode at the end of the body.
  474. * The bytecode is inserted just before every return insturction.
  475. *
  476. * @param src the source code representing the inserted bytecode.
  477. * It must be a single statement or block.
  478. * @param asFinally true if the inserted bytecode is executed
  479. * not only when the control normally returns
  480. * but also when an exception is thrown.
  481. * If this parameter is true, the inserted code cannot
  482. * access local variables.
  483. */
  484. public void insertAfter(String src, boolean asFinally)
  485. throws CannotCompileException
  486. {
  487. declaringClass.checkModify();
  488. ConstPool pool = methodInfo.getConstPool();
  489. CodeAttribute ca = methodInfo.getCodeAttribute();
  490. if (ca == null)
  491. throw new CannotCompileException("no method body");
  492. CodeIterator iterator = ca.iterator();
  493. int retAddr = ca.getMaxLocals();
  494. Bytecode b = new Bytecode(pool, 0, retAddr + 1);
  495. b.setStackDepth(ca.getMaxStack() + 1);
  496. Javac jv = new Javac(b, declaringClass);
  497. try {
  498. int nvars = jv.recordParams(getParameterTypes(),
  499. Modifier.isStatic(getModifiers()));
  500. jv.recordParamNames(ca, nvars);
  501. CtClass rtype = getReturnType0();
  502. int varNo = jv.recordReturnType(rtype, true);
  503. jv.recordLocalVariables(ca, 0);
  504. int handlerLen = insertAfterHandler(asFinally, b, rtype, varNo);
  505. byte[] save = makeSaveCode(pool, rtype, varNo);
  506. byte[] restore = makeRestoreCode(b, pool, rtype, varNo);
  507. b.addAstore(retAddr);
  508. jv.compileStmnt(src);
  509. b.addRet(retAddr);
  510. ca.setMaxStack(b.getMaxStack());
  511. ca.setMaxLocals(b.getMaxLocals());
  512. int gapPos = iterator.append(b.get());
  513. iterator.append(b.getExceptionTable(), gapPos);
  514. if (asFinally)
  515. ca.getExceptionTable().add(0, gapPos, gapPos, 0);
  516. int gapLen = iterator.getCodeLength() - gapPos - handlerLen;
  517. int subr = iterator.getCodeLength() - gapLen;
  518. while (iterator.hasNext()) {
  519. int pos = iterator.next();
  520. if (pos >= subr)
  521. break;
  522. int c = iterator.byteAt(pos);
  523. if (c == Opcode.ARETURN || c == Opcode.IRETURN
  524. || c == Opcode.FRETURN || c == Opcode.LRETURN
  525. || c == Opcode.DRETURN || c == Opcode.RETURN) {
  526. insertJSR(iterator, subr, pos, save, restore);
  527. subr = iterator.getCodeLength() - gapLen;
  528. }
  529. }
  530. }
  531. catch (NotFoundException e) {
  532. throw new CannotCompileException(e);
  533. }
  534. catch (CompileError e) {
  535. throw new CannotCompileException(e);
  536. }
  537. catch (BadBytecode e) {
  538. throw new CannotCompileException(e);
  539. }
  540. }
  541. private byte[] makeSaveCode(ConstPool cp, CtClass rtype, int varNo) {
  542. Bytecode b = new Bytecode(cp, 0, 0);
  543. if (rtype == CtClass.voidType) {
  544. b.addOpcode(Opcode.ACONST_NULL);
  545. b.addAstore(varNo);
  546. return b.get();
  547. }
  548. else {
  549. b.addStore(varNo, rtype);
  550. return b.get();
  551. }
  552. }
  553. private byte[] makeRestoreCode(Bytecode code, ConstPool cp,
  554. CtClass rtype, int varNo) {
  555. if (rtype == CtClass.voidType) {
  556. if (code.getMaxLocals() < 1)
  557. code.setMaxLocals(1);
  558. return new byte[0];
  559. }
  560. else {
  561. Bytecode b = new Bytecode(cp, 0, 0);
  562. b.addLoad(varNo, rtype);
  563. return b.get();
  564. }
  565. }
  566. private void insertJSR(CodeIterator iterator, int subr, int pos,
  567. byte[] save, byte[] restore)
  568. throws BadBytecode
  569. {
  570. int gapSize = 5 + save.length + restore.length;
  571. boolean wide = subr - pos > Short.MAX_VALUE - gapSize - 4;
  572. gapSize = iterator.insertGap(pos, wide ? gapSize : gapSize - 2);
  573. iterator.write(save, pos);
  574. pos += save.length;
  575. if (wide) {
  576. iterator.writeByte(Opcode.JSR_W, pos);
  577. iterator.write32bit(subr - pos + gapSize, pos + 1);
  578. pos += 5;
  579. }
  580. else {
  581. iterator.writeByte(Opcode.JSR, pos);
  582. iterator.write16bit(subr - pos + gapSize, pos + 1);
  583. pos += 3;
  584. }
  585. iterator.write(restore, pos);
  586. }
  587. private int insertAfterHandler(boolean asFinally, Bytecode b,
  588. CtClass rtype, int returnVarNo)
  589. {
  590. if (!asFinally)
  591. return 0;
  592. int var = b.getMaxLocals();
  593. b.incMaxLocals(1);
  594. int pc = b.currentPc();
  595. b.addAstore(var);
  596. if (rtype.isPrimitive()) {
  597. char c = ((CtPrimitiveType)rtype).getDescriptor();
  598. if (c == 'D') {
  599. b.addDconst(0.0);
  600. b.addDstore(returnVarNo);
  601. }
  602. else if (c == 'F') {
  603. b.addFconst(0);
  604. b.addFstore(returnVarNo);
  605. }
  606. else if (c == 'J') {
  607. b.addLconst(0);
  608. b.addLstore(returnVarNo);
  609. }
  610. else if (c != 'V') { // int, boolean, char, short, ...
  611. b.addIconst(0);
  612. b.addIstore(returnVarNo);
  613. }
  614. }
  615. else {
  616. b.addOpcode(Opcode.ACONST_NULL);
  617. b.addAstore(returnVarNo);
  618. }
  619. b.addOpcode(Opcode.JSR);
  620. int pc2 = b.currentPc();
  621. b.addIndex(0); // correct later
  622. b.addAload(var);
  623. b.addOpcode(Opcode.ATHROW);
  624. int pc3 = b.currentPc();
  625. b.write16bit(pc2, pc3 - pc2 + 1);
  626. return pc3 - pc;
  627. }
  628. /* -- OLD version --
  629. public void insertAfter(String src) throws CannotCompileException {
  630. declaringClass.checkModify();
  631. CodeAttribute ca = methodInfo.getCodeAttribute();
  632. CodeIterator iterator = ca.iterator();
  633. Bytecode b = new Bytecode(methodInfo.getConstPool(),
  634. ca.getMaxStack(), ca.getMaxLocals());
  635. b.setStackDepth(ca.getMaxStack());
  636. Javac jv = new Javac(b, declaringClass);
  637. try {
  638. jv.recordParams(getParameterTypes(),
  639. Modifier.isStatic(getModifiers()));
  640. CtClass rtype = getReturnType0();
  641. int varNo = jv.recordReturnType(rtype, true);
  642. boolean isVoid = rtype == CtClass.voidType;
  643. if (isVoid) {
  644. b.addOpcode(Opcode.ACONST_NULL);
  645. b.addAstore(varNo);
  646. jv.compileStmnt(src);
  647. }
  648. else {
  649. b.addStore(varNo, rtype);
  650. jv.compileStmnt(src);
  651. b.addLoad(varNo, rtype);
  652. }
  653. byte[] code = b.get();
  654. ca.setMaxStack(b.getMaxStack());
  655. ca.setMaxLocals(b.getMaxLocals());
  656. while (iterator.hasNext()) {
  657. int pos = iterator.next();
  658. int c = iterator.byteAt(pos);
  659. if (c == Opcode.ARETURN || c == Opcode.IRETURN
  660. || c == Opcode.FRETURN || c == Opcode.LRETURN
  661. || c == Opcode.DRETURN || c == Opcode.RETURN)
  662. iterator.insert(pos, code);
  663. }
  664. }
  665. catch (NotFoundException e) {
  666. throw new CannotCompileException(e);
  667. }
  668. catch (CompileError e) {
  669. throw new CannotCompileException(e);
  670. }
  671. catch (BadBytecode e) {
  672. throw new CannotCompileException(e);
  673. }
  674. }
  675. */
  676. /**
  677. * Adds a catch clause that handles an exception thrown in the
  678. * body. The catch clause must end with a return or throw statement.
  679. *
  680. * @param src the source code representing the catch clause.
  681. * It must be a single statement or block.
  682. * @param exceptionType the type of the exception handled by the
  683. * catch clause.
  684. */
  685. public void addCatch(String src, CtClass exceptionType)
  686. throws CannotCompileException
  687. {
  688. addCatch(src, exceptionType, "$e");
  689. }
  690. /**
  691. * Adds a catch clause that handles an exception thrown in the
  692. * body. The catch clause must end with a return or throw statement.
  693. *
  694. * @param src the source code representing the catch clause.
  695. * It must be a single statement or block.
  696. * @param exceptionType the type of the exception handled by the
  697. * catch clause.
  698. * @param exceptionName the name of the variable containing the
  699. * caught exception, for example,
  700. * <code>$e</code>.
  701. */
  702. public void addCatch(String src, CtClass exceptionType,
  703. String exceptionName)
  704. throws CannotCompileException
  705. {
  706. declaringClass.checkModify();
  707. ConstPool cp = methodInfo.getConstPool();
  708. CodeAttribute ca = methodInfo.getCodeAttribute();
  709. CodeIterator iterator = ca.iterator();
  710. Bytecode b = new Bytecode(cp, ca.getMaxStack(), ca.getMaxLocals());
  711. b.setStackDepth(1);
  712. Javac jv = new Javac(b, declaringClass);
  713. try {
  714. jv.recordParams(getParameterTypes(),
  715. Modifier.isStatic(getModifiers()));
  716. int var = jv.recordVariable(exceptionType, exceptionName);
  717. b.addAstore(var);
  718. jv.compileStmnt(src);
  719. int stack = b.getMaxStack();
  720. int locals = b.getMaxLocals();
  721. if (stack > ca.getMaxStack())
  722. ca.setMaxStack(stack);
  723. if (locals > ca.getMaxLocals())
  724. ca.setMaxLocals(locals);
  725. int len = iterator.getCodeLength();
  726. int pos = iterator.append(b.get());
  727. ca.getExceptionTable().add(getStartPosOfBody(ca), len, len,
  728. cp.addClassInfo(exceptionType));
  729. iterator.append(b.getExceptionTable(), pos);
  730. }
  731. catch (NotFoundException e) {
  732. throw new CannotCompileException(e);
  733. }
  734. catch (CompileError e) {
  735. throw new CannotCompileException(e);
  736. }
  737. }
  738. /* CtConstructor overrides this method.
  739. */
  740. int getStartPosOfBody(CodeAttribute ca) throws CannotCompileException {
  741. return 0;
  742. }
  743. /**
  744. * Inserts bytecode at the specified line in the body.
  745. * It is equivalent to:
  746. *
  747. * <br><code>insertAt(lineNum, true, src)</code>
  748. *
  749. * <br>See this method as well.
  750. *
  751. * @param lineNum the line number. The bytecode is inserted at the
  752. * beginning of the code at the line specified by this
  753. * line number.
  754. * @param src the source code representing the inserted bytecode.
  755. * It must be a single statement or block.
  756. * @return the line number at which the bytecode has been inserted.
  757. *
  758. * @see CtBehavior#insertAt(int,boolean,String)
  759. */
  760. public int insertAt(int lineNum, String src)
  761. throws CannotCompileException
  762. {
  763. return insertAt(lineNum, true, src);
  764. }
  765. /**
  766. * Inserts bytecode at the specified line in the body.
  767. *
  768. * <p>If there is not
  769. * a statement at the specified line, the bytecode might be inserted
  770. * at the line including the first statement after that line specified.
  771. * For example, if there is only a closing brace at that line, the
  772. * bytecode would be inserted at another line below.
  773. * To know exactly where the bytecode will be inserted, call with
  774. * <code>modify</code> set to <code>false</code>.
  775. *
  776. * @param lineNum the line number. The bytecode is inserted at the
  777. * beginning of the code at the line specified by this
  778. * line number.
  779. * @param modify if false, this method does not insert the bytecode.
  780. * It instead only returns the line number at which
  781. * the bytecode would be inserted.
  782. * @param src the source code representing the inserted bytecode.
  783. * It must be a single statement or block.
  784. * If modify is false, the value of src can be null.
  785. * @return the line number at which the bytecode has been inserted.
  786. */
  787. public int insertAt(int lineNum, boolean modify, String src)
  788. throws CannotCompileException
  789. {
  790. CodeAttribute ca = methodInfo.getCodeAttribute();
  791. if (ca == null)
  792. throw new CannotCompileException("no method body");
  793. LineNumberAttribute ainfo
  794. = (LineNumberAttribute)ca.getAttribute(LineNumberAttribute.tag);
  795. if (ainfo == null)
  796. throw new CannotCompileException("no line number info");
  797. LineNumberAttribute.Pc pc = ainfo.toNearPc(lineNum);
  798. lineNum = pc.line;
  799. int index = pc.index;
  800. if (!modify)
  801. return lineNum;
  802. declaringClass.checkModify();
  803. CodeIterator iterator = ca.iterator();
  804. Javac jv = new Javac(declaringClass);
  805. try {
  806. jv.recordLocalVariables(ca, index);
  807. jv.recordParams(getParameterTypes(),
  808. Modifier.isStatic(getModifiers()));
  809. jv.setMaxLocals(ca.getMaxLocals());
  810. jv.compileStmnt(src);
  811. Bytecode b = jv.getBytecode();
  812. int locals = b.getMaxLocals();
  813. int stack = b.getMaxStack();
  814. ca.setMaxLocals(locals);
  815. /* We assume that there is no values in the operand stack
  816. * at the position where the bytecode is inserted.
  817. */
  818. if (stack > ca.getMaxStack())
  819. ca.setMaxStack(stack);
  820. iterator.insert(index, b.get());
  821. iterator.insert(b.getExceptionTable(), index);
  822. return lineNum;
  823. }
  824. catch (NotFoundException e) {
  825. throw new CannotCompileException(e);
  826. }
  827. catch (CompileError e) {
  828. throw new CannotCompileException(e);
  829. }
  830. catch (BadBytecode e) {
  831. throw new CannotCompileException(e);
  832. }
  833. }
  834. }