com.caucho.bytecode.JavaMethod Maven / Gradle / Ivy
/*
* Copyright (c) 1998-2018 Caucho Technology -- all rights reserved
*
* This file is part of Resin(R) Open Source
*
* Each copy or derived work must preserve the copyright notice and this
* notice unmodified.
*
* Resin Open Source is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Resin Open Source is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
* of NON-INFRINGEMENT. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License
* along with Resin Open Source; if not, write to the
*
* Free Software Foundation, Inc.
* 59 Temple Place, Suite 330
* Boston, MA 02111-1307 USA
*
* @author Scott Ferguson
*/
package com.caucho.bytecode;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.lang.reflect.*;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Represents a java field.
*/
public class JavaMethod extends JMethod {
static private final Logger log = Logger.getLogger(JavaMethod.class.getName());
private static final JClass []NULL_CLASS = new JClass[0];
private JavaClassLoader _loader;
private JavaClass _jClass;
private int _accessFlags;
private String _name;
private String _descriptor;
private JClass []_exceptions = NULL_CLASS;
private int _line = -1;
private ArrayList _attributes = new ArrayList();
private JavaAnnotation []_annotations;
private boolean _isWrite;
public JavaMethod(JavaClassLoader loader)
{
_loader = loader;
}
public JavaMethod()
{
}
/**
* Sets the JavaClass.
*/
public void setJavaClass(JavaClass jClass)
{
_jClass = jClass;
}
public void setWrite(boolean isWrite)
{
_isWrite = isWrite;
}
/**
* Sets the name.
*/
public void setName(String name)
{
_name = name;
if (_jClass != null)
_jClass.getConstantPool().addUTF8(name);
}
/**
* Gets the name.
*/
public String getName()
{
return _name;
}
/**
* Returns the line number.
*/
public int getLine()
{
if (_line >= 0)
return _line;
Attribute attr = getAttribute("LineNumberTable");
if (attr == null) {
_line = 0;
return _line;
}
_line = 0;
return _line;
}
/**
* Returns the class loader.
*/
public JavaClassLoader getClassLoader()
{
return _loader;
}
/**
* Sets the access flags
*/
public void setAccessFlags(int flags)
{
_accessFlags = flags;
}
/**
* Gets the access flags
*/
public int getAccessFlags()
{
return _accessFlags;
}
/**
* Returns true for a final method
*/
public boolean isFinal()
{
return Modifier.isFinal(getAccessFlags());
}
/**
* Returns true for a public method
*/
public boolean isPublic()
{
return Modifier.isPublic(getAccessFlags());
}
/**
* Returns true for a protected method
*/
public boolean isProtected()
{
return Modifier.isProtected(getAccessFlags());
}
/**
* Returns true for a private method
*/
public boolean isPrivate()
{
return Modifier.isPrivate(getAccessFlags());
}
/**
* Returns true for an abstract method
*/
public boolean isAbstract()
{
return Modifier.isAbstract(getAccessFlags());
}
/**
* Returns true for a static method
*/
public boolean isStatic()
{
return Modifier.isStatic(getAccessFlags());
}
/**
* Sets the descriptor.
*/
public void setDescriptor(String descriptor)
{
_descriptor = descriptor;
if (_jClass != null)
_jClass.getConstantPool().addUTF8(descriptor);
}
/**
* Gets the descriptor.
*/
public String getDescriptor()
{
return _descriptor;
}
/**
* Returns the declaring class.
*/
public JClass getDeclaringClass()
{
return _jClass;
}
/**
* Returns the return types.
*/
public JClass getReturnType()
{
String descriptor = getDescriptor();
int i = descriptor.lastIndexOf(')');
return getClassLoader().descriptorToClass(descriptor, i + 1);
}
/**
* Returns the return type.
*/
public JType getGenericReturnType()
{
SignatureAttribute sigAttr = (SignatureAttribute) getAttribute("Signature");
if (sigAttr != null) {
String sig = sigAttr.getSignature();
int t = sig.lastIndexOf(')');
return _loader.parseParameterizedType(sig.substring(t + 1));
}
return getReturnType();
}
/**
* Returns the parameter types.
*/
public JClass []getParameterTypes()
{
String descriptor = getDescriptor();
ArrayList typeList = new ArrayList();
int i = 0;
while ((i = nextDescriptor(descriptor, i)) >= 0) {
typeList.add(getClassLoader().descriptorToClass(descriptor, i));
}
JClass []types = new JClass[typeList.size()];
typeList.toArray(types);
return types;
}
private int nextDescriptor(String name, int i)
{
switch (name.charAt(i)) {
case ')':
return -1;
case '(':
case 'V':
case 'Z':
case 'C':
case 'B':
case 'S':
case 'I':
case 'J':
case 'F':
case 'D':
i += 1;
break;
case '[':
return nextDescriptor(name, i + 1);
case 'L':
{
int tail = name.indexOf( ';', i);
if (tail < 0)
throw new IllegalStateException();
i = tail + 1;
}
break;
default:
throw new UnsupportedOperationException(name.substring(i));
}
if (name.length() <= i)
return -1;
else if (name.charAt(i) == ')')
return -1;
else
return i;
}
/**
* Sets the exception types
*/
public void setExceptionTypes(JClass []exceptions)
{
_exceptions = exceptions;
}
/**
* Returns the exception types.
*/
public JClass []getExceptionTypes()
{
return _exceptions;
}
/**
* Adds an attribute.
*/
public void addAttribute(Attribute attr)
{
_attributes.add(attr);
}
public CodeWriterAttribute createCodeWriter()
{
CodeWriterAttribute code = new CodeWriterAttribute(_jClass);
_attributes.add(code);
return code;
}
/**
* Removes an attribute.
*/
public Attribute removeAttribute(String name)
{
for (int i = _attributes.size() - 1; i >= 0; i--) {
Attribute attr = _attributes.get(i);
if (attr.getName().equals(name)) {
_attributes.remove(i);
return attr;
}
}
return null;
}
/**
* Returns the attribute.
*/
public ArrayList getAttributes()
{
return _attributes;
}
/**
* Returns the attribute.
*/
public Attribute getAttribute(String name)
{
for (int i = _attributes.size() - 1; i >= 0; i--) {
Attribute attr = _attributes.get(i);
if (attr.getName().equals(name))
return attr;
}
return null;
}
/**
* Returns the declared annotations.
*/
public JAnnotation []getDeclaredAnnotations()
{
if (_annotations == null) {
Attribute attr = getAttribute("RuntimeVisibleAnnotations");
if (attr instanceof OpaqueAttribute) {
byte []buffer = ((OpaqueAttribute) attr).getValue();
try {
ByteArrayInputStream is = new ByteArrayInputStream(buffer);
ConstantPool cp = _jClass.getConstantPool();
_annotations = JavaAnnotation.parseAnnotations(is, cp,
getClassLoader());
} catch (IOException e) {
log.log(Level.FINER, e.toString(), e);
}
}
if (_annotations == null) {
_annotations = new JavaAnnotation[0];
}
}
return _annotations;
}
/**
* Returns the code attribute.
*/
public CodeAttribute getCode()
{
for (int i = 0; i < _attributes.size(); i++) {
Attribute attr = _attributes.get(i);
if (attr instanceof CodeAttribute)
return (CodeAttribute) attr;
}
return null;
}
/**
* Create the code attribute.
*/
public CodeAttribute createCode()
{
CodeAttribute code = new CodeAttribute();
for (int i = 0; i < _attributes.size(); i++) {
Attribute attr = _attributes.get(i);
if (attr instanceof CodeAttribute)
return (CodeAttribute) attr;
}
return null;
}
/**
* Writes the field to the output.
*/
public void write(ByteCodeWriter out)
throws IOException
{
out.writeShort(_accessFlags);
out.writeUTF8Const(_name);
out.writeUTF8Const(_descriptor);
out.writeShort(_attributes.size());
for (int i = 0; i < _attributes.size(); i++) {
Attribute attr = _attributes.get(i);
attr.write(out);
}
}
/**
* exports the method.
*/
public JavaMethod export(JavaClass source, JavaClass target)
{
JavaMethod method = new JavaMethod(_loader);
method.setName(_name);
method.setDescriptor(_descriptor);
method.setAccessFlags(_accessFlags);
target.getConstantPool().addUTF8(_name);
target.getConstantPool().addUTF8(_descriptor);
for (int i = 0; i < _attributes.size(); i++) {
Attribute attr = _attributes.get(i);
method.addAttribute(attr.export(source, target));
}
return method;
}
/**
* Concatenates the method.
*/
public void concatenate(JavaMethod tail)
{
CodeAttribute codeAttr = getCode();
CodeAttribute tailCodeAttr = tail.getCode();
byte []code = codeAttr.getCode();
byte []tailCode = tailCodeAttr.getCode();
int codeLength = code.length;
if ((code[codeLength - 1] & 0xff) == CodeVisitor.RETURN)
codeLength = codeLength - 1;
byte []newCode = new byte[codeLength + tailCode.length];
System.arraycopy(code, 0, newCode, 0, codeLength);
System.arraycopy(tailCode, 0, newCode, codeLength, tailCode.length);
codeAttr.setCode(newCode);
if (codeAttr.getMaxStack() < tailCodeAttr.getMaxStack())
codeAttr.setMaxStack(tailCodeAttr.getMaxStack());
if (codeAttr.getMaxLocals() < tailCodeAttr.getMaxLocals())
codeAttr.setMaxLocals(tailCodeAttr.getMaxLocals());
ArrayList exns = tailCodeAttr.getExceptions();
for (int i = 0; i < exns.size(); i++) {
CodeAttribute.ExceptionItem exn = exns.get(i);
CodeAttribute.ExceptionItem newExn = new CodeAttribute.ExceptionItem();
newExn.setType(exn.getType());
newExn.setStart(exn.getStart() + codeLength);
newExn.setEnd(exn.getEnd() + codeLength);
newExn.setHandler(exn.getHandler() + codeLength);
}
}
public String toString()
{
return "JavaMethod[" + _name + "]";
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy