001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.bytecode;
031:
032: import com.caucho.log.Log;
033:
034: import java.io.ByteArrayInputStream;
035: import java.io.IOException;
036: import java.lang.reflect.*;
037: import java.util.ArrayList;
038: import java.util.logging.Level;
039: import java.util.logging.Logger;
040:
041: /**
042: * Represents a java field.
043: */
044: public class JavaMethod extends JMethod {
045: static private final Logger log = Log.open(JavaMethod.class);
046:
047: private static final JClass[] NULL_CLASS = new JClass[0];
048:
049: private JavaClassLoader _loader;
050:
051: private JavaClass _jClass;
052:
053: private int _accessFlags;
054: private String _name;
055: private String _descriptor;
056: private JClass[] _exceptions = NULL_CLASS;
057: private int _line = -1;
058:
059: private ArrayList<Attribute> _attributes = new ArrayList<Attribute>();
060:
061: private JavaAnnotation[] _annotations;
062:
063: private boolean _isWrite;
064:
065: public JavaMethod(JavaClassLoader loader) {
066: _loader = loader;
067: }
068:
069: public JavaMethod() {
070: }
071:
072: /**
073: * Sets the JavaClass.
074: */
075: public void setJavaClass(JavaClass jClass) {
076: _jClass = jClass;
077: }
078:
079: public void setWrite(boolean isWrite) {
080: _isWrite = isWrite;
081: }
082:
083: /**
084: * Sets the name.
085: */
086: public void setName(String name) {
087: _name = name;
088:
089: if (_jClass != null)
090: _jClass.getConstantPool().addUTF8(name);
091: }
092:
093: /**
094: * Gets the name.
095: */
096: public String getName() {
097: return _name;
098: }
099:
100: /**
101: * Returns the line number.
102: */
103: public int getLine() {
104: if (_line >= 0)
105: return _line;
106:
107: Attribute attr = getAttribute("LineNumberTable");
108:
109: if (attr == null) {
110: _line = 0;
111: return _line;
112: }
113:
114: _line = 0;
115: return _line;
116: }
117:
118: /**
119: * Returns the class loader.
120: */
121: public JavaClassLoader getClassLoader() {
122: return _loader;
123: }
124:
125: /**
126: * Sets the access flags
127: */
128: public void setAccessFlags(int flags) {
129: _accessFlags = flags;
130: }
131:
132: /**
133: * Gets the access flags
134: */
135: public int getAccessFlags() {
136: return _accessFlags;
137: }
138:
139: /**
140: * Returns true for a final method
141: */
142: public boolean isFinal() {
143: return Modifier.isFinal(getAccessFlags());
144: }
145:
146: /**
147: * Returns true for a public method
148: */
149: public boolean isPublic() {
150: return Modifier.isPublic(getAccessFlags());
151: }
152:
153: /**
154: * Returns true for a protected method
155: */
156: public boolean isProtected() {
157: return Modifier.isProtected(getAccessFlags());
158: }
159:
160: /**
161: * Returns true for a private method
162: */
163: public boolean isPrivate() {
164: return Modifier.isPrivate(getAccessFlags());
165: }
166:
167: /**
168: * Returns true for an abstract method
169: */
170: public boolean isAbstract() {
171: return Modifier.isAbstract(getAccessFlags());
172: }
173:
174: /**
175: * Returns true for a static method
176: */
177: public boolean isStatic() {
178: return Modifier.isStatic(getAccessFlags());
179: }
180:
181: /**
182: * Sets the descriptor.
183: */
184: public void setDescriptor(String descriptor) {
185: _descriptor = descriptor;
186:
187: if (_jClass != null)
188: _jClass.getConstantPool().addUTF8(descriptor);
189: }
190:
191: /**
192: * Gets the descriptor.
193: */
194: public String getDescriptor() {
195: return _descriptor;
196: }
197:
198: /**
199: * Returns the declaring class.
200: */
201: public JClass getDeclaringClass() {
202: return _jClass;
203: }
204:
205: /**
206: * Returns the return types.
207: */
208: public JClass getReturnType() {
209: String descriptor = getDescriptor();
210:
211: int i = descriptor.lastIndexOf(')');
212:
213: return getClassLoader().descriptorToClass(descriptor, i + 1);
214: }
215:
216: /**
217: * Returns the return type.
218: */
219: public JType getGenericReturnType() {
220: SignatureAttribute sigAttr = (SignatureAttribute) getAttribute("Signature");
221:
222: if (sigAttr != null) {
223: String sig = sigAttr.getSignature();
224:
225: int t = sig.lastIndexOf(')');
226:
227: return _loader.parseParameterizedType(sig.substring(t + 1));
228: }
229:
230: return getReturnType();
231: }
232:
233: /**
234: * Returns the parameter types.
235: */
236: public JClass[] getParameterTypes() {
237: String descriptor = getDescriptor();
238:
239: ArrayList<JClass> typeList = new ArrayList<JClass>();
240:
241: int i = 0;
242: while ((i = nextDescriptor(descriptor, i)) >= 0) {
243: typeList.add(getClassLoader().descriptorToClass(descriptor,
244: i));
245: }
246:
247: JClass[] types = new JClass[typeList.size()];
248:
249: typeList.toArray(types);
250:
251: return types;
252: }
253:
254: private int nextDescriptor(String name, int i) {
255: switch (name.charAt(i)) {
256: case ')':
257: return -1;
258:
259: case '(':
260: case 'V':
261: case 'Z':
262: case 'C':
263: case 'B':
264: case 'S':
265: case 'I':
266: case 'J':
267: case 'F':
268: case 'D':
269: i += 1;
270: break;
271:
272: case '[':
273: return nextDescriptor(name, i + 1);
274:
275: case 'L': {
276: int tail = name.indexOf(';', i);
277:
278: if (tail < 0)
279: throw new IllegalStateException();
280:
281: i = tail + 1;
282: }
283: break;
284:
285: default:
286: throw new UnsupportedOperationException(name.substring(i));
287: }
288:
289: if (name.length() <= i)
290: return -1;
291: else if (name.charAt(i) == ')')
292: return -1;
293: else
294: return i;
295: }
296:
297: /**
298: * Sets the exception types
299: */
300: public void setExceptionTypes(JClass[] exceptions) {
301: _exceptions = exceptions;
302: }
303:
304: /**
305: * Returns the exception types.
306: */
307: public JClass[] getExceptionTypes() {
308: return _exceptions;
309: }
310:
311: /**
312: * Adds an attribute.
313: */
314: public void addAttribute(Attribute attr) {
315: _attributes.add(attr);
316: }
317:
318: public CodeWriterAttribute createCodeWriter() {
319: CodeWriterAttribute code = new CodeWriterAttribute(_jClass);
320:
321: _attributes.add(code);
322:
323: return code;
324: }
325:
326: /**
327: * Removes an attribute.
328: */
329: public Attribute removeAttribute(String name) {
330: for (int i = _attributes.size() - 1; i >= 0; i--) {
331: Attribute attr = _attributes.get(i);
332:
333: if (attr.getName().equals(name)) {
334: _attributes.remove(i);
335: return attr;
336: }
337: }
338:
339: return null;
340: }
341:
342: /**
343: * Returns the attribute.
344: */
345: public ArrayList<Attribute> getAttributes() {
346: return _attributes;
347: }
348:
349: /**
350: * Returns the attribute.
351: */
352: public Attribute getAttribute(String name) {
353: for (int i = _attributes.size() - 1; i >= 0; i--) {
354: Attribute attr = _attributes.get(i);
355:
356: if (attr.getName().equals(name))
357: return attr;
358: }
359:
360: return null;
361: }
362:
363: /**
364: * Returns the declared annotations.
365: */
366: public JAnnotation[] getDeclaredAnnotations() {
367: if (_annotations == null) {
368: Attribute attr = getAttribute("RuntimeVisibleAnnotations");
369:
370: if (attr instanceof OpaqueAttribute) {
371: byte[] buffer = ((OpaqueAttribute) attr).getValue();
372:
373: try {
374: ByteArrayInputStream is = new ByteArrayInputStream(
375: buffer);
376:
377: ConstantPool cp = _jClass.getConstantPool();
378:
379: _annotations = JavaAnnotation.parseAnnotations(is,
380: cp, getClassLoader());
381: } catch (IOException e) {
382: log.log(Level.FINER, e.toString(), e);
383: }
384: }
385:
386: if (_annotations == null) {
387: _annotations = new JavaAnnotation[0];
388: }
389: }
390:
391: return _annotations;
392: }
393:
394: /**
395: * Returns the code attribute.
396: */
397: public CodeAttribute getCode() {
398: for (int i = 0; i < _attributes.size(); i++) {
399: Attribute attr = _attributes.get(i);
400:
401: if (attr instanceof CodeAttribute)
402: return (CodeAttribute) attr;
403: }
404:
405: return null;
406: }
407:
408: /**
409: * Create the code attribute.
410: */
411: public CodeAttribute createCode() {
412: CodeAttribute code = new CodeAttribute();
413:
414: for (int i = 0; i < _attributes.size(); i++) {
415: Attribute attr = _attributes.get(i);
416:
417: if (attr instanceof CodeAttribute)
418: return (CodeAttribute) attr;
419: }
420:
421: return null;
422: }
423:
424: /**
425: * Writes the field to the output.
426: */
427: public void write(ByteCodeWriter out) throws IOException {
428: out.writeShort(_accessFlags);
429: out.writeUTF8Const(_name);
430: out.writeUTF8Const(_descriptor);
431:
432: out.writeShort(_attributes.size());
433: for (int i = 0; i < _attributes.size(); i++) {
434: Attribute attr = _attributes.get(i);
435:
436: attr.write(out);
437: }
438: }
439:
440: /**
441: * exports the method.
442: */
443: public JavaMethod export(JavaClass source, JavaClass target) {
444: JavaMethod method = new JavaMethod(_loader);
445: method.setName(_name);
446: method.setDescriptor(_descriptor);
447: method.setAccessFlags(_accessFlags);
448:
449: target.getConstantPool().addUTF8(_name);
450: target.getConstantPool().addUTF8(_descriptor);
451:
452: for (int i = 0; i < _attributes.size(); i++) {
453: Attribute attr = _attributes.get(i);
454:
455: method.addAttribute(attr.export(source, target));
456: }
457:
458: return method;
459: }
460:
461: /**
462: * Concatenates the method.
463: */
464: public void concatenate(JavaMethod tail) {
465: CodeAttribute codeAttr = getCode();
466: CodeAttribute tailCodeAttr = tail.getCode();
467:
468: byte[] code = codeAttr.getCode();
469: byte[] tailCode = tailCodeAttr.getCode();
470:
471: int codeLength = code.length;
472:
473: if ((code[codeLength - 1] & 0xff) == CodeVisitor.RETURN)
474: codeLength = codeLength - 1;
475:
476: byte[] newCode = new byte[codeLength + tailCode.length];
477: System.arraycopy(code, 0, newCode, 0, codeLength);
478: System.arraycopy(tailCode, 0, newCode, codeLength,
479: tailCode.length);
480:
481: codeAttr.setCode(newCode);
482:
483: if (codeAttr.getMaxStack() < tailCodeAttr.getMaxStack())
484: codeAttr.setMaxStack(tailCodeAttr.getMaxStack());
485:
486: if (codeAttr.getMaxLocals() < tailCodeAttr.getMaxLocals())
487: codeAttr.setMaxLocals(tailCodeAttr.getMaxLocals());
488:
489: ArrayList<CodeAttribute.ExceptionItem> exns = tailCodeAttr
490: .getExceptions();
491: for (int i = 0; i < exns.size(); i++) {
492: CodeAttribute.ExceptionItem exn = exns.get(i);
493:
494: CodeAttribute.ExceptionItem newExn = new CodeAttribute.ExceptionItem();
495:
496: newExn.setType(exn.getType());
497: newExn.setStart(exn.getStart() + codeLength);
498: newExn.setEnd(exn.getEnd() + codeLength);
499: newExn.setHandler(exn.getHandler() + codeLength);
500: }
501: }
502:
503: public String toString() {
504: return "JavaMethod[" + _name + "]";
505: }
506: }
|