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

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