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

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