Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

CtNewWrappedMethod.java 7.5KB

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