Method.java 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383
  1. // Copyright (c) 1997, 2007 Per M.A. Bothner.
  2. // This is free software; for terms and warranty disclaimer see ./COPYING.
  3. package gnu.bytecode;
  4. import java.io.*;
  5. /**
  6. * Represents a method in a <code>ClassType</code>.
  7. * <p>
  8. * A <code>Method</code> contain a <code>CodeAttr</code> object;
  9. * the interface for generating bytecode instructions is primarily
  10. * in <code>CodeAttr</code>.
  11. * <p>
  12. * All the methods whose name start with <code>compile_</code> are
  13. * deprecated, and should not be used; use the methods
  14. * in <code>CodeAttr</code>instead.
  15. */
  16. public class Method implements AttrContainer, Member {
  17. private String name;
  18. Type[] arg_types;
  19. Type return_type;
  20. int access_flags;
  21. int name_index; /* Index in constant table, or 0 if un-assigned */
  22. int signature_index; /* Index in constant table, or 0 if un-assigned */
  23. Method next;
  24. ClassType classfile;
  25. CodeAttr code;
  26. /* #ifdef JAVA8 */
  27. java.lang.reflect.Executable rmethod;
  28. /* #else */
  29. // java.lang.reflect.AccessibleObject rmethod;
  30. /* #endif */
  31. Attribute attributes;
  32. public final Attribute getAttributes() { return attributes; }
  33. public final void setAttributes (Attribute attributes)
  34. { this.attributes = attributes; }
  35. ExceptionsAttr exceptions;
  36. public final ExceptionsAttr getExceptionAttr() { return exceptions; }
  37. public void setExceptions(short[] exn_indices) {
  38. if (exceptions == null)
  39. exceptions = new ExceptionsAttr(this);
  40. exceptions.setExceptions(exn_indices, classfile);
  41. }
  42. public void setExceptions(ClassType[] exn_types) {
  43. if (exceptions == null)
  44. exceptions = new ExceptionsAttr(this);
  45. exceptions.setExceptions(exn_types);
  46. }
  47. public final CodeAttr getCode () { return code; }
  48. private Method() {
  49. }
  50. /** Make a generic "clone" method.
  51. * This is used for array types.
  52. */
  53. static Method makeCloneMethod(Type returnType) {
  54. Method method = new Method();
  55. method.name = "clone";
  56. method.access_flags = Access.PUBLIC;
  57. method.arg_types = Type.typeArray0;
  58. method.return_type = returnType;
  59. method.classfile = Type.objectType;
  60. return method;
  61. }
  62. /** A copy constructor, except you can override the declaring class.
  63. * This can be used to improve binary compatibility by emitting method
  64. * references where the declared class is the type of the receiver.
  65. */
  66. public Method(Method base, ClassType clas) {
  67. arg_types = base.arg_types;
  68. return_type = base.return_type;
  69. name = base.name;
  70. access_flags = base.access_flags;
  71. classfile = clas;
  72. }
  73. Method(ClassType clfile, int flags) {
  74. if (clfile.last_method == null)
  75. clfile.methods = this;
  76. else
  77. clfile.last_method.next = this;
  78. clfile.last_method = this;
  79. clfile.methods_count++;
  80. access_flags = flags;
  81. classfile = clfile;
  82. }
  83. public final void setStaticFlag(boolean is_static) {
  84. if (is_static)
  85. access_flags |= Access.STATIC;
  86. else
  87. access_flags ^= ~Access.STATIC;
  88. }
  89. public final boolean getStaticFlag() {
  90. return (access_flags & Access.STATIC) != 0;
  91. }
  92. public final boolean isAbstract() {
  93. return (access_flags & Access.ABSTRACT) != 0;
  94. }
  95. public final boolean isNative() {
  96. return (access_flags & Access.NATIVE) != 0;
  97. }
  98. public int getModifiers() {
  99. return access_flags;
  100. }
  101. public void setModifiers(int modifiers) {
  102. access_flags = modifiers;
  103. }
  104. public final ConstantPool getConstants() {
  105. return classfile.constants;
  106. }
  107. public Scope pushScope() {
  108. prepareCode(0);
  109. return code.pushScope();
  110. }
  111. /** True if control could reach here. */
  112. public final boolean reachableHere () { return code.reachableHere(); }
  113. public Scope popScope() { return code.popScope(); }
  114. /**
  115. * Allocate slots for a local variable (or parameter).
  116. * @param local the variable we need to allocate
  117. */
  118. @Deprecated public void allocate_local(Variable local) {
  119. local.allocateLocal(code);
  120. }
  121. /** Allocate a Code attribute, and prepare to generate code.
  122. * Most code generators should use the startCode convenience method. */
  123. public void initCode() {
  124. if (classfile.constants == null)
  125. classfile.constants = new ConstantPool();
  126. prepareCode(0);
  127. code.sourceDbgExt = classfile.sourceDbgExt;
  128. code.noteParamTypes();
  129. code.pushScope();
  130. }
  131. /**
  132. * @deprecated Use startCode instead
  133. */
  134. public void init_param_slots(){
  135. startCode();
  136. }
  137. /** Recommended method to create a new CodeAttr for this Method. */
  138. public CodeAttr startCode() {
  139. initCode();
  140. code.addParamLocals();
  141. return code;
  142. }
  143. void kill_local(Variable var) { var.freeLocal(code); }
  144. /** Method that must be called before we generate any instructions.
  145. * Set so there is room for at least max_size bytes of code.
  146. */
  147. void prepareCode(int max_size) {
  148. if (code == null)
  149. code = new CodeAttr(this);
  150. code.reserve(max_size);
  151. }
  152. // This method should be called before we generate code for
  153. // an instruction (or sequence).
  154. // An upper bound of the intruction length is max_size.
  155. // deprecated!
  156. void instruction_start_hook(int max_size) {
  157. prepareCode(max_size);
  158. }
  159. final Type pop_stack_type () { return code.popType(); }
  160. final void push_stack_type (Type type) { code.pushType(type); }
  161. public void compile_checkcast(Type type) {
  162. code.emitCheckcast(type);
  163. }
  164. public void maybe_compile_checkcast(Type type) {
  165. Type stack_type = code.topType();
  166. if (type != stack_type) // FIXME rather simple-minded, but safe.
  167. code.emitCheckcast(type);
  168. }
  169. /**
  170. * Comple code to push the contents of a local variable onto the statck.
  171. * @param var The variable whose contents we want to push.
  172. * @deprecated
  173. */
  174. public void push_var(Variable var) { code.emitLoad (var); }
  175. @Deprecated
  176. public void compile_push_value(Variable var) { code.emitLoad(var); }
  177. @Deprecated public void compile_store_value(Variable var) {
  178. code.emitStore(var);
  179. }
  180. public void compile_push_this() {
  181. code.emitPushThis();
  182. }
  183. void write (DataOutputStream dstr, ClassType classfile)
  184. throws java.io.IOException {
  185. dstr.writeShort (access_flags);
  186. dstr.writeShort (name_index);
  187. dstr.writeShort (signature_index);
  188. Attribute.writeAll(this, dstr);
  189. }
  190. public static String makeSignature(Type arg_types[], Type return_type) {
  191. /* #ifdef JAVA5 */
  192. StringBuilder buf = new StringBuilder(100);
  193. /* #else */
  194. // StringBuffer buf = new StringBuffer(100);
  195. /* #endif */
  196. int args_count = arg_types.length;
  197. buf.append('(');
  198. for (int i = 0; i < args_count; i++)
  199. buf.append (arg_types[i].getSignature());
  200. buf.append(')');
  201. buf.append(return_type.getSignature());
  202. return buf.toString();
  203. }
  204. public static String makeGenericSignature(Type arg_types[],
  205. Type return_type) {
  206. StringBuilder buf = new StringBuilder(100);
  207. int args_count = arg_types.length;
  208. buf.append('(');
  209. for (int i = 0; i < args_count; i++)
  210. buf.append (arg_types[i].getMaybeGenericSignature());
  211. buf.append(')');
  212. buf.append(return_type.getMaybeGenericSignature());
  213. return buf.toString();
  214. }
  215. String signature;
  216. public String getSignature() {
  217. if (signature == null)
  218. signature = makeSignature(arg_types, return_type);
  219. return signature;
  220. }
  221. public void setSignature(String signature) {
  222. int len = signature.length();
  223. if (len < 3 || signature.charAt(0) != '(')
  224. throw new ClassFormatError("bad method signature");
  225. int pos = 1;
  226. java.util.Stack<Type> types = new java.util.Stack<Type>();
  227. for (;;) {
  228. int arg_sig_len = Type.signatureLength(signature, pos);
  229. if (arg_sig_len < 0) {
  230. if (pos < len && signature.charAt(pos) == ')')
  231. break;
  232. throw new ClassFormatError("bad method signature");
  233. }
  234. Type arg_type = Type.signatureToType(signature, pos, arg_sig_len);
  235. types.push(arg_type);
  236. pos += arg_sig_len;
  237. }
  238. arg_types = new Type[types.size()];
  239. for (int i = types.size(); --i >= 0; )
  240. arg_types[i] = (Type) types.pop();
  241. return_type = Type.signatureToType(signature, pos+1, len-pos-1);
  242. }
  243. public void setSignature(int signature_index) {
  244. CpoolUtf8 sigConstant = (CpoolUtf8)
  245. getConstants().getForced(signature_index, ConstantPool.UTF8);
  246. this.signature_index = signature_index;
  247. setSignature(sigConstant.string);
  248. }
  249. public <T extends java.lang.annotation.Annotation>
  250. T getAnnotation(Class<T> clas) {
  251. T ann = RuntimeAnnotationsAttr.getAnnotation(this, clas);
  252. if (ann != null)
  253. return ann;
  254. return rmethod == null ? null : rmethod.getAnnotation(clas);
  255. }
  256. void assignConstants() {
  257. ConstantPool constants = getConstants();
  258. if (name_index == 0 && name != null)
  259. name_index = constants.addUtf8(name).index;
  260. String signature = getSignature();
  261. String genericSignature = makeGenericSignature(arg_types, return_type);
  262. if (signature_index == 0)
  263. signature_index = constants.addUtf8(signature).index;
  264. if (genericSignature != null && ! genericSignature.equals(signature)) {
  265. SignatureAttr attr = new SignatureAttr(genericSignature);
  266. attr.addToFrontOf(this);
  267. }
  268. Attribute.assignConstants(this, classfile);
  269. }
  270. public ClassType getDeclaringClass() { return classfile; }
  271. public final Type getReturnType() { return return_type; }
  272. public final void setReturnType(Type type) { return_type = type; }
  273. public final Type[] getParameterTypes() { return arg_types; }
  274. public final ClassType[] getExceptions()
  275. {
  276. if (exceptions == null) return null;
  277. return exceptions.getExceptions();
  278. }
  279. public final String getName() {
  280. return name;
  281. }
  282. public final void setName(String name) {
  283. this.name = name;
  284. }
  285. public final void setName(int name_index) {
  286. if (name_index <= 0)
  287. name = null;
  288. else {
  289. CpoolUtf8 nameConstant = (CpoolUtf8)
  290. getConstants().getForced(name_index, ConstantPool.UTF8);
  291. name = nameConstant.string;
  292. }
  293. this.name_index = name_index;
  294. }
  295. public final Method getNext() {
  296. return next;
  297. }
  298. public void listParameters(StringBuffer sbuf) {
  299. int args_count = arg_types.length;
  300. sbuf.append('(');
  301. for (int i = 0; i < args_count; i++) {
  302. if (i > 0)
  303. sbuf.append(',');
  304. sbuf.append (arg_types[i].getName());
  305. }
  306. sbuf.append(')');
  307. }
  308. public String toString() {
  309. StringBuffer sbuf = new StringBuffer(100);
  310. ClassType declaring = getDeclaringClass();
  311. sbuf.append(declaring != null ? declaring.getName() : "???");
  312. sbuf.append('.');
  313. sbuf.append(name);
  314. if (arg_types != null) {
  315. listParameters(sbuf);
  316. sbuf.append(return_type.getName());
  317. }
  318. return sbuf.toString();
  319. }
  320. public void cleanupAfterCompilation() {
  321. attributes = null;
  322. exceptions = null;
  323. code = null;
  324. }
  325. };