All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.feilong.lib.javassist.bytecode.MethodInfo Maven / Gradle / Ivy

Go to download

feilong is a suite of core and expanded libraries that include utility classes, http, excel,cvs, io classes, and much much more.

There is a newer version: 4.0.8
Show newest version
/*
 * Javassist, a Java-bytecode translator toolkit.
 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved.
 *
 * The contents of this file are subject to the Mozilla Public License Version
 * 1.1 (the "License"); you may not use this file except in compliance with
 * the License.  Alternatively, the contents of this file may be used under
 * the terms of the GNU Lesser General Public License Version 2.1 or later,
 * or the Apache License Version 2.0.
 *
 * Software distributed under the License is distributed on an "AS IS" basis,
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 * for the specific language governing rights and limitations under the
 * License.
 */

package com.feilong.lib.javassist.bytecode;

import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import com.feilong.lib.javassist.ClassPool;
import com.feilong.lib.javassist.bytecode.stackmap.MapMaker;

/**
 * method_info structure.
 *
 * 

* The bytecode sequence of the method is represented * by a CodeAttribute object. * *

* The following code adds the default constructor to a class: * of int type: *

* *
 * ClassFile cf = ...
 * Bytecode code = new Bytecode(cf.getConstPool());
 * code.addAload(0);
 * code.addInvokespecial("java/lang/Object", MethodInfo.nameInit, "()V");
 * code.addReturn(null);
 * code.setMaxLocals(1);
 *
 * MethodInfo minfo = new MethodInfo(cf.getConstPool(), MethodInfo.nameInit, "()V");
 * minfo.setCodeAttribute(code.toCodeAttribute());
 * cf.addMethod(minfo);
 * 
* *
* * @see #getCodeAttribute() * @see CodeAttribute * @see Bytecode * @see com.feilong.lib.javassist.CtMethod#getMethodInfo() * @see com.feilong.lib.javassist.CtConstructor#getMethodInfo() */ public class MethodInfo{ ConstPool constPool; int accessFlags; int name; String cachedName; int descriptor; List attribute; // may be null /** * If this value is true, Javassist maintains a StackMap attribute * generated by the preverify tool of J2ME (CLDC). The initial * value of this field is false. */ public static boolean doPreverify = false; /** * The name of constructors: <init>. */ public static final String nameInit = ""; /** * The name of class initializer (static initializer): * <clinit>. */ public static final String nameClinit = ""; private MethodInfo(ConstPool cp){ constPool = cp; attribute = null; } /** * Constructs a method_info structure. The initial value of * access_flags is zero. * * @param cp * a constant pool table * @param methodname * method name * @param desc * method descriptor * @see Descriptor */ public MethodInfo(ConstPool cp, String methodname, String desc){ this(cp); accessFlags = 0; name = cp.addUtf8Info(methodname); cachedName = methodname; descriptor = constPool.addUtf8Info(desc); } MethodInfo(ConstPool cp, DataInputStream in) throws IOException{ this(cp); read(in); } /** * Constructs a copy of method_info structure. Class names * appearing in the source method_info are renamed according * to classnameMap. * *

* Note: only Code and Exceptions attributes * are copied from the source. The other attributes are ignored. * * @param cp * a constant pool table * @param methodname * a method name * @param src * a source method_info * @param classnameMap * specifies pairs of replaced and substituted name. * @see Descriptor */ public MethodInfo(ConstPool cp, String methodname, MethodInfo src, Map classnameMap) throws BadBytecode{ this(cp); read(src, methodname, classnameMap); } /** * Returns a string representation of the object. */ @Override public String toString(){ return getName() + " " + getDescriptor(); } /** * Copies all constant pool items to a given new constant pool * and replaces the original items with the new ones. * This is used for garbage collecting the items of removed fields * and methods. * * @param cp * the destination */ void compact(ConstPool cp){ name = cp.addUtf8Info(getName()); descriptor = cp.addUtf8Info(getDescriptor()); attribute = AttributeInfo.copyAll(attribute, cp); constPool = cp; } void prune(ConstPool cp){ List newAttributes = new ArrayList<>(); AttributeInfo invisibleAnnotations = getAttribute(AnnotationsAttribute.invisibleTag); if (invisibleAnnotations != null){ invisibleAnnotations = invisibleAnnotations.copy(cp, null); newAttributes.add(invisibleAnnotations); } AttributeInfo visibleAnnotations = getAttribute(AnnotationsAttribute.visibleTag); if (visibleAnnotations != null){ visibleAnnotations = visibleAnnotations.copy(cp, null); newAttributes.add(visibleAnnotations); } AttributeInfo parameterInvisibleAnnotations = getAttribute(ParameterAnnotationsAttribute.invisibleTag); if (parameterInvisibleAnnotations != null){ parameterInvisibleAnnotations = parameterInvisibleAnnotations.copy(cp, null); newAttributes.add(parameterInvisibleAnnotations); } AttributeInfo parameterVisibleAnnotations = getAttribute(ParameterAnnotationsAttribute.visibleTag); if (parameterVisibleAnnotations != null){ parameterVisibleAnnotations = parameterVisibleAnnotations.copy(cp, null); newAttributes.add(parameterVisibleAnnotations); } AnnotationDefaultAttribute defaultAttribute = (AnnotationDefaultAttribute) getAttribute(AnnotationDefaultAttribute.tag); if (defaultAttribute != null){ newAttributes.add(defaultAttribute); } ExceptionsAttribute ea = getExceptionsAttribute(); if (ea != null){ newAttributes.add(ea); } AttributeInfo signature = getAttribute(SignatureAttribute.tag); if (signature != null){ signature = signature.copy(cp, null); newAttributes.add(signature); } attribute = newAttributes; name = cp.addUtf8Info(getName()); descriptor = cp.addUtf8Info(getDescriptor()); constPool = cp; } /** * Returns a method name. */ public String getName(){ if (cachedName == null){ cachedName = constPool.getUtf8Info(name); } return cachedName; } /** * Sets a method name. */ public void setName(String newName){ name = constPool.addUtf8Info(newName); cachedName = newName; } /** * Returns true if this is not a constructor or a class initializer (static * initializer). */ public boolean isMethod(){ String n = getName(); return !n.equals(nameInit) && !n.equals(nameClinit); } /** * Returns a constant pool table used by this method. */ public ConstPool getConstPool(){ return constPool; } /** * Returns true if this is a constructor. */ public boolean isConstructor(){ return getName().equals(nameInit); } /** * Returns true if this is a class initializer (static initializer). */ public boolean isStaticInitializer(){ return getName().equals(nameClinit); } /** * Returns access flags. * * @see AccessFlag */ public int getAccessFlags(){ return accessFlags; } /** * Sets access flags. * * @see AccessFlag */ public void setAccessFlags(int acc){ accessFlags = acc; } /** * Returns a method descriptor. * * @see Descriptor */ public String getDescriptor(){ return constPool.getUtf8Info(descriptor); } /** * Sets a method descriptor. * * @see Descriptor */ public void setDescriptor(String desc){ if (!desc.equals(getDescriptor())){ descriptor = constPool.addUtf8Info(desc); } } /** * Returns all the attributes. The returned List object * is shared with this object. If you add a new attribute to the list, * the attribute is also added to the method represented by this * object. If you remove an attribute from the list, it is also removed * from the method. * * @return a list of AttributeInfo objects. * @see AttributeInfo */ public List getAttributes(){ if (attribute == null){ attribute = new ArrayList<>(); } return attribute; } /** * Returns the attribute with the specified name. If it is not found, this * method returns null. * *

* An attribute name can be obtained by, for example, * {@link AnnotationsAttribute#visibleTag} or * {@link AnnotationsAttribute#invisibleTag}. *

* * @param name * attribute name * @return an AttributeInfo object or null. * @see #getAttributes() */ public AttributeInfo getAttribute(String name){ return AttributeInfo.lookup(attribute, name); } /** * Removes an attribute with the specified name. * * @param name * attribute name. * @return the removed attribute or null. * @since 3.21 */ public AttributeInfo removeAttribute(String name){ return AttributeInfo.remove(attribute, name); } /** * Appends an attribute. If there is already an attribute with the same * name, the new one substitutes for it. * * @see #getAttributes() */ public void addAttribute(AttributeInfo info){ if (attribute == null){ attribute = new ArrayList<>(); } AttributeInfo.remove(attribute, info.getName()); attribute.add(info); } /** * Returns an Exceptions attribute. * * @return an Exceptions attribute or null if it is not specified. */ public ExceptionsAttribute getExceptionsAttribute(){ AttributeInfo info = AttributeInfo.lookup(attribute, ExceptionsAttribute.tag); return (ExceptionsAttribute) info; } /** * Returns a Code attribute. * * @return a Code attribute or null if it is not specified. */ public CodeAttribute getCodeAttribute(){ AttributeInfo info = AttributeInfo.lookup(attribute, CodeAttribute.tag); return (CodeAttribute) info; } /** * Removes an Exception attribute. */ public void removeExceptionsAttribute(){ AttributeInfo.remove(attribute, ExceptionsAttribute.tag); } /** * Adds an Exception attribute. * *

* The added attribute must share the same constant pool table as this * method_info structure. */ public void setExceptionsAttribute(ExceptionsAttribute cattr){ removeExceptionsAttribute(); if (attribute == null){ attribute = new ArrayList<>(); } attribute.add(cattr); } /** * Removes a Code attribute. */ public void removeCodeAttribute(){ AttributeInfo.remove(attribute, CodeAttribute.tag); } /** * Adds a Code attribute. * *

* The added attribute must share the same constant pool table as this * method_info structure. */ public void setCodeAttribute(CodeAttribute cattr){ removeCodeAttribute(); if (attribute == null){ attribute = new ArrayList<>(); } attribute.add(cattr); } /** * Rebuilds a stack map table if the class file is for Java 6 * or later. Java 5 or older Java VMs do not recognize a stack * map table. If doPreverify is true, this method * also rebuilds a stack map for J2ME (CLDC). * * @param pool * used for making type hierarchy. * @param cf * rebuild if this class file is for Java 6 or later. * @see #rebuildStackMap(ClassPool) * @see #rebuildStackMapForME(ClassPool) * @see #doPreverify * @since 3.6 */ public void rebuildStackMapIf6(ClassPool pool,ClassFile cf) throws BadBytecode{ if (cf.getMajorVersion() >= ClassFile.JAVA_6){ rebuildStackMap(pool); } if (doPreverify){ rebuildStackMapForME(pool); } } /** * Rebuilds a stack map table. If no stack map table is included, * a new one is created. If this MethodInfo does not * include a code attribute, nothing happens. * * @param pool * used for making type hierarchy. * @see StackMapTable * @since 3.6 */ public void rebuildStackMap(ClassPool pool) throws BadBytecode{ CodeAttribute ca = getCodeAttribute(); if (ca != null){ StackMapTable smt = MapMaker.make(pool, this); ca.setAttribute(smt); } } /** * Rebuilds a stack map table for J2ME (CLDC). If no stack map table is included, * a new one is created. If this MethodInfo does not * include a code attribute, nothing happens. * * @param pool * used for making type hierarchy. * @see StackMap * @since 3.12 */ public void rebuildStackMapForME(ClassPool pool) throws BadBytecode{ CodeAttribute ca = getCodeAttribute(); if (ca != null){ StackMap sm = MapMaker.make2(pool, this); ca.setAttribute(sm); } } /** * Returns the line number of the source line corresponding to the specified * bytecode contained in this method. * * @param pos * the position of the bytecode (>= 0). an index into the code * array. * @return -1 if this information is not available. */ public int getLineNumber(int pos){ CodeAttribute ca = getCodeAttribute(); if (ca == null){ return -1; } LineNumberAttribute ainfo = (LineNumberAttribute) ca.getAttribute(LineNumberAttribute.tag); if (ainfo == null){ return -1; } return ainfo.toLineNumber(pos); } /** * Changes a super constructor called by this constructor. * *

* This method modifies a call to super(), which should be * at the head of a constructor body, so that a constructor in a different * super class is called. This method does not change actual parameters. * Hence the new super class must have a constructor with the same signature * as the original one. * *

* This method should be called when the super class of the class declaring * this method is changed. * *

* This method does not perform anything unless this MethodInfo * represents a constructor. * * @param superclass * the new super class */ public void setSuperclass(String superclass) throws BadBytecode{ if (!isConstructor()){ return; } CodeAttribute ca = getCodeAttribute(); byte[] code = ca.getCode(); CodeIterator iterator = ca.iterator(); int pos = iterator.skipSuperConstructor(); if (pos >= 0){ // not this() ConstPool cp = constPool; int mref = ByteArray.readU16bit(code, pos + 1); int nt = cp.getMethodrefNameAndType(mref); int sc = cp.addClassInfo(superclass); int mref2 = cp.addMethodrefInfo(sc, nt); ByteArray.write16bit(mref2, code, pos + 1); } } private void read(MethodInfo src,String methodname,Map classnames){ ConstPool destCp = constPool; accessFlags = src.accessFlags; name = destCp.addUtf8Info(methodname); cachedName = methodname; ConstPool srcCp = src.constPool; String desc = srcCp.getUtf8Info(src.descriptor); String desc2 = Descriptor.rename(desc, classnames); descriptor = destCp.addUtf8Info(desc2); attribute = new ArrayList<>(); ExceptionsAttribute eattr = src.getExceptionsAttribute(); if (eattr != null){ attribute.add(eattr.copy(destCp, classnames)); } CodeAttribute cattr = src.getCodeAttribute(); if (cattr != null){ attribute.add(cattr.copy(destCp, classnames)); } } private void read(DataInputStream in) throws IOException{ accessFlags = in.readUnsignedShort(); name = in.readUnsignedShort(); descriptor = in.readUnsignedShort(); int n = in.readUnsignedShort(); attribute = new ArrayList<>(); for (int i = 0; i < n; ++i){ attribute.add(AttributeInfo.read(constPool, in)); } } void write(DataOutputStream out) throws IOException{ out.writeShort(accessFlags); out.writeShort(name); out.writeShort(descriptor); if (attribute == null){ out.writeShort(0); }else{ out.writeShort(attribute.size()); AttributeInfo.writeAll(attribute, out); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy