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 6.9KB

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