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.2KB

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