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.

CtNewWrappedMethod.java 7.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  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 java.util.Map;
  18. import javassist.CtMethod.ConstParameter;
  19. import javassist.bytecode.AccessFlag;
  20. import javassist.bytecode.BadBytecode;
  21. import javassist.bytecode.Bytecode;
  22. import javassist.bytecode.ClassFile;
  23. import javassist.bytecode.MethodInfo;
  24. import javassist.bytecode.SyntheticAttribute;
  25. import javassist.compiler.JvstCodeGen;
  26. class CtNewWrappedMethod {
  27. private static final String addedWrappedMethod = "_added_m$";
  28. public static CtMethod wrapped(CtClass returnType, String mname,
  29. CtClass[] parameterTypes,
  30. CtClass[] exceptionTypes,
  31. CtMethod body, ConstParameter constParam,
  32. CtClass declaring)
  33. throws CannotCompileException
  34. {
  35. CtMethod mt = new CtMethod(returnType, mname, parameterTypes,
  36. declaring);
  37. mt.setModifiers(body.getModifiers());
  38. try {
  39. mt.setExceptionTypes(exceptionTypes);
  40. }
  41. catch (NotFoundException e) {
  42. throw new CannotCompileException(e);
  43. }
  44. Bytecode code = makeBody(declaring, declaring.getClassFile2(), body,
  45. parameterTypes, returnType, constParam);
  46. MethodInfo minfo = mt.getMethodInfo2();
  47. minfo.setCodeAttribute(code.toCodeAttribute());
  48. // a stack map has been already created.
  49. return mt;
  50. }
  51. static Bytecode makeBody(CtClass clazz, ClassFile classfile,
  52. CtMethod wrappedBody,
  53. CtClass[] parameters,
  54. CtClass returnType,
  55. ConstParameter cparam)
  56. throws CannotCompileException
  57. {
  58. boolean isStatic = Modifier.isStatic(wrappedBody.getModifiers());
  59. Bytecode code = new Bytecode(classfile.getConstPool(), 0, 0);
  60. int stacksize = makeBody0(clazz, classfile, wrappedBody, isStatic,
  61. parameters, returnType, cparam, code);
  62. code.setMaxStack(stacksize);
  63. code.setMaxLocals(isStatic, parameters, 0);
  64. return code;
  65. }
  66. /* The generated method body does not need a stack map table
  67. * because it does not contain a branch instruction.
  68. */
  69. protected static int makeBody0(CtClass clazz, ClassFile classfile,
  70. CtMethod wrappedBody,
  71. boolean isStatic, CtClass[] parameters,
  72. CtClass returnType, ConstParameter cparam,
  73. Bytecode code)
  74. throws CannotCompileException
  75. {
  76. if (!(clazz instanceof CtClassType))
  77. throw new CannotCompileException("bad declaring class"
  78. + clazz.getName());
  79. if (!isStatic)
  80. code.addAload(0);
  81. int stacksize = compileParameterList(code, parameters,
  82. (isStatic ? 0 : 1));
  83. int stacksize2;
  84. String desc;
  85. if (cparam == null) {
  86. stacksize2 = 0;
  87. desc = ConstParameter.defaultDescriptor();
  88. }
  89. else {
  90. stacksize2 = cparam.compile(code);
  91. desc = cparam.descriptor();
  92. }
  93. checkSignature(wrappedBody, desc);
  94. String bodyname;
  95. try {
  96. bodyname = addBodyMethod((CtClassType)clazz, classfile,
  97. wrappedBody);
  98. /* if an exception is thrown below, the method added above
  99. * should be removed. (future work :<)
  100. */
  101. }
  102. catch (BadBytecode e) {
  103. throw new CannotCompileException(e);
  104. }
  105. if (isStatic)
  106. code.addInvokestatic(Bytecode.THIS, bodyname, desc);
  107. else
  108. code.addInvokespecial(Bytecode.THIS, bodyname, desc);
  109. compileReturn(code, returnType); // consumes 2 stack entries
  110. if (stacksize < stacksize2 + 2)
  111. stacksize = stacksize2 + 2;
  112. return stacksize;
  113. }
  114. private static void checkSignature(CtMethod wrappedBody,
  115. String descriptor)
  116. throws CannotCompileException
  117. {
  118. if (!descriptor.equals(wrappedBody.getMethodInfo2().getDescriptor()))
  119. throw new CannotCompileException(
  120. "wrapped method with a bad signature: "
  121. + wrappedBody.getDeclaringClass().getName()
  122. + '.' + wrappedBody.getName());
  123. }
  124. private static String addBodyMethod(CtClassType clazz,
  125. ClassFile classfile,
  126. CtMethod src)
  127. throws BadBytecode, CannotCompileException
  128. {
  129. Map<CtMethod,String> bodies = clazz.getHiddenMethods();
  130. String bodyname = bodies.get(src);
  131. if (bodyname == null) {
  132. do {
  133. bodyname = addedWrappedMethod + clazz.getUniqueNumber();
  134. } while (classfile.getMethod(bodyname) != null);
  135. ClassMap map = new ClassMap();
  136. map.put(src.getDeclaringClass().getName(), clazz.getName());
  137. MethodInfo body = new MethodInfo(classfile.getConstPool(),
  138. bodyname, src.getMethodInfo2(),
  139. map);
  140. int acc = body.getAccessFlags();
  141. body.setAccessFlags(AccessFlag.setPrivate(acc));
  142. body.addAttribute(new SyntheticAttribute(classfile.getConstPool()));
  143. // a stack map is copied. rebuilding it is not needed.
  144. classfile.addMethod(body);
  145. bodies.put(src, bodyname);
  146. CtMember.Cache cache = clazz.hasMemberCache();
  147. if (cache != null)
  148. cache.addMethod(new CtMethod(body, clazz));
  149. }
  150. return bodyname;
  151. }
  152. /* compileParameterList() returns the stack size used
  153. * by the produced code.
  154. *
  155. * @param regno the index of the local variable in which
  156. * the first argument is received.
  157. * (0: static method, 1: regular method.)
  158. */
  159. static int compileParameterList(Bytecode code,
  160. CtClass[] params, int regno) {
  161. return JvstCodeGen.compileParameterList(code, params, regno);
  162. }
  163. /*
  164. * The produced codes cosume 1 or 2 stack entries.
  165. */
  166. private static void compileReturn(Bytecode code, CtClass type) {
  167. if (type.isPrimitive()) {
  168. CtPrimitiveType pt = (CtPrimitiveType)type;
  169. if (pt != CtClass.voidType) {
  170. String wrapper = pt.getWrapperName();
  171. code.addCheckcast(wrapper);
  172. code.addInvokevirtual(wrapper, pt.getGetMethodName(),
  173. pt.getGetMethodDescriptor());
  174. }
  175. code.addOpcode(pt.getReturnOp());
  176. }
  177. else {
  178. code.addCheckcast(type);
  179. code.addOpcode(Bytecode.ARETURN);
  180. }
  181. }
  182. }