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.

AccessorMaker.java 9.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
  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.compiler;
  16. import javassist.*;
  17. import javassist.bytecode.*;
  18. import java.util.HashMap;
  19. /**
  20. * AccessorMaker maintains accessors to private members of an enclosing
  21. * class. It is necessary for compiling a method in an inner class.
  22. */
  23. public class AccessorMaker {
  24. private CtClass clazz;
  25. private int uniqueNumber;
  26. private HashMap accessors;
  27. static final String lastParamType = "javassist.runtime.Inner";
  28. public AccessorMaker(CtClass c) {
  29. clazz = c;
  30. uniqueNumber = 1;
  31. accessors = new HashMap();
  32. }
  33. public String getConstructor(CtClass c, String desc, MethodInfo orig)
  34. throws CompileError
  35. {
  36. String key = "<init>:" + desc;
  37. String consDesc = (String)accessors.get(key);
  38. if (consDesc != null)
  39. return consDesc; // already exists.
  40. consDesc = Descriptor.appendParameter(lastParamType, desc);
  41. ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
  42. try {
  43. ConstPool cp = cf.getConstPool();
  44. ClassPool pool = clazz.getClassPool();
  45. MethodInfo minfo
  46. = new MethodInfo(cp, MethodInfo.nameInit, consDesc);
  47. minfo.setAccessFlags(0);
  48. minfo.addAttribute(new SyntheticAttribute(cp));
  49. ExceptionsAttribute ea = orig.getExceptionsAttribute();
  50. if (ea != null)
  51. minfo.addAttribute(ea.copy(cp, null));
  52. CtClass[] params = Descriptor.getParameterTypes(desc, pool);
  53. Bytecode code = new Bytecode(cp);
  54. code.addAload(0);
  55. int regno = 1;
  56. for (int i = 0; i < params.length; ++i)
  57. regno += code.addLoad(regno, params[i]);
  58. code.setMaxLocals(regno + 1); // the last parameter is added.
  59. code.addInvokespecial(clazz, MethodInfo.nameInit, desc);
  60. code.addReturn(null);
  61. minfo.setCodeAttribute(code.toCodeAttribute());
  62. cf.addMethod(minfo);
  63. }
  64. catch (CannotCompileException e) {
  65. throw new CompileError(e);
  66. }
  67. catch (NotFoundException e) {
  68. throw new CompileError(e);
  69. }
  70. accessors.put(key, consDesc);
  71. return consDesc;
  72. }
  73. /**
  74. * Returns the name of the method for accessing a private method.
  75. *
  76. * @param name the name of the private method.
  77. * @param desc the descriptor of the private method.
  78. * @param accDesc the descriptor of the accessor method. The first
  79. * parameter type is <code>clazz</code>.
  80. * If the private method is static,
  81. * <code>accDesc<code> must be equal to <code>desc</code>.
  82. *
  83. * @param orig the method info of the private method.
  84. * @return
  85. */
  86. public String getMethodAccessor(String name, String desc, String accDesc,
  87. MethodInfo orig)
  88. throws CompileError
  89. {
  90. String key = name + ":" + desc;
  91. String accName = (String)accessors.get(key);
  92. if (accName != null)
  93. return accName; // already exists.
  94. ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
  95. accName = findAccessorName(cf);
  96. try {
  97. ConstPool cp = cf.getConstPool();
  98. ClassPool pool = clazz.getClassPool();
  99. MethodInfo minfo
  100. = new MethodInfo(cp, accName, accDesc);
  101. minfo.setAccessFlags(AccessFlag.STATIC);
  102. minfo.addAttribute(new SyntheticAttribute(cp));
  103. ExceptionsAttribute ea = orig.getExceptionsAttribute();
  104. if (ea != null)
  105. minfo.addAttribute(ea.copy(cp, null));
  106. CtClass[] params = Descriptor.getParameterTypes(accDesc, pool);
  107. int regno = 0;
  108. Bytecode code = new Bytecode(cp);
  109. for (int i = 0; i < params.length; ++i)
  110. regno += code.addLoad(regno, params[i]);
  111. code.setMaxLocals(regno);
  112. if (desc == accDesc)
  113. code.addInvokestatic(clazz, name, desc);
  114. else
  115. code.addInvokevirtual(clazz, name, desc);
  116. code.addReturn(Descriptor.getReturnType(desc, pool));
  117. minfo.setCodeAttribute(code.toCodeAttribute());
  118. cf.addMethod(minfo);
  119. }
  120. catch (CannotCompileException e) {
  121. throw new CompileError(e);
  122. }
  123. catch (NotFoundException e) {
  124. throw new CompileError(e);
  125. }
  126. accessors.put(key, accName);
  127. return accName;
  128. }
  129. /**
  130. * Returns the method_info representing the added getter.
  131. */
  132. public MethodInfo getFieldGetter(FieldInfo finfo, boolean is_static)
  133. throws CompileError
  134. {
  135. String fieldName = finfo.getName();
  136. String key = fieldName + ":getter";
  137. Object res = accessors.get(key);
  138. if (res != null)
  139. return (MethodInfo)res; // already exists.
  140. ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
  141. String accName = findAccessorName(cf);
  142. try {
  143. ConstPool cp = cf.getConstPool();
  144. ClassPool pool = clazz.getClassPool();
  145. String fieldType = finfo.getDescriptor();
  146. String accDesc;
  147. if (is_static)
  148. accDesc = "()" + fieldType;
  149. else
  150. accDesc = "(" + Descriptor.of(clazz) + ")" + fieldType;
  151. MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
  152. minfo.setAccessFlags(AccessFlag.STATIC);
  153. minfo.addAttribute(new SyntheticAttribute(cp));
  154. Bytecode code = new Bytecode(cp);
  155. if (is_static) {
  156. code.addGetstatic(Bytecode.THIS, fieldName, fieldType);
  157. }
  158. else {
  159. code.addAload(0);
  160. code.addGetfield(Bytecode.THIS, fieldName, fieldType);
  161. code.setMaxLocals(1);
  162. }
  163. code.addReturn(Descriptor.toCtClass(fieldType, pool));
  164. minfo.setCodeAttribute(code.toCodeAttribute());
  165. cf.addMethod(minfo);
  166. accessors.put(key, minfo);
  167. return minfo;
  168. }
  169. catch (CannotCompileException e) {
  170. throw new CompileError(e);
  171. }
  172. catch (NotFoundException e) {
  173. throw new CompileError(e);
  174. }
  175. }
  176. /**
  177. * Returns the method_info representing the added setter.
  178. */
  179. public MethodInfo getFieldSetter(FieldInfo finfo, boolean is_static)
  180. throws CompileError
  181. {
  182. String fieldName = finfo.getName();
  183. String key = fieldName + ":setter";
  184. Object res = accessors.get(key);
  185. if (res != null)
  186. return (MethodInfo)res; // already exists.
  187. ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
  188. String accName = findAccessorName(cf);
  189. try {
  190. ConstPool cp = cf.getConstPool();
  191. ClassPool pool = clazz.getClassPool();
  192. String fieldType = finfo.getDescriptor();
  193. String accDesc;
  194. if (is_static)
  195. accDesc = "(" + fieldType + ")V";
  196. else
  197. accDesc = "(" + Descriptor.of(clazz) + fieldType + ")V";
  198. MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
  199. minfo.setAccessFlags(AccessFlag.STATIC);
  200. minfo.addAttribute(new SyntheticAttribute(cp));
  201. Bytecode code = new Bytecode(cp);
  202. int reg;
  203. if (is_static) {
  204. reg = code.addLoad(0, Descriptor.toCtClass(fieldType, pool));
  205. code.addPutstatic(Bytecode.THIS, fieldName, fieldType);
  206. }
  207. else {
  208. code.addAload(0);
  209. reg = code.addLoad(1, Descriptor.toCtClass(fieldType, pool))
  210. + 1;
  211. code.addPutfield(Bytecode.THIS, fieldName, fieldType);
  212. }
  213. code.addReturn(null);
  214. code.setMaxLocals(reg);
  215. minfo.setCodeAttribute(code.toCodeAttribute());
  216. cf.addMethod(minfo);
  217. accessors.put(key, minfo);
  218. return minfo;
  219. }
  220. catch (CannotCompileException e) {
  221. throw new CompileError(e);
  222. }
  223. catch (NotFoundException e) {
  224. throw new CompileError(e);
  225. }
  226. }
  227. private String findAccessorName(ClassFile cf) {
  228. String accName;
  229. do {
  230. accName = "access$" + uniqueNumber++;
  231. } while (cf.getMethod(accName) != null);
  232. return accName;
  233. }
  234. }