Cloud.Liu
3 years ago
272 changed files with 3 additions and 63945 deletions
@ -1,6 +0,0 @@
|
||||
*.iml |
||||
.idea/ |
||||
.DS_Store |
||||
.project |
||||
.classpath |
||||
*.gradle |
@ -1,2 +0,0 @@
|
||||
源码地址:https://github.com/jboss-javassist/javassist <br> |
||||
版本:3.18 |
@ -1,18 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" |
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> |
||||
<modelVersion>4.0.0</modelVersion> |
||||
|
||||
<parent> |
||||
<groupId>com.fr.third</groupId> |
||||
<artifactId>step3</artifactId> |
||||
<version>${revision}</version> |
||||
<relativePath>../base-third-project/base-third-step3</relativePath> |
||||
</parent> |
||||
|
||||
<artifactId>fine-javassist</artifactId> |
||||
<version>${revision}</version> |
||||
|
||||
|
||||
</project> |
@ -1,99 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import java.io.*; |
||||
import java.net.URL; |
||||
import java.net.MalformedURLException; |
||||
|
||||
/** |
||||
* A <code>ByteArrayClassPath</code> contains bytes that is served as |
||||
* a class file to a <code>ClassPool</code>. It is useful to convert |
||||
* a byte array to a <code>CtClass</code> object. |
||||
* |
||||
* <p>For example, if you want to convert a byte array <code>b</code> |
||||
* into a <code>CtClass</code> object representing the class with a name |
||||
* <code>classname</code>, then do as following: |
||||
* |
||||
* <ul><pre> |
||||
* ClassPool cp = ClassPool.getDefault(); |
||||
* cp.insertClassPath(new ByteArrayClassPath(classname, b)); |
||||
* CtClass cc = cp.get(classname); |
||||
* </pre></ul> |
||||
* |
||||
* <p>The <code>ClassPool</code> object <code>cp</code> uses the created |
||||
* <code>ByteArrayClassPath</code> object as the source of the class file. |
||||
* |
||||
* <p>A <code>ByteArrayClassPath</code> must be instantiated for every |
||||
* class. It contains only a single class file. |
||||
* |
||||
* @see ClassPath |
||||
* @see ClassPool#insertClassPath(ClassPath) |
||||
* @see ClassPool#appendClassPath(ClassPath) |
||||
* @see ClassPool#makeClass(InputStream) |
||||
*/ |
||||
public class ByteArrayClassPath implements ClassPath { |
||||
protected String classname; |
||||
protected byte[] classfile; |
||||
|
||||
/* |
||||
* Creates a <code>ByteArrayClassPath</code> containing the given |
||||
* bytes. |
||||
* |
||||
* @param name a fully qualified class name |
||||
* @param classfile the contents of a class file. |
||||
*/ |
||||
public ByteArrayClassPath(String name, byte[] classfile) { |
||||
this.classname = name; |
||||
this.classfile = classfile; |
||||
} |
||||
|
||||
/** |
||||
* Closes this class path. |
||||
*/ |
||||
public void close() {} |
||||
|
||||
public String toString() { |
||||
return "byte[]:" + classname; |
||||
} |
||||
|
||||
/** |
||||
* Opens the class file. |
||||
*/ |
||||
public InputStream openClassfile(String classname) { |
||||
if(this.classname.equals(classname)) |
||||
return new ByteArrayInputStream(classfile); |
||||
else |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the URL. |
||||
*/ |
||||
public URL find(String classname) { |
||||
if(this.classname.equals(classname)) { |
||||
String cname = classname.replace('.', '/') + ".class"; |
||||
try { |
||||
// return new File(cname).toURL();
|
||||
return new URL("file:/ByteArrayClassPath/" + cname); |
||||
} |
||||
catch (MalformedURLException e) {} |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
} |
@ -1,120 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.compiler.CompileError; |
||||
|
||||
/** |
||||
* Thrown when bytecode transformation has failed. |
||||
*/ |
||||
public class CannotCompileException extends Exception { |
||||
private Throwable myCause; |
||||
|
||||
/** |
||||
* Gets the cause of this throwable. |
||||
* It is for JDK 1.3 compatibility. |
||||
*/ |
||||
public Throwable getCause() { |
||||
return (myCause == this ? null : myCause); |
||||
} |
||||
|
||||
/** |
||||
* Initializes the cause of this throwable. |
||||
* It is for JDK 1.3 compatibility. |
||||
*/ |
||||
public synchronized Throwable initCause(Throwable cause) { |
||||
myCause = cause; |
||||
return this; |
||||
} |
||||
|
||||
private String message; |
||||
|
||||
/** |
||||
* Gets a long message if it is available. |
||||
*/ |
||||
public String getReason() { |
||||
if (message != null) |
||||
return message; |
||||
else |
||||
return this.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a CannotCompileException with a message. |
||||
* |
||||
* @param msg the message. |
||||
*/ |
||||
public CannotCompileException(String msg) { |
||||
super(msg); |
||||
message = msg; |
||||
initCause(null); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a CannotCompileException with an <code>Exception</code> |
||||
* representing the cause. |
||||
* |
||||
* @param e the cause. |
||||
*/ |
||||
public CannotCompileException(Throwable e) { |
||||
super("by " + e.toString()); |
||||
message = null; |
||||
initCause(e); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a CannotCompileException with a detailed message |
||||
* and an <code>Exception</code> representing the cause. |
||||
* |
||||
* @param msg the message. |
||||
* @param e the cause. |
||||
*/ |
||||
public CannotCompileException(String msg, Throwable e) { |
||||
this(msg); |
||||
initCause(e); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a CannotCompileException with a |
||||
* <code>NotFoundException</code>. |
||||
*/ |
||||
public CannotCompileException(NotFoundException e) { |
||||
this("cannot find " + e.getMessage(), e); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a CannotCompileException with an <code>CompileError</code>. |
||||
*/ |
||||
public CannotCompileException(CompileError e) { |
||||
this("[source error] " + e.getMessage(), e); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a CannotCompileException |
||||
* with a <code>ClassNotFoundException</code>. |
||||
*/ |
||||
public CannotCompileException(ClassNotFoundException e, String name) { |
||||
this("cannot find " + name, e); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a CannotCompileException with a ClassFormatError. |
||||
*/ |
||||
public CannotCompileException(ClassFormatError e, String name) { |
||||
this("invalid class format: " + name, e); |
||||
} |
||||
} |
@ -1,97 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import java.io.InputStream; |
||||
import java.net.URL; |
||||
|
||||
/** |
||||
* A search-path for obtaining a class file |
||||
* by <code>getResourceAsStream()</code> in <code>java.lang.Class</code>. |
||||
* |
||||
* <p>Try adding a <code>ClassClassPath</code> when a program is running |
||||
* with a user-defined class loader and any class files are not found with |
||||
* the default <code>ClassPool</code>. For example, |
||||
* |
||||
* <ul><pre> |
||||
* ClassPool cp = ClassPool.getDefault(); |
||||
* cp.insertClassPath(new ClassClassPath(this.getClass())); |
||||
* </pre></ul> |
||||
* |
||||
* This code snippet permanently adds a <code>ClassClassPath</code> |
||||
* to the default <code>ClassPool</code>. Note that the default |
||||
* <code>ClassPool</code> is a singleton. The added |
||||
* <code>ClassClassPath</code> uses a class object representing |
||||
* the class including the code snippet above. |
||||
* |
||||
* @see ClassPool#insertClassPath(ClassPath) |
||||
* @see ClassPool#appendClassPath(ClassPath) |
||||
* @see LoaderClassPath |
||||
*/ |
||||
public class ClassClassPath implements ClassPath { |
||||
private Class thisClass; |
||||
|
||||
/** Creates a search path. |
||||
* |
||||
* @param c the <code>Class</code> object used to obtain a class
|
||||
* file. <code>getResourceAsStream()</code> is called on |
||||
* this object. |
||||
*/ |
||||
public ClassClassPath(Class c) { |
||||
thisClass = c; |
||||
} |
||||
|
||||
ClassClassPath() { |
||||
/* The value of thisClass was this.getClass() in early versions: |
||||
* |
||||
* thisClass = this.getClass(); |
||||
* |
||||
* However, this made openClassfile() not search all the system |
||||
* class paths if javassist.jar is put in jre/lib/ext/ |
||||
* (with JDK1.4). |
||||
*/ |
||||
this(java.lang.Object.class); |
||||
} |
||||
|
||||
/** |
||||
* Obtains a class file by <code>getResourceAsStream()</code>. |
||||
*/ |
||||
public InputStream openClassfile(String classname) { |
||||
String jarname = "/" + classname.replace('.', '/') + ".class"; |
||||
return thisClass.getResourceAsStream(jarname); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the URL of the specified class file. |
||||
* |
||||
* @return null if the class file could not be found. |
||||
*/ |
||||
public URL find(String classname) { |
||||
String jarname = "/" + classname.replace('.', '/') + ".class"; |
||||
return thisClass.getResource(jarname); |
||||
} |
||||
|
||||
/** |
||||
* Does nothing. |
||||
*/ |
||||
public void close() { |
||||
} |
||||
|
||||
public String toString() { |
||||
return thisClass.getName() + ".class"; |
||||
} |
||||
} |
@ -1,173 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.Descriptor; |
||||
|
||||
/** |
||||
* A hash table associating class names with different names. |
||||
* |
||||
* <p>This hashtable is used for replacing class names in a class
|
||||
* definition or a method body. Define a subclass of this class
|
||||
* if a more complex mapping algorithm is needed. For example, |
||||
* |
||||
* <ul><pre>class MyClassMap extends ClassMap { |
||||
* public Object get(Object jvmClassName) { |
||||
* String name = toJavaName((String)jvmClassName); |
||||
* if (name.startsWith("java.")) |
||||
* return toJvmName("java2." + name.substring(5)); |
||||
* else |
||||
* return super.get(jvmClassName); |
||||
* } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>This subclass maps <code>java.lang.String</code> to |
||||
* <code>java2.lang.String</code>. Note that <code>get()</code> |
||||
* receives and returns the internal representation of a class name. |
||||
* For example, the internal representation of <code>java.lang.String</code> |
||||
* is <code>java/lang/String</code>. |
||||
* |
||||
* <p>Note that this is a map from <code>String</code> to <code>String</code>. |
||||
* |
||||
* @see #get(Object) |
||||
* @see CtClass#replaceClassName(ClassMap) |
||||
* @see CtNewMethod#copy(CtMethod,String,CtClass,ClassMap) |
||||
*/ |
||||
public class ClassMap extends java.util.HashMap { |
||||
private ClassMap parent; |
||||
|
||||
/** |
||||
* Constructs a hash table. |
||||
*/ |
||||
public ClassMap() { parent = null; } |
||||
|
||||
ClassMap(ClassMap map) { parent = map; } |
||||
|
||||
/** |
||||
* Maps a class name to another name in this hashtable. |
||||
* The names are obtained with calling <code>Class.getName()</code>. |
||||
* This method translates the given class names into the |
||||
* internal form used in the JVM before putting it in |
||||
* the hashtable. |
||||
* |
||||
* @param oldname the original class name |
||||
* @param newname the substituted class name. |
||||
*/ |
||||
public void put(CtClass oldname, CtClass newname) { |
||||
put(oldname.getName(), newname.getName()); |
||||
} |
||||
|
||||
/** |
||||
* Maps a class name to another name in this hashtable. |
||||
* If the hashtable contains another mapping from the same |
||||
* class name, the old mapping is replaced. |
||||
* This method translates the given class names into the |
||||
* internal form used in the JVM before putting it in |
||||
* the hashtable. |
||||
* |
||||
* <p>If <code>oldname</code> is identical to |
||||
* <code>newname</code>, then this method does not |
||||
* perform anything; it does not record the mapping from |
||||
* <code>oldname</code> to <code>newname</code>. See |
||||
* <code>fix</code> method. |
||||
* |
||||
* @param oldname the original class name. |
||||
* @param newname the substituted class name. |
||||
* @see #fix(String) |
||||
*/ |
||||
public void put(String oldname, String newname) { |
||||
if (oldname == newname) |
||||
return; |
||||
|
||||
String oldname2 = toJvmName(oldname); |
||||
String s = (String)get(oldname2); |
||||
if (s == null || !s.equals(oldname2)) |
||||
super.put(oldname2, toJvmName(newname)); |
||||
} |
||||
|
||||
/** |
||||
* Is equivalent to <code>put()</code> except that |
||||
* the given mapping is not recorded into the hashtable |
||||
* if another mapping from <code>oldname</code> is |
||||
* already included. |
||||
* |
||||
* @param oldname the original class name. |
||||
* @param newname the substituted class name. |
||||
*/ |
||||
public void putIfNone(String oldname, String newname) { |
||||
if (oldname == newname) |
||||
return; |
||||
|
||||
String oldname2 = toJvmName(oldname); |
||||
String s = (String)get(oldname2); |
||||
if (s == null) |
||||
super.put(oldname2, toJvmName(newname)); |
||||
} |
||||
|
||||
protected final void put0(Object oldname, Object newname) { |
||||
super.put(oldname, newname); |
||||
} |
||||
|
||||
/** |
||||
* Returns the class name to wihch the given <code>jvmClassName</code> |
||||
* is mapped. A subclass of this class should override this method. |
||||
* |
||||
* <p>This method receives and returns the internal representation of |
||||
* class name used in the JVM. |
||||
* |
||||
* @see #toJvmName(String) |
||||
* @see #toJavaName(String) |
||||
*/ |
||||
public Object get(Object jvmClassName) { |
||||
Object found = super.get(jvmClassName); |
||||
if (found == null && parent != null) |
||||
return parent.get(jvmClassName); |
||||
else |
||||
return found; |
||||
} |
||||
|
||||
/** |
||||
* Prevents a mapping from the specified class name to another name. |
||||
*/ |
||||
public void fix(CtClass clazz) { |
||||
fix(clazz.getName()); |
||||
} |
||||
|
||||
/** |
||||
* Prevents a mapping from the specified class name to another name. |
||||
*/ |
||||
public void fix(String name) { |
||||
String name2 = toJvmName(name); |
||||
super.put(name2, name2); |
||||
} |
||||
|
||||
/** |
||||
* Converts a class name into the internal representation used in |
||||
* the JVM. |
||||
*/ |
||||
public static String toJvmName(String classname) { |
||||
return Descriptor.toJvmName(classname); |
||||
} |
||||
|
||||
/** |
||||
* Converts a class name from the internal representation used in |
||||
* the JVM to the normal one used in Java. |
||||
*/ |
||||
public static String toJavaName(String classname) { |
||||
return Descriptor.toJavaName(classname); |
||||
} |
||||
} |
@ -1,68 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import java.io.InputStream; |
||||
import java.net.URL; |
||||
|
||||
/** |
||||
* <code>ClassPath</code> is an interface implemented by objects |
||||
* representing a class search path. |
||||
* <code>ClassPool</code> uses those objects for reading class files. |
||||
* |
||||
* <p>The users can define a class implementing this interface so that |
||||
* a class file is obtained from a non-standard source. |
||||
* |
||||
* @see ClassPool#insertClassPath(ClassPath) |
||||
* @see ClassPool#appendClassPath(ClassPath) |
||||
* @see ClassPool#removeClassPath(ClassPath) |
||||
*/ |
||||
public interface ClassPath { |
||||
/** |
||||
* Opens a class file. |
||||
* This method may be called just to examine whether the class file |
||||
* exists as well as to read the contents of the file. |
||||
* |
||||
* <p>This method can return null if the specified class file is not |
||||
* found. If null is returned, the next search path is examined. |
||||
* However, if an error happens, this method must throw an exception |
||||
* so that the search will be terminated. |
||||
* |
||||
* <p>This method should not modify the contents of the class file. |
||||
* |
||||
* @param classname a fully-qualified class name |
||||
* @return the input stream for reading a class file |
||||
* @see Translator |
||||
*/ |
||||
InputStream openClassfile(String classname) throws NotFoundException; |
||||
|
||||
/** |
||||
* Returns the uniform resource locator (URL) of the class file |
||||
* with the specified name. |
||||
* |
||||
* @param classname a fully-qualified class name. |
||||
* @return null if the specified class file could not be found. |
||||
*/ |
||||
URL find(String classname); |
||||
|
||||
/** |
||||
* This method is invoked when the <code>ClassPath</code> object is |
||||
* detached from the search path. It will be an empty method in most of |
||||
* classes. |
||||
*/ |
||||
void close(); |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,429 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import java.io.*; |
||||
import java.util.jar.*; |
||||
import java.net.MalformedURLException; |
||||
import java.net.URL; |
||||
|
||||
final class ClassPathList { |
||||
ClassPathList next; |
||||
com.fr.third.javassist.ClassPath path; |
||||
|
||||
ClassPathList(com.fr.third.javassist.ClassPath p, ClassPathList n) { |
||||
next = n; |
||||
path = p; |
||||
} |
||||
} |
||||
|
||||
final class DirClassPath implements com.fr.third.javassist.ClassPath { |
||||
String directory; |
||||
|
||||
DirClassPath(String dirName) { |
||||
directory = dirName; |
||||
} |
||||
|
||||
public InputStream openClassfile(String classname) { |
||||
try { |
||||
char sep = File.separatorChar; |
||||
String filename = directory + sep |
||||
+ classname.replace('.', sep) + ".class"; |
||||
return new FileInputStream(filename.toString()); |
||||
} |
||||
catch (FileNotFoundException e) {} |
||||
catch (SecurityException e) {} |
||||
return null; |
||||
} |
||||
|
||||
public URL find(String classname) { |
||||
char sep = File.separatorChar; |
||||
String filename = directory + sep |
||||
+ classname.replace('.', sep) + ".class"; |
||||
File f = new File(filename); |
||||
if (f.exists()) |
||||
try { |
||||
return f.getCanonicalFile().toURI().toURL(); |
||||
} |
||||
catch (MalformedURLException e) {} |
||||
catch (IOException e) {} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
public void close() {} |
||||
|
||||
public String toString() { |
||||
return directory; |
||||
} |
||||
} |
||||
|
||||
final class JarDirClassPath implements com.fr.third.javassist.ClassPath { |
||||
JarClassPath[] jars; |
||||
|
||||
JarDirClassPath(String dirName) throws NotFoundException { |
||||
File[] files = new File(dirName).listFiles(new FilenameFilter() { |
||||
public boolean accept(File dir, String name) { |
||||
name = name.toLowerCase(); |
||||
return name.endsWith(".jar") || name.endsWith(".zip"); |
||||
} |
||||
}); |
||||
|
||||
if (files != null) { |
||||
jars = new JarClassPath[files.length]; |
||||
for (int i = 0; i < files.length; i++) |
||||
jars[i] = new JarClassPath(files[i].getPath()); |
||||
} |
||||
} |
||||
|
||||
public InputStream openClassfile(String classname) throws NotFoundException { |
||||
if (jars != null) |
||||
for (int i = 0; i < jars.length; i++) { |
||||
InputStream is = jars[i].openClassfile(classname); |
||||
if (is != null) |
||||
return is; |
||||
} |
||||
|
||||
return null; // not found
|
||||
} |
||||
|
||||
public URL find(String classname) { |
||||
if (jars != null) |
||||
for (int i = 0; i < jars.length; i++) { |
||||
URL url = jars[i].find(classname); |
||||
if (url != null) |
||||
return url; |
||||
} |
||||
|
||||
return null; // not found
|
||||
} |
||||
|
||||
public void close() { |
||||
if (jars != null) |
||||
for (int i = 0; i < jars.length; i++) |
||||
jars[i].close(); |
||||
} |
||||
} |
||||
|
||||
final class JarClassPath implements com.fr.third.javassist.ClassPath { |
||||
JarFile jarfile; |
||||
String jarfileURL; |
||||
|
||||
JarClassPath(String pathname) throws NotFoundException { |
||||
try { |
||||
jarfile = new JarFile(pathname); |
||||
jarfileURL = new File(pathname).getCanonicalFile() |
||||
.toURI().toURL().toString(); |
||||
return; |
||||
} |
||||
catch (IOException e) {} |
||||
throw new NotFoundException(pathname); |
||||
} |
||||
|
||||
public InputStream openClassfile(String classname) |
||||
throws NotFoundException |
||||
{ |
||||
try { |
||||
String jarname = classname.replace('.', '/') + ".class"; |
||||
JarEntry je = jarfile.getJarEntry(jarname); |
||||
if (je != null) |
||||
return jarfile.getInputStream(je); |
||||
else |
||||
return null; // not found
|
||||
} |
||||
catch (IOException e) {} |
||||
throw new NotFoundException("broken jar file?: " |
||||
+ jarfile.getName()); |
||||
} |
||||
|
||||
public URL find(String classname) { |
||||
String jarname = classname.replace('.', '/') + ".class"; |
||||
JarEntry je = jarfile.getJarEntry(jarname); |
||||
if (je != null) |
||||
try { |
||||
return new URL("jar:" + jarfileURL + "!/" + jarname); |
||||
} |
||||
catch (MalformedURLException e) {} |
||||
|
||||
return null; // not found
|
||||
} |
||||
|
||||
public void close() { |
||||
try { |
||||
jarfile.close(); |
||||
jarfile = null; |
||||
} |
||||
catch (IOException e) {} |
||||
} |
||||
|
||||
public String toString() { |
||||
return jarfile == null ? "<null>" : jarfile.toString(); |
||||
} |
||||
} |
||||
|
||||
final class ClassPoolTail { |
||||
protected ClassPathList pathList; |
||||
|
||||
public ClassPoolTail() { |
||||
pathList = null; |
||||
} |
||||
|
||||
public String toString() { |
||||
StringBuffer buf = new StringBuffer(); |
||||
buf.append("[class path: "); |
||||
ClassPathList list = pathList; |
||||
while (list != null) { |
||||
buf.append(list.path.toString()); |
||||
buf.append(File.pathSeparatorChar); |
||||
list = list.next; |
||||
} |
||||
|
||||
buf.append(']'); |
||||
return buf.toString(); |
||||
} |
||||
|
||||
public synchronized com.fr.third.javassist.ClassPath insertClassPath(com.fr.third.javassist.ClassPath cp) { |
||||
pathList = new ClassPathList(cp, pathList); |
||||
return cp; |
||||
} |
||||
|
||||
public synchronized com.fr.third.javassist.ClassPath appendClassPath(com.fr.third.javassist.ClassPath cp) { |
||||
ClassPathList tail = new ClassPathList(cp, null); |
||||
ClassPathList list = pathList; |
||||
if (list == null) |
||||
pathList = tail; |
||||
else { |
||||
while (list.next != null) |
||||
list = list.next; |
||||
|
||||
list.next = tail; |
||||
} |
||||
|
||||
return cp; |
||||
} |
||||
|
||||
public synchronized void removeClassPath(com.fr.third.javassist.ClassPath cp) { |
||||
ClassPathList list = pathList; |
||||
if (list != null) |
||||
if (list.path == cp) |
||||
pathList = list.next; |
||||
else { |
||||
while (list.next != null) |
||||
if (list.next.path == cp) |
||||
list.next = list.next.next; |
||||
else |
||||
list = list.next; |
||||
} |
||||
|
||||
cp.close(); |
||||
} |
||||
|
||||
public com.fr.third.javassist.ClassPath appendSystemPath() { |
||||
return appendClassPath(new ClassClassPath()); |
||||
} |
||||
|
||||
public com.fr.third.javassist.ClassPath insertClassPath(String pathname) |
||||
throws NotFoundException |
||||
{ |
||||
return insertClassPath(makePathObject(pathname)); |
||||
} |
||||
|
||||
public com.fr.third.javassist.ClassPath appendClassPath(String pathname) |
||||
throws NotFoundException |
||||
{ |
||||
return appendClassPath(makePathObject(pathname)); |
||||
} |
||||
|
||||
private static ClassPath makePathObject(String pathname) |
||||
throws NotFoundException |
||||
{ |
||||
String lower = pathname.toLowerCase(); |
||||
if (lower.endsWith(".jar") || lower.endsWith(".zip")) |
||||
return new JarClassPath(pathname); |
||||
|
||||
int len = pathname.length(); |
||||
if (len > 2 && pathname.charAt(len - 1) == '*' |
||||
&& (pathname.charAt(len - 2) == '/' |
||||
|| pathname.charAt(len - 2) == File.separatorChar)) { |
||||
String dir = pathname.substring(0, len - 2); |
||||
return new JarDirClassPath(dir); |
||||
} |
||||
|
||||
return new DirClassPath(pathname); |
||||
} |
||||
|
||||
/** |
||||
* This method does not close the output stream. |
||||
*/ |
||||
void writeClassfile(String classname, OutputStream out) |
||||
throws NotFoundException, IOException, CannotCompileException |
||||
{ |
||||
InputStream fin = openClassfile(classname); |
||||
if (fin == null) |
||||
throw new NotFoundException(classname); |
||||
|
||||
try { |
||||
copyStream(fin, out); |
||||
} |
||||
finally { |
||||
fin.close(); |
||||
} |
||||
} |
||||
|
||||
/* |
||||
-- faster version -- |
||||
void checkClassName(String classname) throws NotFoundException { |
||||
if (find(classname) == null) |
||||
throw new NotFoundException(classname); |
||||
} |
||||
|
||||
-- slower version -- |
||||
|
||||
void checkClassName(String classname) throws NotFoundException { |
||||
InputStream fin = openClassfile(classname); |
||||
try { |
||||
fin.close(); |
||||
} |
||||
catch (IOException e) {} |
||||
} |
||||
*/ |
||||
|
||||
|
||||
/** |
||||
* Opens the class file for the class specified by |
||||
* <code>classname</code>. |
||||
* |
||||
* @param classname a fully-qualified class name |
||||
* @return null if the file has not been found. |
||||
* @throws NotFoundException if any error is reported by ClassPath. |
||||
*/ |
||||
InputStream openClassfile(String classname) |
||||
throws NotFoundException |
||||
{ |
||||
ClassPathList list = pathList; |
||||
InputStream ins = null; |
||||
NotFoundException error = null; |
||||
while (list != null) { |
||||
try { |
||||
ins = list.path.openClassfile(classname); |
||||
} |
||||
catch (NotFoundException e) { |
||||
if (error == null) |
||||
error = e; |
||||
} |
||||
|
||||
if (ins == null) |
||||
list = list.next; |
||||
else |
||||
return ins; |
||||
} |
||||
|
||||
if (error != null) |
||||
throw error; |
||||
else |
||||
return null; // not found
|
||||
} |
||||
|
||||
/** |
||||
* Searches the class path to obtain the URL of the class file |
||||
* specified by classname. It is also used to determine whether |
||||
* the class file exists. |
||||
* |
||||
* @param classname a fully-qualified class name. |
||||
* @return null if the class file could not be found. |
||||
*/ |
||||
public URL find(String classname) { |
||||
ClassPathList list = pathList; |
||||
URL url = null; |
||||
while (list != null) { |
||||
url = list.path.find(classname); |
||||
if (url == null) |
||||
list = list.next; |
||||
else |
||||
return url; |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Reads from an input stream until it reaches the end. |
||||
* |
||||
* @return the contents of that input stream |
||||
*/ |
||||
public static byte[] readStream(InputStream fin) throws IOException { |
||||
byte[][] bufs = new byte[8][]; |
||||
int bufsize = 4096; |
||||
|
||||
for (int i = 0; i < 8; ++i) { |
||||
bufs[i] = new byte[bufsize]; |
||||
int size = 0; |
||||
int len = 0; |
||||
do { |
||||
len = fin.read(bufs[i], size, bufsize - size); |
||||
if (len >= 0) |
||||
size += len; |
||||
else { |
||||
byte[] result = new byte[bufsize - 4096 + size]; |
||||
int s = 0; |
||||
for (int j = 0; j < i; ++j) { |
||||
System.arraycopy(bufs[j], 0, result, s, s + 4096); |
||||
s = s + s + 4096; |
||||
} |
||||
|
||||
System.arraycopy(bufs[i], 0, result, s, size); |
||||
return result; |
||||
} |
||||
} while (size < bufsize); |
||||
bufsize *= 2; |
||||
} |
||||
|
||||
throw new IOException("too much data"); |
||||
} |
||||
|
||||
/** |
||||
* Reads from an input stream and write to an output stream |
||||
* until it reaches the end. This method does not close the |
||||
* streams. |
||||
*/ |
||||
public static void copyStream(InputStream fin, OutputStream fout) |
||||
throws IOException |
||||
{ |
||||
int bufsize = 4096; |
||||
byte[] buf = null; |
||||
for (int i = 0; i < 64; ++i) { |
||||
if (i < 8) { |
||||
bufsize *= 2; |
||||
buf = new byte[bufsize]; |
||||
} |
||||
int size = 0; |
||||
int len = 0; |
||||
do { |
||||
len = fin.read(buf, size, bufsize - size); |
||||
if (len >= 0) |
||||
size += len; |
||||
else { |
||||
fout.write(buf, 0, size); |
||||
return; |
||||
} |
||||
} while (size < bufsize); |
||||
fout.write(buf); |
||||
} |
||||
|
||||
throw new IOException("too much data"); |
||||
} |
||||
} |
@ -1,809 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.CodeAttribute; |
||||
import com.fr.third.javassist.convert.TransformCall; |
||||
import com.fr.third.javassist.expr.ExprEditor; |
||||
|
||||
/** |
||||
* Simple translator of method bodies |
||||
* (also see the <code>javassist.expr</code> package). |
||||
* |
||||
* <p>Instances of this class specifies how to instrument of the |
||||
* bytecodes representing a method body. They are passed to |
||||
* <code>CtClass.instrument()</code> or |
||||
* <code>CtMethod.instrument()</code> as a parameter. |
||||
* |
||||
* <p>Example: |
||||
* <ul><pre> |
||||
* ClassPool cp = ClassPool.getDefault(); |
||||
* CtClass point = cp.get("Point"); |
||||
* CtClass singleton = cp.get("Singleton"); |
||||
* CtClass client = cp.get("Client"); |
||||
* CodeConverter conv = new CodeConverter(); |
||||
* conv.replaceNew(point, singleton, "makePoint"); |
||||
* client.instrument(conv); |
||||
* </pre></ul> |
||||
* |
||||
* <p>This program substitutes "<code>Singleton.makePoint()</code>" |
||||
* for all occurrences of "<code>new Point()</code>" |
||||
* appearing in methods declared in a <code>Client</code> class. |
||||
* |
||||
* @see CtClass#instrument(CodeConverter) |
||||
* @see CtMethod#instrument(CodeConverter) |
||||
* @see ExprEditor |
||||
*/ |
||||
public class CodeConverter { |
||||
protected com.fr.third.javassist.convert.Transformer transformers = null; |
||||
|
||||
/** |
||||
* Modify a method body so that instantiation of the specified class
|
||||
* is replaced with a call to the specified static method. For example, |
||||
* <code>replaceNew(ctPoint, ctSingleton, "createPoint")</code> |
||||
* (where <code>ctPoint</code> and <code>ctSingleton</code> are |
||||
* compile-time classes for class <code>Point</code> and class
|
||||
* <code>Singleton</code>, respectively) |
||||
* replaces all occurrences of: |
||||
* |
||||
* <ul><code>new Point(x, y)</code></ul> |
||||
* |
||||
* in the method body with: |
||||
* |
||||
* <ul><code>Singleton.createPoint(x, y)</code></ul> |
||||
* |
||||
* <p>This enables to intercept instantiation of <code>Point</code> |
||||
* and change the samentics. For example, the following |
||||
* <code>createPoint()</code> implements the singleton pattern: |
||||
* |
||||
* <ul><pre>public static Point createPoint(int x, int y) { |
||||
* if (aPoint == null) |
||||
* aPoint = new Point(x, y); |
||||
* return aPoint; |
||||
* } |
||||
* </pre></ul> |
||||
* |
||||
* <p>The static method call substituted for the original <code>new</code> |
||||
* expression must be |
||||
* able to receive the same set of parameters as the original |
||||
* constructor. If there are multiple constructors with different |
||||
* parameter types, then there must be multiple static methods |
||||
* with the same name but different parameter types. |
||||
* |
||||
* <p>The return type of the substituted static method must be |
||||
* the exactly same as the type of the instantiated class specified by |
||||
* <code>newClass</code>. |
||||
* |
||||
* @param newClass the instantiated class. |
||||
* @param calledClass the class in which the static method is |
||||
* declared. |
||||
* @param calledMethod the name of the static method. |
||||
*/ |
||||
public void replaceNew(CtClass newClass, |
||||
CtClass calledClass, String calledMethod) { |
||||
transformers = new com.fr.third.javassist.convert.TransformNew(transformers, newClass.getName(), |
||||
calledClass.getName(), calledMethod); |
||||
} |
||||
|
||||
/** |
||||
* Modify a method body so that instantiation of the class
|
||||
* specified by <code>oldClass</code> |
||||
* is replaced with instantiation of another class <code>newClass</code>. |
||||
* For example, |
||||
* <code>replaceNew(ctPoint, ctPoint2)</code> |
||||
* (where <code>ctPoint</code> and <code>ctPoint2</code> are |
||||
* compile-time classes for class <code>Point</code> and class
|
||||
* <code>Point2</code>, respectively) |
||||
* replaces all occurrences of: |
||||
* |
||||
* <ul><code>new Point(x, y)</code></ul> |
||||
* |
||||
* in the method body with: |
||||
* |
||||
* <ul><code>new Point2(x, y)</code></ul> |
||||
* |
||||
* <p>Note that <code>Point2</code> must be type-compatible with <code>Point</code>. |
||||
* It must have the same set of methods, fields, and constructors as the |
||||
* replaced class. |
||||
*/ |
||||
public void replaceNew(CtClass oldClass, CtClass newClass) { |
||||
transformers = new com.fr.third.javassist.convert.TransformNewClass(transformers, oldClass.getName(), |
||||
newClass.getName()); |
||||
} |
||||
|
||||
/** |
||||
* Modify a method body so that field read/write expressions access |
||||
* a different field from the original one. |
||||
* |
||||
* <p>Note that this method changes only the filed name and the class
|
||||
* declaring the field; the type of the target object does not change. |
||||
* Therefore, the substituted field must be declared in the same class
|
||||
* or a superclass of the original class. |
||||
* |
||||
* <p>Also, <code>clazz</code> and <code>newClass</code> must specify |
||||
* the class directly declaring the field. They must not specify |
||||
* a subclass of that class. |
||||
* |
||||
* @param field the originally accessed field. |
||||
* @param newClass the class declaring the substituted field. |
||||
* @param newFieldname the name of the substituted field. |
||||
*/ |
||||
public void redirectFieldAccess(CtField field, |
||||
CtClass newClass, String newFieldname) { |
||||
transformers = new com.fr.third.javassist.convert.TransformFieldAccess(transformers, field, |
||||
newClass.getName(), |
||||
newFieldname); |
||||
} |
||||
|
||||
/** |
||||
* Modify a method body so that an expression reading the specified |
||||
* field is replaced with a call to the specified <i>static</i> method. |
||||
* This static method receives the target object of the original |
||||
* read expression as a parameter. It must return a value of |
||||
* the same type as the field. |
||||
* |
||||
* <p>For example, the program below |
||||
* |
||||
* <ul><pre>Point p = new Point(); |
||||
* int newX = p.x + 3;</pre></ul> |
||||
* |
||||
* <p>can be translated into: |
||||
* |
||||
* <ul><pre>Point p = new Point(); |
||||
* int newX = Accessor.readX(p) + 3;</pre></ul> |
||||
* |
||||
* <p>where |
||||
* |
||||
* <ul><pre>public class Accessor { |
||||
* public static int readX(Object target) { ... } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>The type of the parameter of <code>readX()</code> must |
||||
* be <code>java.lang.Object</code> independently of the actual |
||||
* type of <code>target</code>. The return type must be the same |
||||
* as the field type. |
||||
* |
||||
* @param field the field. |
||||
* @param calledClass the class in which the static method is |
||||
* declared. |
||||
* @param calledMethod the name of the static method. |
||||
*/ |
||||
public void replaceFieldRead(CtField field, |
||||
CtClass calledClass, String calledMethod) { |
||||
transformers = new com.fr.third.javassist.convert.TransformReadField(transformers, field, |
||||
calledClass.getName(), |
||||
calledMethod); |
||||
} |
||||
|
||||
/** |
||||
* Modify a method body so that an expression writing the specified |
||||
* field is replaced with a call to the specified static method. |
||||
* This static method receives two parameters: the target object of |
||||
* the original |
||||
* write expression and the assigned value. The return type of the |
||||
* static method is <code>void</code>. |
||||
* |
||||
* <p>For example, the program below |
||||
* |
||||
* <ul><pre>Point p = new Point(); |
||||
* p.x = 3;</pre></ul> |
||||
* |
||||
* <p>can be translated into: |
||||
* |
||||
* <ul><pre>Point p = new Point(); |
||||
* Accessor.writeX(3);</pre></ul> |
||||
* |
||||
* <p>where |
||||
* |
||||
* <ul><pre>public class Accessor { |
||||
* public static void writeX(Object target, int value) { ... } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>The type of the first parameter of <code>writeX()</code> must |
||||
* be <code>java.lang.Object</code> independently of the actual |
||||
* type of <code>target</code>. The type of the second parameter |
||||
* is the same as the field type. |
||||
* |
||||
* @param field the field. |
||||
* @param calledClass the class in which the static method is |
||||
* declared. |
||||
* @param calledMethod the name of the static method. |
||||
*/ |
||||
public void replaceFieldWrite(CtField field, |
||||
CtClass calledClass, String calledMethod) { |
||||
transformers = new com.fr.third.javassist.convert.TransformWriteField(transformers, field, |
||||
calledClass.getName(), |
||||
calledMethod); |
||||
} |
||||
|
||||
/** |
||||
* Modify a method body, so that ALL accesses to an array are replaced with |
||||
* calls to static methods within another class. In the case of reading an |
||||
* element from the array, this is replaced with a call to a static method with |
||||
* the array and the index as arguments, the return value is the value read from |
||||
* the array. If writing to an array, this is replaced with a call to a static |
||||
* method with the array, index and new value as parameters, the return value of |
||||
* the static method is <code>void</code>. |
||||
* |
||||
* <p>The <code>calledClass</code> parameter is the class containing the static methods to be used |
||||
* for array replacement. The <code>names</code> parameter points to an implementation of |
||||
* <code>ArrayAccessReplacementMethodNames</code> which specifies the names of the method to be |
||||
* used for access for each type of array. For example reading from an <code>int[]</code> will |
||||
* require a different method than if writing to an <code>int[]</code>, and writing to a <code>long[]</code> |
||||
* will require a different method than if writing to a <code>byte[]</code>. If the implementation |
||||
* of <code>ArrayAccessReplacementMethodNames</code> does not contain the name for access for a |
||||
* type of array, that access is not replaced. |
||||
* |
||||
* <p>A default implementation of <code>ArrayAccessReplacementMethodNames</code> called |
||||
* <code>DefaultArrayAccessReplacementMethodNames</code> has been provided and is what is used in the |
||||
* following example. This also assumes that <code>'foo.ArrayAdvisor'</code> is the name of the |
||||
* <code>CtClass</code> passed in. |
||||
* |
||||
* <p>If we have the following class: |
||||
* <pre>class POJO{ |
||||
* int[] ints = new int[]{1, 2, 3, 4, 5}; |
||||
* long[] longs = new int[]{10, 20, 30}; |
||||
* Object objects = new Object[]{true, false}; |
||||
* Integer[] integers = new Integer[]{new Integer(10)}; |
||||
* } |
||||
* </pre> |
||||
* and this is accessed as: |
||||
* <pre>POJO p = new POJO(); |
||||
* |
||||
* //Write to int array
|
||||
* p.ints[2] = 7; |
||||
* |
||||
* //Read from int array
|
||||
* int i = p.ints[2]; |
||||
* |
||||
* //Write to long array
|
||||
* p.longs[2] = 1000L; |
||||
* |
||||
* //Read from long array
|
||||
* long l = p.longs[2]; |
||||
* |
||||
* //Write to Object array
|
||||
* p.objects[2] = "Hello"; |
||||
* |
||||
* //Read from Object array
|
||||
* Object o = p.objects[2]; |
||||
* |
||||
* //Write to Integer array
|
||||
* Integer integer = new Integer(5); |
||||
* p.integers[0] = integer; |
||||
* |
||||
* //Read from Object array
|
||||
* integer = p.integers[0]; |
||||
* </pre> |
||||
* |
||||
* Following instrumentation we will have |
||||
* <pre>POJO p = new POJO(); |
||||
* |
||||
* //Write to int array
|
||||
* ArrayAdvisor.arrayWriteInt(p.ints, 2, 7); |
||||
* |
||||
* //Read from int array
|
||||
* int i = ArrayAdvisor.arrayReadInt(p.ints, 2); |
||||
* |
||||
* //Write to long array
|
||||
* ArrayAdvisor.arrayWriteLong(p.longs, 2, 1000L); |
||||
* |
||||
* //Read from long array
|
||||
* long l = ArrayAdvisor.arrayReadLong(p.longs, 2); |
||||
* |
||||
* //Write to Object array
|
||||
* ArrayAdvisor.arrayWriteObject(p.objects, 2, "Hello"); |
||||
* |
||||
* //Read from Object array
|
||||
* Object o = ArrayAdvisor.arrayReadObject(p.objects, 2); |
||||
* |
||||
* //Write to Integer array
|
||||
* Integer integer = new Integer(5); |
||||
* ArrayAdvisor.arrayWriteObject(p.integers, 0, integer); |
||||
* |
||||
* //Read from Object array
|
||||
* integer = ArrayAdvisor.arrayWriteObject(p.integers, 0); |
||||
* </pre> |
||||
* |
||||
* @see DefaultArrayAccessReplacementMethodNames |
||||
* |
||||
* @param calledClass the class containing the static methods. |
||||
* @param names contains the names of the methods to replace |
||||
* the different kinds of array access with. |
||||
*/ |
||||
public void replaceArrayAccess(CtClass calledClass, ArrayAccessReplacementMethodNames names) |
||||
throws NotFoundException |
||||
{ |
||||
transformers = new com.fr.third.javassist.convert.TransformAccessArrayField(transformers, calledClass.getName(), names); |
||||
} |
||||
|
||||
/** |
||||
* Modify method invocations in a method body so that a different |
||||
* method will be invoked. |
||||
* |
||||
* <p>Note that the target object, the parameters, or |
||||
* the type of invocation |
||||
* (static method call, interface call, or private method call) |
||||
* are not modified. Only the method name is changed. The substituted |
||||
* method must have the same signature that the original one has. |
||||
* If the original method is a static method, the substituted method |
||||
* must be static. |
||||
* |
||||
* @param origMethod original method |
||||
* @param substMethod substituted method |
||||
*/ |
||||
public void redirectMethodCall(CtMethod origMethod, |
||||
CtMethod substMethod) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
String d1 = origMethod.getMethodInfo2().getDescriptor(); |
||||
String d2 = substMethod.getMethodInfo2().getDescriptor(); |
||||
if (!d1.equals(d2)) |
||||
throw new com.fr.third.javassist.CannotCompileException("signature mismatch: " |
||||
+ substMethod.getLongName()); |
||||
|
||||
int mod1 = origMethod.getModifiers(); |
||||
int mod2 = substMethod.getModifiers(); |
||||
if (Modifier.isStatic(mod1) != Modifier.isStatic(mod2) |
||||
|| (Modifier.isPrivate(mod1) && !Modifier.isPrivate(mod2)) |
||||
|| origMethod.getDeclaringClass().isInterface() |
||||
!= substMethod.getDeclaringClass().isInterface()) |
||||
throw new com.fr.third.javassist.CannotCompileException("invoke-type mismatch " |
||||
+ substMethod.getLongName()); |
||||
|
||||
transformers = new com.fr.third.javassist.convert.TransformCall(transformers, origMethod, |
||||
substMethod); |
||||
} |
||||
|
||||
/** |
||||
* Correct invocations to a method that has been renamed. |
||||
* If a method is renamed, calls to that method must be also |
||||
* modified so that the method with the new name will be called. |
||||
* |
||||
* <p>The method must be declared in the same class before and |
||||
* after it is renamed. |
||||
* |
||||
* <p>Note that the target object, the parameters, or |
||||
* the type of invocation |
||||
* (static method call, interface call, or private method call) |
||||
* are not modified. Only the method name is changed. |
||||
* |
||||
* @param oldMethodName the old name of the method. |
||||
* @param newMethod the method with the new name. |
||||
* @see CtMethod#setName(String) |
||||
*/ |
||||
public void redirectMethodCall(String oldMethodName, |
||||
CtMethod newMethod) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
transformers |
||||
= new TransformCall(transformers, oldMethodName, newMethod); |
||||
} |
||||
|
||||
/** |
||||
* Insert a call to another method before an existing method call. |
||||
* That "before" method must be static. The return type must be |
||||
* <code>void</code>. As parameters, the before method receives |
||||
* the target object and all the parameters to the originally invoked |
||||
* method. For example, if the originally invoked method is |
||||
* <code>move()</code>: |
||||
* |
||||
* <ul><pre>class Point { |
||||
* Point move(int x, int y) { ... } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>Then the before method must be something like this: |
||||
* |
||||
* <ul><pre>class Verbose { |
||||
* static void print(Point target, int x, int y) { ... } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>The <code>CodeConverter</code> would translate bytecode |
||||
* equivalent to: |
||||
* |
||||
* <ul><pre>Point p2 = p.move(x + y, 0);</pre></ul> |
||||
* |
||||
* <p>into the bytecode equivalent to: |
||||
* |
||||
* <ul><pre>int tmp1 = x + y; |
||||
* int tmp2 = 0; |
||||
* Verbose.print(p, tmp1, tmp2); |
||||
* Point p2 = p.move(tmp1, tmp2);</pre></ul> |
||||
* |
||||
* @param origMethod the method originally invoked. |
||||
* @param beforeMethod the method invoked before |
||||
* <code>origMethod</code>. |
||||
*/ |
||||
public void insertBeforeMethod(CtMethod origMethod, |
||||
CtMethod beforeMethod) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
try { |
||||
transformers = new com.fr.third.javassist.convert.TransformBefore(transformers, origMethod, |
||||
beforeMethod); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Inserts a call to another method after an existing method call. |
||||
* That "after" method must be static. The return type must be |
||||
* <code>void</code>. As parameters, the after method receives |
||||
* the target object and all the parameters to the originally invoked |
||||
* method. For example, if the originally invoked method is |
||||
* <code>move()</code>: |
||||
* |
||||
* <ul><pre>class Point { |
||||
* Point move(int x, int y) { ... } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>Then the after method must be something like this: |
||||
* |
||||
* <ul><pre>class Verbose { |
||||
* static void print(Point target, int x, int y) { ... } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>The <code>CodeConverter</code> would translate bytecode |
||||
* equivalent to: |
||||
* |
||||
* <ul><pre>Point p2 = p.move(x + y, 0);</pre></ul> |
||||
* |
||||
* <p>into the bytecode equivalent to: |
||||
* |
||||
* <ul><pre>int tmp1 = x + y; |
||||
* int tmp2 = 0; |
||||
* Point p2 = p.move(tmp1, tmp2); |
||||
* Verbose.print(p, tmp1, tmp2);</pre></ul> |
||||
* |
||||
* @param origMethod the method originally invoked. |
||||
* @param afterMethod the method invoked after |
||||
* <code>origMethod</code>. |
||||
*/ |
||||
public void insertAfterMethod(CtMethod origMethod, |
||||
CtMethod afterMethod) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
try { |
||||
transformers = new com.fr.third.javassist.convert.TransformAfter(transformers, origMethod, |
||||
afterMethod); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Performs code conversion. |
||||
*/ |
||||
protected void doit(CtClass clazz, com.fr.third.javassist.bytecode.MethodInfo minfo, com.fr.third.javassist.bytecode.ConstPool cp) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
com.fr.third.javassist.convert.Transformer t; |
||||
CodeAttribute codeAttr = minfo.getCodeAttribute(); |
||||
if (codeAttr == null || transformers == null) |
||||
return; |
||||
for (t = transformers; t != null; t = t.getNext()) |
||||
t.initialize(cp, clazz, minfo); |
||||
|
||||
com.fr.third.javassist.bytecode.CodeIterator iterator = codeAttr.iterator(); |
||||
while (iterator.hasNext()) { |
||||
try { |
||||
int pos = iterator.next(); |
||||
for (t = transformers; t != null; t = t.getNext()) |
||||
pos = t.transform(clazz, pos, iterator, cp); |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
int locals = 0; |
||||
int stack = 0; |
||||
for (t = transformers; t != null; t = t.getNext()) { |
||||
int s = t.extraLocals(); |
||||
if (s > locals) |
||||
locals = s; |
||||
|
||||
s = t.extraStack(); |
||||
if (s > stack) |
||||
stack = s; |
||||
} |
||||
|
||||
for (t = transformers; t != null; t = t.getNext()) |
||||
t.clean(); |
||||
|
||||
if (locals > 0) |
||||
codeAttr.setMaxLocals(codeAttr.getMaxLocals() + locals); |
||||
|
||||
if (stack > 0) |
||||
codeAttr.setMaxStack(codeAttr.getMaxStack() + stack); |
||||
|
||||
try { |
||||
minfo.rebuildStackMapIf6(clazz.getClassPool(), |
||||
clazz.getClassFile2()); |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode b) { |
||||
throw new CannotCompileException(b.getMessage(), b); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Interface containing the method names to be used |
||||
* as array access replacements. |
||||
* |
||||
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a> |
||||
* @version $Revision: 1.16 $ |
||||
*/ |
||||
public interface ArrayAccessReplacementMethodNames |
||||
{ |
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;I)B</code> to replace reading from a byte[]. |
||||
*/ |
||||
String byteOrBooleanRead(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;IB)V</code> to replace writing to a byte[]. |
||||
*/ |
||||
String byteOrBooleanWrite(); |
||||
|
||||
/** |
||||
* @return the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;I)C</code> to replace reading from a char[]. |
||||
*/ |
||||
String charRead(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;IC)V</code> to replace writing to a byte[]. |
||||
*/ |
||||
String charWrite(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;I)D</code> to replace reading from a double[]. |
||||
*/ |
||||
String doubleRead(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;ID)V</code> to replace writing to a double[]. |
||||
*/ |
||||
String doubleWrite(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;I)F</code> to replace reading from a float[]. |
||||
*/ |
||||
String floatRead(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;IF)V</code> to replace writing to a float[]. |
||||
*/ |
||||
String floatWrite(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;I)I</code> to replace reading from a int[]. |
||||
*/ |
||||
String intRead(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;II)V</code> to replace writing to a int[]. |
||||
*/ |
||||
String intWrite(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;I)J</code> to replace reading from a long[]. |
||||
*/ |
||||
String longRead(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;IJ)V</code> to replace writing to a long[]. |
||||
*/ |
||||
String longWrite(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;I)Ljava/lang/Object;</code> |
||||
* to replace reading from a Object[] (or any subclass of object). |
||||
*/ |
||||
String objectRead(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;ILjava/lang/Object;)V</code> |
||||
* to replace writing to a Object[] (or any subclass of object). |
||||
*/ |
||||
String objectWrite(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;I)S</code> to replace reading from a short[]. |
||||
*/ |
||||
String shortRead(); |
||||
|
||||
/** |
||||
* Returns the name of a static method with the signature |
||||
* <code>(Ljava/lang/Object;IS)V</code> to replace writing to a short[]. |
||||
*/ |
||||
String shortWrite(); |
||||
} |
||||
|
||||
/** |
||||
* Default implementation of the <code>ArrayAccessReplacementMethodNames</code> |
||||
* interface giving default values for method names to be used for replacing |
||||
* accesses to array elements. |
||||
* |
||||
* @author <a href="kabir.khan@jboss.com">Kabir Khan</a> |
||||
* @version $Revision: 1.16 $ |
||||
*/ |
||||
public static class DefaultArrayAccessReplacementMethodNames |
||||
implements ArrayAccessReplacementMethodNames |
||||
{ |
||||
/** |
||||
* Returns "arrayReadByteOrBoolean" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;I)B to replace reading from a byte[]. |
||||
*/ |
||||
public String byteOrBooleanRead() |
||||
{ |
||||
return "arrayReadByteOrBoolean"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayWriteByteOrBoolean" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;IB)V to replace writing to a byte[]. |
||||
*/ |
||||
public String byteOrBooleanWrite() |
||||
{ |
||||
return "arrayWriteByteOrBoolean"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayReadChar" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;I)C to replace reading from a char[]. |
||||
*/ |
||||
public String charRead() |
||||
{ |
||||
return "arrayReadChar"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayWriteChar" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;IC)V to replace writing to a byte[]. |
||||
*/ |
||||
public String charWrite() |
||||
{ |
||||
return "arrayWriteChar"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayReadDouble" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;I)D to replace reading from a double[]. |
||||
*/ |
||||
public String doubleRead() |
||||
{ |
||||
return "arrayReadDouble"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayWriteDouble" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;ID)V to replace writing to a double[]. |
||||
*/ |
||||
public String doubleWrite() |
||||
{ |
||||
return "arrayWriteDouble"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayReadFloat" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;I)F to replace reading from a float[]. |
||||
*/ |
||||
public String floatRead() |
||||
{ |
||||
return "arrayReadFloat"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayWriteFloat" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;IF)V to replace writing to a float[]. |
||||
*/ |
||||
public String floatWrite() |
||||
{ |
||||
return "arrayWriteFloat"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayReadInt" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;I)I to replace reading from a int[]. |
||||
*/ |
||||
public String intRead() |
||||
{ |
||||
return "arrayReadInt"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayWriteInt" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;II)V to replace writing to a int[]. |
||||
*/ |
||||
public String intWrite() |
||||
{ |
||||
return "arrayWriteInt"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayReadLong" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;I)J to replace reading from a long[]. |
||||
*/ |
||||
public String longRead() |
||||
{ |
||||
return "arrayReadLong"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayWriteLong" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;IJ)V to replace writing to a long[]. |
||||
*/ |
||||
public String longWrite() |
||||
{ |
||||
return "arrayWriteLong"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayReadObject" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;I)Ljava/lang/Object; to replace reading from a Object[] (or any subclass of object). |
||||
*/ |
||||
public String objectRead() |
||||
{ |
||||
return "arrayReadObject"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayWriteObject" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;ILjava/lang/Object;)V to replace writing to a Object[] (or any subclass of object). |
||||
*/ |
||||
public String objectWrite() |
||||
{ |
||||
return "arrayWriteObject"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayReadShort" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;I)S to replace reading from a short[]. |
||||
*/ |
||||
public String shortRead() |
||||
{ |
||||
return "arrayReadShort"; |
||||
} |
||||
|
||||
/** |
||||
* Returns "arrayWriteShort" as the name of the static method with the signature |
||||
* (Ljava/lang/Object;IS)V to replace writing to a short[]. |
||||
*/ |
||||
public String shortWrite() |
||||
{ |
||||
return "arrayWriteShort"; |
||||
} |
||||
} |
||||
} |
@ -1,113 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
/** |
||||
* Array types. |
||||
*/ |
||||
final class CtArray extends CtClass { |
||||
protected com.fr.third.javassist.ClassPool pool; |
||||
|
||||
// the name of array type ends with "[]".
|
||||
CtArray(String name, com.fr.third.javassist.ClassPool cp) { |
||||
super(name); |
||||
pool = cp; |
||||
} |
||||
|
||||
public ClassPool getClassPool() { |
||||
return pool; |
||||
} |
||||
|
||||
public boolean isArray() { |
||||
return true; |
||||
} |
||||
|
||||
private CtClass[] interfaces = null; |
||||
|
||||
public int getModifiers() { |
||||
int mod = Modifier.FINAL; |
||||
try { |
||||
mod |= getComponentType().getModifiers() |
||||
& (Modifier.PROTECTED | Modifier.PUBLIC | Modifier.PRIVATE); |
||||
} |
||||
catch (NotFoundException e) {} |
||||
return mod; |
||||
} |
||||
|
||||
public CtClass[] getInterfaces() throws NotFoundException { |
||||
if (interfaces == null) { |
||||
Class[] intfs = Object[].class.getInterfaces(); |
||||
// java.lang.Cloneable and java.io.Serializable.
|
||||
// If the JVM is CLDC, intfs is empty.
|
||||
interfaces = new CtClass[intfs.length]; |
||||
for (int i = 0; i < intfs.length; i++) |
||||
interfaces[i] = pool.get(intfs[i].getName()); |
||||
} |
||||
|
||||
return interfaces; |
||||
} |
||||
|
||||
public boolean subtypeOf(CtClass clazz) throws NotFoundException { |
||||
if (super.subtypeOf(clazz)) |
||||
return true; |
||||
|
||||
String cname = clazz.getName(); |
||||
if (cname.equals(javaLangObject)) |
||||
return true; |
||||
|
||||
CtClass[] intfs = getInterfaces(); |
||||
for (int i = 0; i < intfs.length; i++) |
||||
if (intfs[i].subtypeOf(clazz)) |
||||
return true; |
||||
|
||||
return clazz.isArray() |
||||
&& getComponentType().subtypeOf(clazz.getComponentType()); |
||||
} |
||||
|
||||
public CtClass getComponentType() throws NotFoundException { |
||||
String name = getName(); |
||||
return pool.get(name.substring(0, name.length() - 2)); |
||||
} |
||||
|
||||
public CtClass getSuperclass() throws NotFoundException { |
||||
return pool.get(javaLangObject); |
||||
} |
||||
|
||||
public CtMethod[] getMethods() { |
||||
try { |
||||
return getSuperclass().getMethods(); |
||||
} |
||||
catch (NotFoundException e) { |
||||
return super.getMethods(); |
||||
} |
||||
} |
||||
|
||||
public CtMethod getMethod(String name, String desc) |
||||
throws NotFoundException |
||||
{ |
||||
return getSuperclass().getMethod(name, desc); |
||||
} |
||||
|
||||
public CtConstructor[] getConstructors() { |
||||
try { |
||||
return getSuperclass().getConstructors(); |
||||
} |
||||
catch (NotFoundException e) { |
||||
return super.getConstructors(); |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,403 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.CodeAttribute; |
||||
import com.fr.third.javassist.compiler.Javac; |
||||
import com.fr.third.javassist.compiler.CompileError; |
||||
|
||||
/** |
||||
* An instance of CtConstructor represents a constructor. |
||||
* It may represent a static constructor |
||||
* (class initializer). To distinguish a constructor and a class
|
||||
* initializer, call <code>isClassInitializer()</code>. |
||||
* |
||||
* <p>See the super class <code>CtBehavior</code> as well since |
||||
* a number of useful methods are in <code>CtBehavior</code>. |
||||
* |
||||
* @see com.fr.third.javassist.CtClass#getDeclaredConstructors() |
||||
* @see com.fr.third.javassist.CtClass#getClassInitializer() |
||||
* @see CtNewConstructor |
||||
*/ |
||||
public final class CtConstructor extends CtBehavior { |
||||
protected CtConstructor(com.fr.third.javassist.bytecode.MethodInfo minfo, com.fr.third.javassist.CtClass declaring) { |
||||
super(declaring, minfo); |
||||
} |
||||
|
||||
/** |
||||
* Creates a constructor with no constructor body. |
||||
* The created constructor |
||||
* must be added to a class with <code>CtClass.addConstructor()</code>. |
||||
* |
||||
* <p>The created constructor does not include a constructor body, |
||||
* which must be specified with <code>setBody()</code>. |
||||
* |
||||
* @param declaring the class to which the created method is added. |
||||
* @param parameters a list of the parameter types |
||||
* |
||||
* @see com.fr.third.javassist.CtClass#addConstructor(CtConstructor) |
||||
* @see CtConstructor#setBody(String) |
||||
* @see CtConstructor#setBody(CtConstructor, com.fr.third.javassist.ClassMap) |
||||
*/ |
||||
public CtConstructor(com.fr.third.javassist.CtClass[] parameters, com.fr.third.javassist.CtClass declaring) { |
||||
this((com.fr.third.javassist.bytecode.MethodInfo)null, declaring); |
||||
com.fr.third.javassist.bytecode.ConstPool cp = declaring.getClassFile2().getConstPool(); |
||||
String desc = com.fr.third.javassist.bytecode.Descriptor.ofConstructor(parameters); |
||||
methodInfo = new com.fr.third.javassist.bytecode.MethodInfo(cp, "<init>", desc); |
||||
setModifiers(Modifier.PUBLIC); |
||||
} |
||||
|
||||
/** |
||||
* Creates a copy of a <code>CtConstructor</code> object. |
||||
* The created constructor must be |
||||
* added to a class with <code>CtClass.addConstructor()</code>. |
||||
* |
||||
* <p>All occurrences of class names in the created constructor |
||||
* are replaced with names specified by |
||||
* <code>map</code> if <code>map</code> is not <code>null</code>. |
||||
* |
||||
* <p>By default, all the occurrences of the names of the class
|
||||
* declaring <code>src</code> and the superclass are replaced |
||||
* with the name of the class and the superclass that |
||||
* the created constructor is added to. |
||||
* This is done whichever <code>map</code> is null or not. |
||||
* To prevent this replacement, call <code>ClassMap.fix()</code> |
||||
* or <code>put()</code> to explicitly specify replacement. |
||||
* |
||||
* <p><b>Note:</b> if the <code>.class</code> notation (for example, |
||||
* <code>String.class</code>) is included in an expression, the |
||||
* Javac compiler may produce a helper method. |
||||
* Since this constructor never |
||||
* copies this helper method, the programmers have the responsiblity of |
||||
* copying it. Otherwise, use <code>Class.forName()</code> in the |
||||
* expression. |
||||
* |
||||
* @param src the source method. |
||||
* @param declaring the class to which the created method is added. |
||||
* @param map the hashtable associating original class names |
||||
* with substituted names. |
||||
* It can be <code>null</code>. |
||||
* |
||||
* @see com.fr.third.javassist.CtClass#addConstructor(CtConstructor) |
||||
* @see com.fr.third.javassist.ClassMap#fix(String) |
||||
*/ |
||||
public CtConstructor(CtConstructor src, com.fr.third.javassist.CtClass declaring, com.fr.third.javassist.ClassMap map) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
this((com.fr.third.javassist.bytecode.MethodInfo)null, declaring); |
||||
copy(src, true, map); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if this object represents a constructor. |
||||
*/ |
||||
public boolean isConstructor() { |
||||
return methodInfo.isConstructor(); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if this object represents a static initializer. |
||||
*/ |
||||
public boolean isClassInitializer() { |
||||
return methodInfo.isStaticInitializer(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the constructor name followed by parameter types |
||||
* such as <code>javassist.CtConstructor(CtClass[],CtClass)</code>. |
||||
* |
||||
* @since 3.5 |
||||
*/ |
||||
public String getLongName() { |
||||
return getDeclaringClass().getName() |
||||
+ (isConstructor() ? com.fr.third.javassist.bytecode.Descriptor.toString(getSignature()) |
||||
: ("." + com.fr.third.javassist.bytecode.MethodInfo.nameClinit + "()")); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the name of this constructor. |
||||
* It is the same as the simple name of the class declaring this |
||||
* constructor. If this object represents a class initializer, |
||||
* then this method returns <code>"<clinit>"</code>. |
||||
*/ |
||||
public String getName() { |
||||
if (methodInfo.isStaticInitializer()) |
||||
return com.fr.third.javassist.bytecode.MethodInfo.nameClinit; |
||||
else |
||||
return declaringClass.getSimpleName(); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the constructor (or static initializer) |
||||
* is the default one. This method returns true if the constructor |
||||
* takes some arguments but it does not perform anything except |
||||
* calling <code>super()</code> (the no-argument constructor of |
||||
* the super class). |
||||
*/ |
||||
public boolean isEmpty() { |
||||
com.fr.third.javassist.bytecode.CodeAttribute ca = getMethodInfo2().getCodeAttribute(); |
||||
if (ca == null) |
||||
return false; // native or abstract??
|
||||
// they are not allowed, though.
|
||||
|
||||
com.fr.third.javassist.bytecode.ConstPool cp = ca.getConstPool(); |
||||
com.fr.third.javassist.bytecode.CodeIterator it = ca.iterator(); |
||||
try { |
||||
int pos, desc; |
||||
int op0 = it.byteAt(it.next()); |
||||
return op0 == com.fr.third.javassist.bytecode.Opcode.RETURN // empty static initializer
|
||||
|| (op0 == com.fr.third.javassist.bytecode.Opcode.ALOAD_0 |
||||
&& it.byteAt(pos = it.next()) == com.fr.third.javassist.bytecode.Opcode.INVOKESPECIAL |
||||
&& (desc = cp.isConstructor(getSuperclassName(), |
||||
it.u16bitAt(pos + 1))) != 0 |
||||
&& "()V".equals(cp.getUtf8Info(desc)) |
||||
&& it.byteAt(it.next()) == com.fr.third.javassist.bytecode.Opcode.RETURN |
||||
&& !it.hasNext()); |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) {} |
||||
return false; |
||||
} |
||||
|
||||
private String getSuperclassName() { |
||||
com.fr.third.javassist.bytecode.ClassFile cf = declaringClass.getClassFile2(); |
||||
return cf.getSuperclass(); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if this constructor calls a constructor |
||||
* of the super class. This method returns false if it |
||||
* calls another constructor of this class by <code>this()</code>. |
||||
*/ |
||||
public boolean callsSuper() throws com.fr.third.javassist.CannotCompileException { |
||||
com.fr.third.javassist.bytecode.CodeAttribute codeAttr = methodInfo.getCodeAttribute(); |
||||
if (codeAttr != null) { |
||||
com.fr.third.javassist.bytecode.CodeIterator it = codeAttr.iterator(); |
||||
try { |
||||
int index = it.skipSuperConstructor(); |
||||
return index >= 0; |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Sets a constructor body. |
||||
* |
||||
* @param src the source code representing the constructor body. |
||||
* It must be a single statement or block. |
||||
* If it is <code>null</code>, the substituted |
||||
* constructor body does nothing except calling |
||||
* <code>super()</code>. |
||||
*/ |
||||
public void setBody(String src) throws com.fr.third.javassist.CannotCompileException { |
||||
if (src == null) |
||||
if (isClassInitializer()) |
||||
src = ";"; |
||||
else |
||||
src = "super();"; |
||||
|
||||
super.setBody(src); |
||||
} |
||||
|
||||
/** |
||||
* Copies a constructor body from another constructor. |
||||
* |
||||
* <p>All occurrences of the class names in the copied body |
||||
* are replaced with the names specified by |
||||
* <code>map</code> if <code>map</code> is not <code>null</code>. |
||||
* |
||||
* @param src the method that the body is copied from. |
||||
* @param map the hashtable associating original class names |
||||
* with substituted names. |
||||
* It can be <code>null</code>. |
||||
*/ |
||||
public void setBody(CtConstructor src, com.fr.third.javassist.ClassMap map) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
setBody0(src.declaringClass, src.methodInfo, |
||||
declaringClass, methodInfo, map); |
||||
} |
||||
|
||||
/** |
||||
* Inserts bytecode just after another constructor in the super class
|
||||
* or this class is called. |
||||
* It does not work if this object represents a class initializer. |
||||
* |
||||
* @param src the source code representing the inserted bytecode. |
||||
* It must be a single statement or block. |
||||
*/ |
||||
public void insertBeforeBody(String src) throws com.fr.third.javassist.CannotCompileException { |
||||
com.fr.third.javassist.CtClass cc = declaringClass; |
||||
cc.checkModify(); |
||||
if (isClassInitializer()) |
||||
throw new com.fr.third.javassist.CannotCompileException("class initializer"); |
||||
|
||||
com.fr.third.javassist.bytecode.CodeAttribute ca = methodInfo.getCodeAttribute(); |
||||
com.fr.third.javassist.bytecode.CodeIterator iterator = ca.iterator(); |
||||
com.fr.third.javassist.bytecode.Bytecode b = new com.fr.third.javassist.bytecode.Bytecode(methodInfo.getConstPool(), |
||||
ca.getMaxStack(), ca.getMaxLocals()); |
||||
b.setStackDepth(ca.getMaxStack()); |
||||
Javac jv = new Javac(b, cc); |
||||
try { |
||||
jv.recordParams(getParameterTypes(), false); |
||||
jv.compileStmnt(src); |
||||
ca.setMaxStack(b.getMaxStack()); |
||||
ca.setMaxLocals(b.getMaxLocals()); |
||||
iterator.skipConstructor(); |
||||
int pos = iterator.insertEx(b.get()); |
||||
iterator.insert(b.getExceptionTable(), pos); |
||||
methodInfo.rebuildStackMapIf6(cc.getClassPool(), cc.getClassFile2()); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
catch (CompileError e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
/* This method is called by addCatch() in CtBehavior. |
||||
* super() and this() must not be in a try statement. |
||||
*/ |
||||
int getStartPosOfBody(com.fr.third.javassist.bytecode.CodeAttribute ca) throws com.fr.third.javassist.CannotCompileException { |
||||
com.fr.third.javassist.bytecode.CodeIterator ci = ca.iterator(); |
||||
try { |
||||
ci.skipConstructor(); |
||||
return ci.next(); |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy of this constructor and converts it into a method. |
||||
* The signature of the mehtod is the same as the that of this constructor. |
||||
* The return type is <code>void</code>. The resulting method must be |
||||
* appended to the class specified by <code>declaring</code>. |
||||
* If this constructor is a static initializer, the resulting method takes |
||||
* no parameter. |
||||
* |
||||
* <p>An occurrence of another constructor call <code>this()</code> |
||||
* or a super constructor call <code>super()</code> is |
||||
* eliminated from the resulting method. |
||||
* |
||||
* <p>The immediate super class of the class declaring this constructor |
||||
* must be also a super class of the class declaring the resulting method. |
||||
* If the constructor accesses a field, the class declaring the resulting method |
||||
* must also declare a field with the same name and type. |
||||
* |
||||
* @param name the name of the resulting method. |
||||
* @param declaring the class declaring the resulting method. |
||||
*/ |
||||
public CtMethod toMethod(String name, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
return toMethod(name, declaring, null); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy of this constructor and converts it into a method. |
||||
* The signature of the method is the same as the that of this constructor. |
||||
* The return type is <code>void</code>. The resulting method must be |
||||
* appended to the class specified by <code>declaring</code>. |
||||
* If this constructor is a static initializer, the resulting method takes |
||||
* no parameter. |
||||
* |
||||
* <p>An occurrence of another constructor call <code>this()</code> |
||||
* or a super constructor call <code>super()</code> is |
||||
* eliminated from the resulting method. |
||||
* |
||||
* <p>The immediate super class of the class declaring this constructor |
||||
* must be also a super class of the class declaring the resulting method |
||||
* (this is obviously true if the second parameter <code>declaring</code> is |
||||
* the same as the class declaring this constructor). |
||||
* If the constructor accesses a field, the class declaring the resulting method |
||||
* must also declare a field with the same name and type. |
||||
* |
||||
* @param name the name of the resulting method. |
||||
* @param declaring the class declaring the resulting method. |
||||
* It is normally the same as the class declaring this |
||||
* constructor. |
||||
* @param map the hash table associating original class names |
||||
* with substituted names. The original class names will be |
||||
* replaced while making a copy. |
||||
* <code>map</code> can be <code>null</code>. |
||||
*/ |
||||
public CtMethod toMethod(String name, CtClass declaring, ClassMap map) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
CtMethod method = new CtMethod(null, declaring); |
||||
method.copy(this, false, map); |
||||
if (isConstructor()) { |
||||
com.fr.third.javassist.bytecode.MethodInfo minfo = method.getMethodInfo2(); |
||||
com.fr.third.javassist.bytecode.CodeAttribute ca = minfo.getCodeAttribute(); |
||||
if (ca != null) { |
||||
removeConsCall(ca); |
||||
try { |
||||
methodInfo.rebuildStackMapIf6(declaring.getClassPool(), |
||||
declaring.getClassFile2()); |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
} |
||||
|
||||
method.setName(name); |
||||
return method; |
||||
} |
||||
|
||||
private static void removeConsCall(CodeAttribute ca) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
com.fr.third.javassist.bytecode.CodeIterator iterator = ca.iterator(); |
||||
try { |
||||
int pos = iterator.skipConstructor(); |
||||
if (pos >= 0) { |
||||
int mref = iterator.u16bitAt(pos + 1); |
||||
String desc = ca.getConstPool().getMethodrefType(mref); |
||||
int num = com.fr.third.javassist.bytecode.Descriptor.numOfParameters(desc) + 1; |
||||
if (num > 3) |
||||
pos = iterator.insertGapAt(pos, num - 3, false).position; |
||||
|
||||
iterator.writeByte(com.fr.third.javassist.bytecode.Opcode.POP, pos++); // this
|
||||
iterator.writeByte(com.fr.third.javassist.bytecode.Opcode.NOP, pos); |
||||
iterator.writeByte(com.fr.third.javassist.bytecode.Opcode.NOP, pos + 1); |
||||
com.fr.third.javassist.bytecode.Descriptor.Iterator it = new com.fr.third.javassist.bytecode.Descriptor.Iterator(desc); |
||||
while (true) { |
||||
it.next(); |
||||
if (it.isParameter()) |
||||
iterator.writeByte(it.is2byte() ? com.fr.third.javassist.bytecode.Opcode.POP2 : com.fr.third.javassist.bytecode.Opcode.POP, |
||||
pos++); |
||||
else |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) { |
||||
throw new CannotCompileException(e); |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,322 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.AttributeInfo; |
||||
import com.fr.third.javassist.bytecode.SignatureAttribute; |
||||
|
||||
/** |
||||
* An instance of <code>CtMember</code> represents a field, a constructor, |
||||
* or a method. |
||||
*/ |
||||
public abstract class CtMember { |
||||
CtMember next; // for internal use
|
||||
protected com.fr.third.javassist.CtClass declaringClass; |
||||
|
||||
/* Make a circular link of CtMembers declared in the |
||||
* same class so that they are garbage-collected together |
||||
* at the same time. |
||||
*/ |
||||
static class Cache extends CtMember { |
||||
protected void extendToString(StringBuffer buffer) {} |
||||
public boolean hasAnnotation(Class clz) { return false; } |
||||
public Object getAnnotation(Class clz) |
||||
throws ClassNotFoundException { return null; } |
||||
public Object[] getAnnotations() |
||||
throws ClassNotFoundException { return null; } |
||||
public byte[] getAttribute(String name) { return null; } |
||||
public Object[] getAvailableAnnotations() { return null; } |
||||
public int getModifiers() { return 0; } |
||||
public String getName() { return null; } |
||||
public String getSignature() { return null; } |
||||
public void setAttribute(String name, byte[] data) {} |
||||
public void setModifiers(int mod) {} |
||||
public String getGenericSignature() { return null; } |
||||
public void setGenericSignature(String sig) {} |
||||
|
||||
private CtMember methodTail; |
||||
private CtMember consTail; // constructor tail
|
||||
private CtMember fieldTail; |
||||
|
||||
Cache(com.fr.third.javassist.CtClassType decl) { |
||||
super(decl); |
||||
methodTail = this; |
||||
consTail = this; |
||||
fieldTail = this; |
||||
fieldTail.next = this; |
||||
} |
||||
|
||||
CtMember methodHead() { return this; } |
||||
CtMember lastMethod() { return methodTail; } |
||||
CtMember consHead() { return methodTail; } // may include a static initializer
|
||||
CtMember lastCons() { return consTail; } |
||||
CtMember fieldHead() { return consTail; } |
||||
CtMember lastField() { return fieldTail; } |
||||
|
||||
void addMethod(CtMember method) { |
||||
method.next = methodTail.next; |
||||
methodTail.next = method; |
||||
if (methodTail == consTail) { |
||||
consTail = method; |
||||
if (methodTail == fieldTail) |
||||
fieldTail = method; |
||||
} |
||||
|
||||
methodTail = method; |
||||
} |
||||
|
||||
/* Both constructors and a class initializer. |
||||
*/ |
||||
void addConstructor(CtMember cons) { |
||||
cons.next = consTail.next; |
||||
consTail.next = cons; |
||||
if (consTail == fieldTail) |
||||
fieldTail = cons; |
||||
|
||||
consTail = cons; |
||||
} |
||||
|
||||
void addField(CtMember field) { |
||||
field.next = this; // or fieldTail.next
|
||||
fieldTail.next = field; |
||||
fieldTail = field; |
||||
} |
||||
|
||||
static int count(CtMember head, CtMember tail) { |
||||
int n = 0; |
||||
while (head != tail) { |
||||
n++; |
||||
head = head.next; |
||||
} |
||||
|
||||
return n; |
||||
} |
||||
|
||||
void remove(CtMember mem) { |
||||
CtMember m = this; |
||||
CtMember node; |
||||
while ((node = m.next) != this) { |
||||
if (node == mem) { |
||||
m.next = node.next; |
||||
if (node == methodTail) |
||||
methodTail = m; |
||||
|
||||
if (node == consTail) |
||||
consTail = m; |
||||
|
||||
if (node == fieldTail) |
||||
fieldTail = m; |
||||
|
||||
break; |
||||
} |
||||
else |
||||
m = m.next; |
||||
} |
||||
} |
||||
} |
||||
|
||||
protected CtMember(com.fr.third.javassist.CtClass clazz) { |
||||
declaringClass = clazz; |
||||
next = null; |
||||
} |
||||
|
||||
final CtMember next() { return next; } |
||||
|
||||
/** |
||||
* This method is invoked when setName() or replaceClassName() |
||||
* in CtClass is called. |
||||
* |
||||
* @see CtMethod#nameReplaced() |
||||
*/ |
||||
void nameReplaced() {} |
||||
|
||||
public String toString() { |
||||
StringBuffer buffer = new StringBuffer(getClass().getName()); |
||||
buffer.append("@"); |
||||
buffer.append(Integer.toHexString(hashCode())); |
||||
buffer.append("["); |
||||
buffer.append(Modifier.toString(getModifiers())); |
||||
extendToString(buffer); |
||||
buffer.append("]"); |
||||
return buffer.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Invoked by {@link #toString()} to add to the buffer and provide the |
||||
* complete value. Subclasses should invoke this method, adding a |
||||
* space before each token. The modifiers for the member are |
||||
* provided first; subclasses should provide additional data such |
||||
* as return type, field or method name, etc. |
||||
*/ |
||||
protected abstract void extendToString(StringBuffer buffer); |
||||
|
||||
/** |
||||
* Returns the class that declares this member. |
||||
*/ |
||||
public com.fr.third.javassist.CtClass getDeclaringClass() { return declaringClass; } |
||||
|
||||
/** |
||||
* Returns true if this member is accessible from the given class. |
||||
*/ |
||||
public boolean visibleFrom(com.fr.third.javassist.CtClass clazz) { |
||||
int mod = getModifiers(); |
||||
if (Modifier.isPublic(mod)) |
||||
return true; |
||||
else if (Modifier.isPrivate(mod)) |
||||
return clazz == declaringClass; |
||||
else { // package or protected
|
||||
String declName = declaringClass.getPackageName(); |
||||
String fromName = clazz.getPackageName(); |
||||
boolean visible; |
||||
if (declName == null) |
||||
visible = fromName == null; |
||||
else |
||||
visible = declName.equals(fromName); |
||||
|
||||
if (!visible && Modifier.isProtected(mod)) |
||||
return clazz.subclassOf(declaringClass); |
||||
|
||||
return visible; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Obtains the modifiers of the member. |
||||
* |
||||
* @return modifiers encoded with |
||||
* <code>javassist.Modifier</code>. |
||||
* @see Modifier |
||||
*/ |
||||
public abstract int getModifiers(); |
||||
|
||||
/** |
||||
* Sets the encoded modifiers of the member. |
||||
* |
||||
* @see Modifier |
||||
*/ |
||||
public abstract void setModifiers(int mod); |
||||
|
||||
/** |
||||
* Returns true if the class has the specified annotation class. |
||||
* |
||||
* @param clz the annotation class. |
||||
* @return <code>true</code> if the annotation is found, otherwise <code>false</code>. |
||||
* @since 3.11 |
||||
*/ |
||||
public abstract boolean hasAnnotation(Class clz); |
||||
|
||||
/** |
||||
* Returns the annotation if the class has the specified annotation class. |
||||
* For example, if an annotation <code>@Author</code> is associated |
||||
* with this member, an <code>Author</code> object is returned. |
||||
* The member values can be obtained by calling methods on |
||||
* the <code>Author</code> object. |
||||
* |
||||
* @param clz the annotation class. |
||||
* @return the annotation if found, otherwise <code>null</code>. |
||||
* @since 3.11 |
||||
*/ |
||||
public abstract Object getAnnotation(Class clz) throws ClassNotFoundException; |
||||
|
||||
/** |
||||
* Returns the annotations associated with this member. |
||||
* For example, if an annotation <code>@Author</code> is associated |
||||
* with this member, the returned array contains an <code>Author</code> |
||||
* object. The member values can be obtained by calling methods on |
||||
* the <code>Author</code> object. |
||||
* |
||||
* @return an array of annotation-type objects. |
||||
* @see com.fr.third.javassist.CtClass#getAnnotations() |
||||
*/ |
||||
public abstract Object[] getAnnotations() throws ClassNotFoundException; |
||||
|
||||
/** |
||||
* Returns the annotations associated with this member. |
||||
* This method is equivalent to <code>getAnnotations()</code> |
||||
* except that, if any annotations are not on the classpath, |
||||
* they are not included in the returned array. |
||||
* |
||||
* @return an array of annotation-type objects. |
||||
* @see #getAnnotations() |
||||
* @see com.fr.third.javassist.CtClass#getAvailableAnnotations() |
||||
* @since 3.3 |
||||
*/ |
||||
public abstract Object[] getAvailableAnnotations(); |
||||
|
||||
/** |
||||
* Obtains the name of the member. |
||||
* |
||||
* <p>As for constructor names, see <code>getName()</code> |
||||
* in <code>CtConstructor</code>. |
||||
* |
||||
* @see CtConstructor#getName() |
||||
*/ |
||||
public abstract String getName(); |
||||
|
||||
/** |
||||
* Returns the character string representing the signature of the member. |
||||
* If two members have the same signature (parameter types etc.), |
||||
* <code>getSignature()</code> returns the same string. |
||||
*/ |
||||
public abstract String getSignature(); |
||||
|
||||
/** |
||||
* Returns the generic signature of the member. |
||||
* |
||||
* @see SignatureAttribute#toFieldSignature(String) |
||||
* @see SignatureAttribute#toMethodSignature(String) |
||||
* @see com.fr.third.javassist.CtClass#getGenericSignature() |
||||
* @since 3.17 |
||||
*/ |
||||
public abstract String getGenericSignature(); |
||||
|
||||
/** |
||||
* Sets the generic signature of the member. |
||||
* |
||||
* @param sig a new generic signature. |
||||
* @see SignatureAttribute.ObjectType#encode() |
||||
* @see SignatureAttribute.MethodSignature#encode() |
||||
* @see CtClass#setGenericSignature(String) |
||||
* @since 3.17 |
||||
*/ |
||||
public abstract void setGenericSignature(String sig); |
||||
|
||||
/** |
||||
* Obtains a user-defined attribute with the given name. |
||||
* If that attribute is not found in the class file, this |
||||
* method returns null. |
||||
* |
||||
* <p>Note that an attribute is a data block specified by |
||||
* the class file format. |
||||
* See {@link AttributeInfo}. |
||||
* |
||||
* @param name attribute name |
||||
*/ |
||||
public abstract byte[] getAttribute(String name); |
||||
|
||||
/** |
||||
* Adds a user-defined attribute. The attribute is saved in the class file. |
||||
* |
||||
* <p>Note that an attribute is a data block specified by |
||||
* the class file format. |
||||
* See {@link AttributeInfo}. |
||||
* |
||||
* @param name attribute name |
||||
* @param data attribute value |
||||
*/ |
||||
public abstract void setAttribute(String name, byte[] data); |
||||
} |
@ -1,436 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.CodeAttribute; |
||||
|
||||
/** |
||||
* An instance of <code>CtMethod</code> represents a method. |
||||
* |
||||
* <p>See the super class <code>CtBehavior</code> since |
||||
* a number of useful methods are in <code>CtBehavior</code>. |
||||
* A number of useful factory methods are in <code>CtNewMethod</code>. |
||||
* |
||||
* @see com.fr.third.javassist.CtClass#getDeclaredMethods() |
||||
* @see CtNewMethod |
||||
*/ |
||||
public final class CtMethod extends CtBehavior { |
||||
protected String cachedStringRep; |
||||
|
||||
/** |
||||
* @see #make(com.fr.third.javassist.bytecode.MethodInfo minfo, com.fr.third.javassist.CtClass declaring) |
||||
*/ |
||||
CtMethod(com.fr.third.javassist.bytecode.MethodInfo minfo, com.fr.third.javassist.CtClass declaring) { |
||||
super(declaring, minfo); |
||||
cachedStringRep = null; |
||||
} |
||||
|
||||
/** |
||||
* Creates a public abstract method. The created method must be |
||||
* added to a class with <code>CtClass.addMethod()</code>. |
||||
* |
||||
* @param declaring the class to which the created method is added. |
||||
* @param returnType the type of the returned value |
||||
* @param mname the method name |
||||
* @param parameters a list of the parameter types |
||||
* |
||||
* @see com.fr.third.javassist.CtClass#addMethod(CtMethod) |
||||
*/ |
||||
public CtMethod(com.fr.third.javassist.CtClass returnType, String mname, |
||||
com.fr.third.javassist.CtClass[] parameters, com.fr.third.javassist.CtClass declaring) { |
||||
this(null, declaring); |
||||
com.fr.third.javassist.bytecode.ConstPool cp = declaring.getClassFile2().getConstPool(); |
||||
String desc = com.fr.third.javassist.bytecode.Descriptor.ofMethod(returnType, parameters); |
||||
methodInfo = new com.fr.third.javassist.bytecode.MethodInfo(cp, mname, desc); |
||||
setModifiers(Modifier.PUBLIC | Modifier.ABSTRACT); |
||||
} |
||||
|
||||
/** |
||||
* Creates a copy of a <code>CtMethod</code> object. |
||||
* The created method must be |
||||
* added to a class with <code>CtClass.addMethod()</code>. |
||||
* |
||||
* <p>All occurrences of class names in the created method |
||||
* are replaced with names specified by |
||||
* <code>map</code> if <code>map</code> is not <code>null</code>. |
||||
* |
||||
* <p>For example, suppose that a method <code>at()</code> is as |
||||
* follows: |
||||
* |
||||
* <ul><pre>public X at(int i) { |
||||
* return (X)super.elementAt(i); |
||||
* }</pre></ul> |
||||
* |
||||
* <p>(<code>X</code> is a class name.) If <code>map</code> substitutes |
||||
* <code>String</code> for <code>X</code>, then the created method is: |
||||
* |
||||
* <ul><pre>public String at(int i) { |
||||
* return (String)super.elementAt(i); |
||||
* }</pre></ul> |
||||
* |
||||
* <p>By default, all the occurrences of the names of the class
|
||||
* declaring <code>at()</code> and the superclass are replaced |
||||
* with the name of the class and the superclass that the |
||||
* created method is added to. |
||||
* This is done whichever <code>map</code> is null or not. |
||||
* To prevent this replacement, call <code>ClassMap.fix()</code> |
||||
* or <code>put()</code> to explicitly specify replacement. |
||||
* |
||||
* <p><b>Note:</b> if the <code>.class</code> notation (for example, |
||||
* <code>String.class</code>) is included in an expression, the |
||||
* Javac compiler may produce a helper method. |
||||
* Since this constructor never |
||||
* copies this helper method, the programmers have the responsiblity of |
||||
* copying it. Otherwise, use <code>Class.forName()</code> in the |
||||
* expression. |
||||
* |
||||
* @param src the source method. |
||||
* @param declaring the class to which the created method is added. |
||||
* @param map the hashtable associating original class names |
||||
* with substituted names. |
||||
* It can be <code>null</code>. |
||||
* |
||||
* @see com.fr.third.javassist.CtClass#addMethod(CtMethod) |
||||
* @see com.fr.third.javassist.ClassMap#fix(String) |
||||
*/ |
||||
public CtMethod(CtMethod src, com.fr.third.javassist.CtClass declaring, com.fr.third.javassist.ClassMap map) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
this(null, declaring); |
||||
copy(src, false, map); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the given source code and creates a method. |
||||
* This method simply delegates to <code>make()</code> in |
||||
* <code>CtNewMethod</code>. See it for more details. |
||||
* <code>CtNewMethod</code> has a number of useful factory methods. |
||||
* |
||||
* @param src the source text. |
||||
* @param declaring the class to which the created method is added. |
||||
* @see CtNewMethod#make(String, com.fr.third.javassist.CtClass) |
||||
*/ |
||||
public static CtMethod make(String src, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
return CtNewMethod.make(src, declaring); |
||||
} |
||||
|
||||
/** |
||||
* Creates a method from a <code>MethodInfo</code> object. |
||||
* |
||||
* @param declaring the class declaring the method. |
||||
* @throws com.fr.third.javassist.CannotCompileException if the the <code>MethodInfo</code> |
||||
* object and the declaring class have different |
||||
* <code>ConstPool</code> objects |
||||
* @since 3.6 |
||||
*/ |
||||
public static CtMethod make(com.fr.third.javassist.bytecode.MethodInfo minfo, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
if (declaring.getClassFile2().getConstPool() != minfo.getConstPool()) |
||||
throw new com.fr.third.javassist.CannotCompileException("bad declaring class"); |
||||
|
||||
return new CtMethod(minfo, declaring); |
||||
} |
||||
|
||||
/** |
||||
* Returns a hash code value for the method. |
||||
* If two methods have the same name and signature, then |
||||
* the hash codes for the two methods are equal. |
||||
*/ |
||||
public int hashCode() { |
||||
return getStringRep().hashCode(); |
||||
} |
||||
|
||||
/** |
||||
* This method is invoked when setName() or replaceClassName() |
||||
* in CtClass is called. |
||||
*/ |
||||
void nameReplaced() { |
||||
cachedStringRep = null; |
||||
} |
||||
|
||||
/* This method is also called by CtClassType.getMethods0(). |
||||
*/ |
||||
final String getStringRep() { |
||||
if (cachedStringRep == null) |
||||
cachedStringRep = methodInfo.getName() |
||||
+ com.fr.third.javassist.bytecode.Descriptor.getParamDescriptor(methodInfo.getDescriptor()); |
||||
|
||||
return cachedStringRep; |
||||
} |
||||
|
||||
/** |
||||
* Indicates whether <code>obj</code> has the same name and the |
||||
* same signature as this method. |
||||
*/ |
||||
public boolean equals(Object obj) { |
||||
return obj != null && obj instanceof CtMethod |
||||
&& ((CtMethod)obj).getStringRep().equals(getStringRep()); |
||||
} |
||||
|
||||
/** |
||||
* Returns the method name followed by parameter types |
||||
* such as <code>javassist.CtMethod.setBody(String)</code>. |
||||
* |
||||
* @since 3.5 |
||||
*/ |
||||
public String getLongName() { |
||||
return getDeclaringClass().getName() + "." |
||||
+ getName() + com.fr.third.javassist.bytecode.Descriptor.toString(getSignature()); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the name of this method. |
||||
*/ |
||||
public String getName() { |
||||
return methodInfo.getName(); |
||||
} |
||||
|
||||
/** |
||||
* Changes the name of this method. |
||||
*/ |
||||
public void setName(String newname) { |
||||
declaringClass.checkModify(); |
||||
methodInfo.setName(newname); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the type of the returned value. |
||||
*/ |
||||
public com.fr.third.javassist.CtClass getReturnType() throws NotFoundException { |
||||
return getReturnType0(); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the method body is empty, that is, <code>{}</code>. |
||||
* It also returns true if the method is an abstract method. |
||||
*/ |
||||
public boolean isEmpty() { |
||||
com.fr.third.javassist.bytecode.CodeAttribute ca = getMethodInfo2().getCodeAttribute(); |
||||
if (ca == null) // abstract or native
|
||||
return (getModifiers() & Modifier.ABSTRACT) != 0; |
||||
|
||||
com.fr.third.javassist.bytecode.CodeIterator it = ca.iterator(); |
||||
try { |
||||
return it.hasNext() && it.byteAt(it.next()) == com.fr.third.javassist.bytecode.Opcode.RETURN |
||||
&& !it.hasNext(); |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) {} |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Copies a method body from another method. |
||||
* If this method is abstract, the abstract modifier is removed |
||||
* after the method body is copied. |
||||
* |
||||
* <p>All occurrences of the class names in the copied method body |
||||
* are replaced with the names specified by |
||||
* <code>map</code> if <code>map</code> is not <code>null</code>. |
||||
* |
||||
* @param src the method that the body is copied from. |
||||
* @param map the hashtable associating original class names |
||||
* with substituted names. |
||||
* It can be <code>null</code>. |
||||
*/ |
||||
public void setBody(CtMethod src, ClassMap map) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
setBody0(src.declaringClass, src.methodInfo, |
||||
declaringClass, methodInfo, map); |
||||
} |
||||
|
||||
/** |
||||
* Replace a method body with a new method body wrapping the |
||||
* given method. |
||||
* |
||||
* @param mbody the wrapped method |
||||
* @param constParam the constant parameter given to |
||||
* the wrapped method |
||||
* (maybe <code>null</code>). |
||||
* |
||||
* @see CtNewMethod#wrapped(com.fr.third.javassist.CtClass,String, com.fr.third.javassist.CtClass[], com.fr.third.javassist.CtClass[],CtMethod,CtMethod.ConstParameter, com.fr.third.javassist.CtClass) |
||||
*/ |
||||
public void setWrappedBody(CtMethod mbody, ConstParameter constParam) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
declaringClass.checkModify(); |
||||
|
||||
com.fr.third.javassist.CtClass clazz = getDeclaringClass(); |
||||
com.fr.third.javassist.CtClass[] params; |
||||
com.fr.third.javassist.CtClass retType; |
||||
try { |
||||
params = getParameterTypes(); |
||||
retType = getReturnType(); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
|
||||
com.fr.third.javassist.bytecode.Bytecode code = CtNewWrappedMethod.makeBody(clazz, |
||||
clazz.getClassFile2(), |
||||
mbody, |
||||
params, retType, |
||||
constParam); |
||||
CodeAttribute cattr = code.toCodeAttribute(); |
||||
methodInfo.setCodeAttribute(cattr); |
||||
methodInfo.setAccessFlags(methodInfo.getAccessFlags() |
||||
& ~com.fr.third.javassist.bytecode.AccessFlag.ABSTRACT); |
||||
// rebuilding a stack map table is not needed.
|
||||
} |
||||
|
||||
// inner classes
|
||||
|
||||
/** |
||||
* Instances of this class represent a constant parameter. |
||||
* They are used to specify the parameter given to the methods |
||||
* created by <code>CtNewMethod.wrapped()</code>. |
||||
* |
||||
* @see CtMethod#setWrappedBody(CtMethod,CtMethod.ConstParameter) |
||||
* @see CtNewMethod#wrapped(com.fr.third.javassist.CtClass,String, com.fr.third.javassist.CtClass[], com.fr.third.javassist.CtClass[],CtMethod,CtMethod.ConstParameter, com.fr.third.javassist.CtClass) |
||||
* @see CtNewConstructor#make(com.fr.third.javassist.CtClass[], com.fr.third.javassist.CtClass[],int,CtMethod,CtMethod.ConstParameter, CtClass) |
||||
*/ |
||||
public static class ConstParameter { |
||||
/** |
||||
* Makes an integer constant. |
||||
* |
||||
* @param i the constant value. |
||||
*/ |
||||
public static ConstParameter integer(int i) { |
||||
return new IntConstParameter(i); |
||||
} |
||||
|
||||
/** |
||||
* Makes a long integer constant. |
||||
* |
||||
* @param i the constant value. |
||||
*/ |
||||
public static ConstParameter integer(long i) { |
||||
return new LongConstParameter(i); |
||||
} |
||||
|
||||
/** |
||||
* Makes an <code>String</code> constant. |
||||
* |
||||
* @param s the constant value. |
||||
*/ |
||||
public static ConstParameter string(String s) { |
||||
return new StringConstParameter(s); |
||||
} |
||||
|
||||
ConstParameter() {} |
||||
|
||||
/** |
||||
* @return the size of the stack consumption. |
||||
*/ |
||||
int compile(com.fr.third.javassist.bytecode.Bytecode code) throws com.fr.third.javassist.CannotCompileException { |
||||
return 0; |
||||
} |
||||
|
||||
String descriptor() { |
||||
return defaultDescriptor(); |
||||
} |
||||
|
||||
/** |
||||
* @see CtNewWrappedMethod |
||||
*/ |
||||
static String defaultDescriptor() { |
||||
return "([Ljava/lang/Object;)Ljava/lang/Object;"; |
||||
} |
||||
|
||||
/** |
||||
* Returns the descriptor for constructors. |
||||
* |
||||
* @see CtNewWrappedConstructor |
||||
*/ |
||||
String constDescriptor() { |
||||
return defaultConstDescriptor(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the default descriptor for constructors. |
||||
*/ |
||||
static String defaultConstDescriptor() { |
||||
return "([Ljava/lang/Object;)V"; |
||||
} |
||||
} |
||||
|
||||
static class IntConstParameter extends ConstParameter { |
||||
int param; |
||||
|
||||
IntConstParameter(int i) { |
||||
param = i; |
||||
} |
||||
|
||||
int compile(com.fr.third.javassist.bytecode.Bytecode code) throws com.fr.third.javassist.CannotCompileException { |
||||
code.addIconst(param); |
||||
return 1; |
||||
} |
||||
|
||||
String descriptor() { |
||||
return "([Ljava/lang/Object;I)Ljava/lang/Object;"; |
||||
} |
||||
|
||||
String constDescriptor() { |
||||
return "([Ljava/lang/Object;I)V"; |
||||
} |
||||
} |
||||
|
||||
static class LongConstParameter extends ConstParameter { |
||||
long param; |
||||
|
||||
LongConstParameter(long l) { |
||||
param = l; |
||||
} |
||||
|
||||
int compile(com.fr.third.javassist.bytecode.Bytecode code) throws com.fr.third.javassist.CannotCompileException { |
||||
code.addLconst(param); |
||||
return 2; |
||||
} |
||||
|
||||
String descriptor() { |
||||
return "([Ljava/lang/Object;J)Ljava/lang/Object;"; |
||||
} |
||||
|
||||
String constDescriptor() { |
||||
return "([Ljava/lang/Object;J)V"; |
||||
} |
||||
} |
||||
|
||||
static class StringConstParameter extends ConstParameter { |
||||
String param; |
||||
|
||||
StringConstParameter(String s) { |
||||
param = s; |
||||
} |
||||
|
||||
int compile(com.fr.third.javassist.bytecode.Bytecode code) throws CannotCompileException { |
||||
code.addLdc(param); |
||||
return 1; |
||||
} |
||||
|
||||
String descriptor() { |
||||
return "([Ljava/lang/Object;Ljava/lang/String;)Ljava/lang/Object;"; |
||||
} |
||||
|
||||
String constDescriptor() { |
||||
return "([Ljava/lang/Object;Ljava/lang/String;)V"; |
||||
} |
||||
} |
||||
} |
@ -1,127 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import java.io.DataOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
import com.fr.third.javassist.bytecode.ClassFile; |
||||
|
||||
class CtNewClass extends com.fr.third.javassist.CtClassType { |
||||
/* true if the class is an interface. |
||||
*/ |
||||
protected boolean hasConstructor; |
||||
|
||||
CtNewClass(String name, ClassPool cp, |
||||
boolean isInterface, com.fr.third.javassist.CtClass superclass) { |
||||
super(name, cp); |
||||
wasChanged = true; |
||||
String superName; |
||||
if (isInterface || superclass == null) |
||||
superName = null; |
||||
else |
||||
superName = superclass.getName(); |
||||
|
||||
classfile = new ClassFile(isInterface, name, superName); |
||||
if (isInterface && superclass != null) |
||||
classfile.setInterfaces(new String[] { superclass.getName() }); |
||||
|
||||
setModifiers(Modifier.setPublic(getModifiers())); |
||||
hasConstructor = isInterface; |
||||
} |
||||
|
||||
protected void extendToString(StringBuffer buffer) { |
||||
if (hasConstructor) |
||||
buffer.append("hasConstructor "); |
||||
|
||||
super.extendToString(buffer); |
||||
} |
||||
|
||||
public void addConstructor(com.fr.third.javassist.CtConstructor c) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
hasConstructor = true; |
||||
super.addConstructor(c); |
||||
} |
||||
|
||||
public void toBytecode(DataOutputStream out) |
||||
throws com.fr.third.javassist.CannotCompileException, IOException |
||||
{ |
||||
if (!hasConstructor) |
||||
try { |
||||
inheritAllConstructors(); |
||||
hasConstructor = true; |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
|
||||
super.toBytecode(out); |
||||
} |
||||
|
||||
/** |
||||
* Adds constructors inhrited from the super class. |
||||
* |
||||
* <p>After this method is called, the class inherits all the |
||||
* constructors from the super class. The added constructor |
||||
* calls the super's constructor with the same signature. |
||||
*/ |
||||
public void inheritAllConstructors() |
||||
throws com.fr.third.javassist.CannotCompileException, NotFoundException |
||||
{ |
||||
com.fr.third.javassist.CtClass superclazz; |
||||
com.fr.third.javassist.CtConstructor[] cs; |
||||
|
||||
superclazz = getSuperclass(); |
||||
cs = superclazz.getDeclaredConstructors(); |
||||
|
||||
int n = 0; |
||||
for (int i = 0; i < cs.length; ++i) { |
||||
com.fr.third.javassist.CtConstructor c = cs[i]; |
||||
int mod = c.getModifiers(); |
||||
if (isInheritable(mod, superclazz)) { |
||||
CtConstructor cons |
||||
= CtNewConstructor.make(c.getParameterTypes(), |
||||
c.getExceptionTypes(), this); |
||||
cons.setModifiers(mod & (Modifier.PUBLIC | Modifier.PROTECTED | Modifier.PRIVATE)); |
||||
addConstructor(cons); |
||||
++n; |
||||
} |
||||
} |
||||
|
||||
if (n < 1) |
||||
throw new CannotCompileException( |
||||
"no inheritable constructor in " + superclazz.getName()); |
||||
|
||||
} |
||||
|
||||
private boolean isInheritable(int mod, CtClass superclazz) { |
||||
if (Modifier.isPrivate(mod)) |
||||
return false; |
||||
|
||||
if (Modifier.isPackage(mod)) { |
||||
String pname = getPackageName(); |
||||
String pname2 = superclazz.getPackageName(); |
||||
if (pname == null) |
||||
return pname2 == null; |
||||
else |
||||
return pname.equals(pname2); |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
} |
@ -1,317 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
import com.fr.third.javassist.compiler.Javac; |
||||
import com.fr.third.javassist.compiler.CompileError; |
||||
import com.fr.third.javassist.CtMethod.ConstParameter; |
||||
|
||||
/** |
||||
* A collection of static methods for creating a <code>CtConstructor</code>. |
||||
* An instance of this class does not make any sense. |
||||
* |
||||
* <p>A class initializer (static constructor) cannot be created by the |
||||
* methods in this class. Call <code>makeClassInitializer()</code> in |
||||
* <code>CtClass</code> and append code snippet to the body of the class
|
||||
* initializer obtained by <code>makeClassInitializer()</code>. |
||||
* |
||||
* @see com.fr.third.javassist.CtClass#addConstructor(com.fr.third.javassist.CtConstructor) |
||||
* @see com.fr.third.javassist.CtClass#makeClassInitializer() |
||||
*/ |
||||
public class CtNewConstructor { |
||||
/** |
||||
* Specifies that no parameters are passed to a super-class' |
||||
* constructor. That is, the default constructor is invoked. |
||||
*/ |
||||
public static final int PASS_NONE = 0; // call super()
|
||||
|
||||
/** |
||||
* Specifies that parameters are converted into an array of |
||||
* <code>Object</code> and passed to a super-class' |
||||
* constructor. |
||||
*/ |
||||
public static final int PASS_ARRAY = 1; // an array of parameters
|
||||
|
||||
/** |
||||
* Specifies that parameters are passed <i>as is</i> |
||||
* to a super-class' constructor. The signature of that |
||||
* constructor must be the same as that of the created constructor. |
||||
*/ |
||||
public static final int PASS_PARAMS = 2; |
||||
|
||||
/** |
||||
* Compiles the given source code and creates a constructor. |
||||
* The source code must include not only the constructor body |
||||
* but the whole declaration. |
||||
* |
||||
* @param src the source text. |
||||
* @param declaring the class to which the created constructor is added. |
||||
*/ |
||||
public static com.fr.third.javassist.CtConstructor make(String src, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
Javac compiler = new Javac(declaring); |
||||
try { |
||||
CtMember obj = compiler.compile(src); |
||||
if (obj instanceof com.fr.third.javassist.CtConstructor) { |
||||
// a stack map table has been already created.
|
||||
return (com.fr.third.javassist.CtConstructor)obj; |
||||
} |
||||
} |
||||
catch (CompileError e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
|
||||
throw new com.fr.third.javassist.CannotCompileException("not a constructor"); |
||||
} |
||||
|
||||
/** |
||||
* Creates a public constructor. |
||||
* |
||||
* @param parameters a list of the parameter types. |
||||
* @param exceptions a list of the exception types. |
||||
* @param body the source text of the constructor body. |
||||
* It must be a block surrounded by <code>{}</code>. |
||||
* If it is <code>null</code>, the substituted |
||||
* constructor body does nothing except calling |
||||
* <code>super()</code>. |
||||
* @param declaring the class to which the created method is added. |
||||
*/ |
||||
public static com.fr.third.javassist.CtConstructor make(com.fr.third.javassist.CtClass[] parameters, |
||||
com.fr.third.javassist.CtClass[] exceptions, |
||||
String body, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
try { |
||||
com.fr.third.javassist.CtConstructor cc = new com.fr.third.javassist.CtConstructor(parameters, declaring); |
||||
cc.setExceptionTypes(exceptions); |
||||
cc.setBody(body); |
||||
return cc; |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a copy of a constructor. |
||||
* This is a convenience method for calling |
||||
* {@link com.fr.third.javassist.CtConstructor#CtConstructor(com.fr.third.javassist.CtConstructor, com.fr.third.javassist.CtClass, com.fr.third.javassist.ClassMap) this constructor}. |
||||
* See the description of the constructor for particular behavior of the copying. |
||||
* |
||||
* @param c the copied constructor. |
||||
* @param declaring the class to which the created method is added. |
||||
* @param map the hash table associating original class names |
||||
* with substituted names. |
||||
* It can be <code>null</code>. |
||||
* |
||||
* @see com.fr.third.javassist.CtConstructor#CtConstructor(com.fr.third.javassist.CtConstructor, com.fr.third.javassist.CtClass, com.fr.third.javassist.ClassMap) |
||||
*/ |
||||
public static com.fr.third.javassist.CtConstructor copy(com.fr.third.javassist.CtConstructor c, com.fr.third.javassist.CtClass declaring, |
||||
ClassMap map) throws com.fr.third.javassist.CannotCompileException { |
||||
return new com.fr.third.javassist.CtConstructor(c, declaring, map); |
||||
} |
||||
|
||||
/** |
||||
* Creates a default (public) constructor. |
||||
* |
||||
* <p>The created constructor takes no parameter. It calls |
||||
* <code>super()</code>. |
||||
*/ |
||||
public static com.fr.third.javassist.CtConstructor defaultConstructor(com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
com.fr.third.javassist.CtConstructor cons = new com.fr.third.javassist.CtConstructor((com.fr.third.javassist.CtClass[])null, declaring); |
||||
|
||||
ConstPool cp = declaring.getClassFile2().getConstPool(); |
||||
com.fr.third.javassist.bytecode.Bytecode code = new com.fr.third.javassist.bytecode.Bytecode(cp, 1, 1); |
||||
code.addAload(0); |
||||
try { |
||||
code.addInvokespecial(declaring.getSuperclass(), |
||||
"<init>", "()V"); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
|
||||
code.add(com.fr.third.javassist.bytecode.Bytecode.RETURN); |
||||
|
||||
// no need to construct a stack map table.
|
||||
cons.getMethodInfo2().setCodeAttribute(code.toCodeAttribute()); |
||||
return cons; |
||||
} |
||||
|
||||
/** |
||||
* Creates a public constructor that only calls a constructor |
||||
* in the super class. The created constructor receives parameters |
||||
* specified by <code>parameters</code> but calls the super's |
||||
* constructor without those parameters (that is, it calls the default |
||||
* constructor). |
||||
* |
||||
* <p>The parameters passed to the created constructor should be |
||||
* used for field initialization. <code>CtField.Initializer</code> |
||||
* objects implicitly insert initialization code in constructor |
||||
* bodies. |
||||
* |
||||
* @param parameters parameter types |
||||
* @param exceptions exception types |
||||
* @param declaring the class to which the created constructor |
||||
* is added. |
||||
* @see CtField.Initializer#byParameter(int) |
||||
*/ |
||||
public static com.fr.third.javassist.CtConstructor skeleton(com.fr.third.javassist.CtClass[] parameters, |
||||
com.fr.third.javassist.CtClass[] exceptions, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
return make(parameters, exceptions, PASS_NONE, |
||||
null, null, declaring); |
||||
} |
||||
|
||||
/** |
||||
* Creates a public constructor that only calls a constructor |
||||
* in the super class. The created constructor receives parameters |
||||
* specified by <code>parameters</code> and calls the super's |
||||
* constructor with those parameters. |
||||
* |
||||
* @param parameters parameter types |
||||
* @param exceptions exception types |
||||
* @param declaring the class to which the created constructor |
||||
* is added. |
||||
*/ |
||||
public static com.fr.third.javassist.CtConstructor make(com.fr.third.javassist.CtClass[] parameters, |
||||
com.fr.third.javassist.CtClass[] exceptions, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
return make(parameters, exceptions, PASS_PARAMS, |
||||
null, null, declaring); |
||||
} |
||||
|
||||
/** |
||||
* Creates a public constructor. |
||||
* |
||||
* <p>If <code>howto</code> is <code>PASS_PARAMS</code>, |
||||
* the created constructor calls the super's constructor with the |
||||
* same signature. The superclass must contain |
||||
* a constructor taking the same set of parameters as the created one. |
||||
* |
||||
* <p>If <code>howto</code> is <code>PASS_NONE</code>, |
||||
* the created constructor calls the super's default constructor. |
||||
* The superclass must contain a constructor taking no parameters. |
||||
* |
||||
* <p>If <code>howto</code> is <code>PASS_ARRAY</code>, |
||||
* the created constructor calls the super's constructor |
||||
* with the given parameters in the form of an array of |
||||
* <code>Object</code>. The signature of the super's constructor |
||||
* must be: |
||||
* |
||||
* <ul><code>constructor(Object[] params, <type> cvalue) |
||||
* </code></ul> |
||||
* |
||||
* <p>Here, <code>cvalue</code> is the constant value specified |
||||
* by <code>cparam</code>. |
||||
* |
||||
* <p>If <code>cparam</code> is <code>null</code>, the signature |
||||
* must be: |
||||
* |
||||
* <ul><code>constructor(Object[] params)</code></ul> |
||||
* |
||||
* <p>If <code>body</code> is not null, a copy of that method is |
||||
* embedded in the body of the created constructor. |
||||
* The embedded method is executed after |
||||
* the super's constructor is called and the values of fields are |
||||
* initialized. Note that <code>body</code> must not |
||||
* be a constructor but a method. |
||||
* |
||||
* <p>Since the embedded method is wrapped |
||||
* in parameter-conversion code |
||||
* as in <code>CtNewMethod.wrapped()</code>, |
||||
* the constructor parameters are |
||||
* passed in the form of an array of <code>Object</code>. |
||||
* The method specified by <code>body</code> must have the |
||||
* signature shown below: |
||||
* |
||||
* <ul><code>Object method(Object[] params, <type> cvalue) |
||||
* </code></ul> |
||||
* |
||||
* <p>If <code>cparam</code> is <code>null</code>, the signature |
||||
* must be: |
||||
* |
||||
* <ul><code>Object method(Object[] params)</code></ul> |
||||
* |
||||
* <p>Although the type of the returned value is <code>Object</code>, |
||||
* the value must be always <code>null</code>. |
||||
* |
||||
* <p><i>Example:</i> |
||||
* |
||||
* <ul><pre>ClassPool pool = ... ; |
||||
* CtClass xclass = pool.makeClass("X"); |
||||
* CtMethod method = pool.getMethod("Sample", "m"); |
||||
* xclass.setSuperclass(pool.get("Y")); |
||||
* CtClass[] argTypes = { CtClass.intType }; |
||||
* ConstParameter cparam = ConstParameter.string("test"); |
||||
* CtConstructor c = CtNewConstructor.make(argTypes, null, |
||||
* PASS_PARAMS, method, cparam, xclass); |
||||
* xclass.addConstructor(c);</pre></ul> |
||||
* |
||||
* <p>where the class <code>Sample</code> is as follows: |
||||
* |
||||
* <ul><pre>public class Sample { |
||||
* public Object m(Object[] args, String msg) { |
||||
* System.out.println(msg); |
||||
* return null; |
||||
* } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>This program produces the following class: |
||||
* |
||||
* <ul><pre>public class X extends Y { |
||||
* public X(int p0) { |
||||
* super(p0); |
||||
* String msg = "test"; |
||||
* Object[] args = new Object[] { p0 }; |
||||
* // begin of copied body
|
||||
* System.out.println(msg); |
||||
* Object result = null; |
||||
* // end
|
||||
* } |
||||
* }</pre></ul> |
||||
* |
||||
* @param parameters a list of the parameter types |
||||
* @param exceptions a list of the exceptions |
||||
* @param howto how to pass parameters to the super-class' |
||||
* constructor (<code>PASS_NONE</code>, |
||||
* <code>PASS_ARRAY</code>, |
||||
* or <code>PASS_PARAMS</code>) |
||||
* @param body appended body (may be <code>null</code>). |
||||
* It must be not a constructor but a method. |
||||
* @param cparam constant parameter (may be <code>null</code>.) |
||||
* @param declaring the class to which the created constructor |
||||
* is added. |
||||
* |
||||
* @see CtNewMethod#wrapped(com.fr.third.javassist.CtClass,String, com.fr.third.javassist.CtClass[], com.fr.third.javassist.CtClass[], com.fr.third.javassist.CtMethod, ConstParameter, com.fr.third.javassist.CtClass) |
||||
*/ |
||||
public static CtConstructor make(com.fr.third.javassist.CtClass[] parameters, |
||||
com.fr.third.javassist.CtClass[] exceptions, int howto, |
||||
CtMethod body, ConstParameter cparam, |
||||
CtClass declaring) |
||||
throws CannotCompileException |
||||
{ |
||||
return CtNewWrappedConstructor.wrapped(parameters, exceptions, |
||||
howto, body, cparam, declaring); |
||||
} |
||||
} |
@ -1,476 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
import com.fr.third.javassist.compiler.Javac; |
||||
import com.fr.third.javassist.compiler.CompileError; |
||||
import com.fr.third.javassist.CtMethod.ConstParameter; |
||||
|
||||
/** |
||||
* A collection of static methods for creating a <code>CtMethod</code>. |
||||
* An instance of this class does not make any sense. |
||||
* |
||||
* @see com.fr.third.javassist.CtClass#addMethod(com.fr.third.javassist.CtMethod) |
||||
*/ |
||||
public class CtNewMethod { |
||||
|
||||
/** |
||||
* Compiles the given source code and creates a method. |
||||
* The source code must include not only the method body |
||||
* but the whole declaration, for example, |
||||
* |
||||
* <ul><pre>"public Object id(Object obj) { return obj; }"</pre></ul> |
||||
* |
||||
* @param src the source text. |
||||
* @param declaring the class to which the created method is added. |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod make(String src, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
return make(src, declaring, null, null); |
||||
} |
||||
|
||||
/** |
||||
* Compiles the given source code and creates a method. |
||||
* The source code must include not only the method body |
||||
* but the whole declaration, for example, |
||||
* |
||||
* <ul><pre>"public Object id(Object obj) { return obj; }"</pre></ul> |
||||
* |
||||
* <p>If the source code includes <code>$proceed()</code>, then |
||||
* it is compiled into a method call on the specified object. |
||||
* |
||||
* @param src the source text. |
||||
* @param declaring the class to which the created method is added. |
||||
* @param delegateObj the source text specifying the object |
||||
* that is called on by <code>$proceed()</code>. |
||||
* @param delegateMethod the name of the method |
||||
* that is called by <code>$proceed()</code>. |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod make(String src, com.fr.third.javassist.CtClass declaring, |
||||
String delegateObj, String delegateMethod) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
Javac compiler = new Javac(declaring); |
||||
try { |
||||
if (delegateMethod != null) |
||||
compiler.recordProceed(delegateObj, delegateMethod); |
||||
|
||||
CtMember obj = compiler.compile(src); |
||||
if (obj instanceof com.fr.third.javassist.CtMethod) |
||||
return (com.fr.third.javassist.CtMethod)obj; |
||||
} |
||||
catch (CompileError e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
|
||||
throw new com.fr.third.javassist.CannotCompileException("not a method"); |
||||
} |
||||
|
||||
/** |
||||
* Creates a public (non-static) method. The created method cannot |
||||
* be changed to a static method later. |
||||
* |
||||
* @param returnType the type of the returned value. |
||||
* @param mname the method name. |
||||
* @param parameters a list of the parameter types. |
||||
* @param exceptions a list of the exception types. |
||||
* @param body the source text of the method body. |
||||
* It must be a block surrounded by <code>{}</code>. |
||||
* If it is <code>null</code>, the created method |
||||
* does nothing except returning zero or null. |
||||
* @param declaring the class to which the created method is added. |
||||
* @see #make(int, com.fr.third.javassist.CtClass, String, com.fr.third.javassist.CtClass[], com.fr.third.javassist.CtClass[], String, com.fr.third.javassist.CtClass) |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod make(com.fr.third.javassist.CtClass returnType, |
||||
String mname, com.fr.third.javassist.CtClass[] parameters, |
||||
com.fr.third.javassist.CtClass[] exceptions, |
||||
String body, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
return make(Modifier.PUBLIC, returnType, mname, parameters, exceptions, |
||||
body, declaring); |
||||
} |
||||
|
||||
/** |
||||
* Creates a method. <code>modifiers</code> can contain |
||||
* <code>Modifier.STATIC</code>. |
||||
* |
||||
* @param modifiers access modifiers. |
||||
* @param returnType the type of the returned value. |
||||
* @param mname the method name. |
||||
* @param parameters a list of the parameter types. |
||||
* @param exceptions a list of the exception types. |
||||
* @param body the source text of the method body. |
||||
* It must be a block surrounded by <code>{}</code>. |
||||
* If it is <code>null</code>, the created method |
||||
* does nothing except returning zero or null. |
||||
* @param declaring the class to which the created method is added. |
||||
* |
||||
* @see Modifier |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod make(int modifiers, com.fr.third.javassist.CtClass returnType, |
||||
String mname, com.fr.third.javassist.CtClass[] parameters, |
||||
com.fr.third.javassist.CtClass[] exceptions, |
||||
String body, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
try { |
||||
com.fr.third.javassist.CtMethod cm |
||||
= new com.fr.third.javassist.CtMethod(returnType, mname, parameters, declaring); |
||||
cm.setModifiers(modifiers); |
||||
cm.setExceptionTypes(exceptions); |
||||
cm.setBody(body); |
||||
return cm; |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Creates a copy of a method. This method is provided for creating |
||||
* a new method based on an existing method. |
||||
* This is a convenience method for calling |
||||
* {@link com.fr.third.javassist.CtMethod#CtMethod(com.fr.third.javassist.CtMethod, com.fr.third.javassist.CtClass, com.fr.third.javassist.ClassMap) this constructor}. |
||||
* See the description of the constructor for particular behavior of the copying. |
||||
* |
||||
* @param src the source method. |
||||
* @param declaring the class to which the created method is added. |
||||
* @param map the hash table associating original class names |
||||
* with substituted names. |
||||
* It can be <code>null</code>. |
||||
* |
||||
* @see com.fr.third.javassist.CtMethod#CtMethod(com.fr.third.javassist.CtMethod, com.fr.third.javassist.CtClass, com.fr.third.javassist.ClassMap) |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod copy(com.fr.third.javassist.CtMethod src, com.fr.third.javassist.CtClass declaring, |
||||
com.fr.third.javassist.ClassMap map) throws com.fr.third.javassist.CannotCompileException { |
||||
return new com.fr.third.javassist.CtMethod(src, declaring, map); |
||||
} |
||||
|
||||
/** |
||||
* Creates a copy of a method with a new name. |
||||
* This method is provided for creating |
||||
* a new method based on an existing method. |
||||
* This is a convenience method for calling |
||||
* {@link com.fr.third.javassist.CtMethod#CtMethod(com.fr.third.javassist.CtMethod, com.fr.third.javassist.CtClass, com.fr.third.javassist.ClassMap) this constructor}. |
||||
* See the description of the constructor for particular behavior of the copying. |
||||
* |
||||
* @param src the source method. |
||||
* @param name the name of the created method. |
||||
* @param declaring the class to which the created method is added. |
||||
* @param map the hash table associating original class names |
||||
* with substituted names. |
||||
* It can be <code>null</code>. |
||||
* |
||||
* @see com.fr.third.javassist.CtMethod#CtMethod(com.fr.third.javassist.CtMethod, com.fr.third.javassist.CtClass, com.fr.third.javassist.ClassMap) |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod copy(com.fr.third.javassist.CtMethod src, String name, com.fr.third.javassist.CtClass declaring, |
||||
ClassMap map) throws com.fr.third.javassist.CannotCompileException { |
||||
com.fr.third.javassist.CtMethod cm = new com.fr.third.javassist.CtMethod(src, declaring, map); |
||||
cm.setName(name); |
||||
return cm; |
||||
} |
||||
|
||||
/** |
||||
* Creates a public abstract method. |
||||
* |
||||
* @param returnType the type of the returned value |
||||
* @param mname the method name |
||||
* @param parameters a list of the parameter types |
||||
* @param exceptions a list of the exception types |
||||
* @param declaring the class to which the created method is added. |
||||
* |
||||
* @see com.fr.third.javassist.CtMethod#CtMethod(com.fr.third.javassist.CtClass,String, com.fr.third.javassist.CtClass[], com.fr.third.javassist.CtClass) |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod abstractMethod(com.fr.third.javassist.CtClass returnType, |
||||
String mname, |
||||
com.fr.third.javassist.CtClass[] parameters, |
||||
com.fr.third.javassist.CtClass[] exceptions, |
||||
com.fr.third.javassist.CtClass declaring) |
||||
throws NotFoundException |
||||
{ |
||||
com.fr.third.javassist.CtMethod cm = new com.fr.third.javassist.CtMethod(returnType, mname, parameters, declaring); |
||||
cm.setExceptionTypes(exceptions); |
||||
return cm; |
||||
} |
||||
|
||||
/** |
||||
* Creates a public getter method. The getter method returns the value |
||||
* of the specified field in the class to which this method is added. |
||||
* The created method is initially not static even if the field is |
||||
* static. Change the modifiers if the method should be static. |
||||
* |
||||
* @param methodName the name of the getter |
||||
* @param field the field accessed. |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod getter(String methodName, com.fr.third.javassist.CtField field) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
com.fr.third.javassist.bytecode.FieldInfo finfo = field.getFieldInfo2(); |
||||
String fieldType = finfo.getDescriptor(); |
||||
String desc = "()" + fieldType; |
||||
com.fr.third.javassist.bytecode.ConstPool cp = finfo.getConstPool(); |
||||
com.fr.third.javassist.bytecode.MethodInfo minfo = new com.fr.third.javassist.bytecode.MethodInfo(cp, methodName, desc); |
||||
minfo.setAccessFlags(com.fr.third.javassist.bytecode.AccessFlag.PUBLIC); |
||||
|
||||
com.fr.third.javassist.bytecode.Bytecode code = new com.fr.third.javassist.bytecode.Bytecode(cp, 2, 1); |
||||
try { |
||||
String fieldName = finfo.getName(); |
||||
if ((finfo.getAccessFlags() & com.fr.third.javassist.bytecode.AccessFlag.STATIC) == 0) { |
||||
code.addAload(0); |
||||
code.addGetfield(com.fr.third.javassist.bytecode.Bytecode.THIS, fieldName, fieldType); |
||||
} |
||||
else |
||||
code.addGetstatic(com.fr.third.javassist.bytecode.Bytecode.THIS, fieldName, fieldType); |
||||
|
||||
code.addReturn(field.getType()); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
|
||||
minfo.setCodeAttribute(code.toCodeAttribute()); |
||||
com.fr.third.javassist.CtClass cc = field.getDeclaringClass(); |
||||
// a stack map is not needed.
|
||||
return new com.fr.third.javassist.CtMethod(minfo, cc); |
||||
} |
||||
|
||||
/** |
||||
* Creates a public setter method. The setter method assigns the |
||||
* value of the first parameter to the specified field |
||||
* in the class to which this method is added. |
||||
* The created method is not static even if the field is |
||||
* static. You may not change it to be static |
||||
* by <code>setModifiers()</code> in <code>CtBehavior</code>. |
||||
* |
||||
* @param methodName the name of the setter |
||||
* @param field the field accessed. |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod setter(String methodName, CtField field) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
com.fr.third.javassist.bytecode.FieldInfo finfo = field.getFieldInfo2(); |
||||
String fieldType = finfo.getDescriptor(); |
||||
String desc = "(" + fieldType + ")V"; |
||||
com.fr.third.javassist.bytecode.ConstPool cp = finfo.getConstPool(); |
||||
com.fr.third.javassist.bytecode.MethodInfo minfo = new com.fr.third.javassist.bytecode.MethodInfo(cp, methodName, desc); |
||||
minfo.setAccessFlags(com.fr.third.javassist.bytecode.AccessFlag.PUBLIC); |
||||
|
||||
com.fr.third.javassist.bytecode.Bytecode code = new com.fr.third.javassist.bytecode.Bytecode(cp, 3, 3); |
||||
try { |
||||
String fieldName = finfo.getName(); |
||||
if ((finfo.getAccessFlags() & com.fr.third.javassist.bytecode.AccessFlag.STATIC) == 0) { |
||||
code.addAload(0); |
||||
code.addLoad(1, field.getType()); |
||||
code.addPutfield(com.fr.third.javassist.bytecode.Bytecode.THIS, fieldName, fieldType); |
||||
} |
||||
else { |
||||
code.addLoad(1, field.getType()); |
||||
code.addPutstatic(com.fr.third.javassist.bytecode.Bytecode.THIS, fieldName, fieldType); |
||||
} |
||||
|
||||
code.addReturn(null); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
|
||||
minfo.setCodeAttribute(code.toCodeAttribute()); |
||||
com.fr.third.javassist.CtClass cc = field.getDeclaringClass(); |
||||
// a stack map is not needed.
|
||||
return new com.fr.third.javassist.CtMethod(minfo, cc); |
||||
} |
||||
|
||||
/** |
||||
* Creates a method forwarding to a delegate in |
||||
* a super class. The created method calls a method specified |
||||
* by <code>delegate</code> with all the parameters passed to the |
||||
* created method. If the delegate method returns a value, |
||||
* the created method returns that value to the caller. |
||||
* The delegate method must be declared in a super class. |
||||
* |
||||
* <p>The following method is an example of the created method. |
||||
* |
||||
* <ul><pre>int f(int p, int q) { |
||||
* return super.f(p, q); |
||||
* }</pre></ul> |
||||
* |
||||
* <p>The name of the created method can be changed by |
||||
* <code>setName()</code>. |
||||
* |
||||
* @param delegate the method that the created method forwards to. |
||||
* @param declaring the class to which the created method is |
||||
* added. |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod delegator(com.fr.third.javassist.CtMethod delegate, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
try { |
||||
return delegator0(delegate, declaring); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
private static com.fr.third.javassist.CtMethod delegator0(com.fr.third.javassist.CtMethod delegate, com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException, NotFoundException |
||||
{ |
||||
com.fr.third.javassist.bytecode.MethodInfo deleInfo = delegate.getMethodInfo2(); |
||||
String methodName = deleInfo.getName(); |
||||
String desc = deleInfo.getDescriptor(); |
||||
ConstPool cp = declaring.getClassFile2().getConstPool(); |
||||
com.fr.third.javassist.bytecode.MethodInfo minfo = new com.fr.third.javassist.bytecode.MethodInfo(cp, methodName, desc); |
||||
minfo.setAccessFlags(deleInfo.getAccessFlags()); |
||||
|
||||
com.fr.third.javassist.bytecode.ExceptionsAttribute eattr = deleInfo.getExceptionsAttribute(); |
||||
if (eattr != null) |
||||
minfo.setExceptionsAttribute( |
||||
(com.fr.third.javassist.bytecode.ExceptionsAttribute)eattr.copy(cp, null)); |
||||
|
||||
com.fr.third.javassist.bytecode.Bytecode code = new com.fr.third.javassist.bytecode.Bytecode(cp, 0, 0); |
||||
boolean isStatic = Modifier.isStatic(delegate.getModifiers()); |
||||
com.fr.third.javassist.CtClass deleClass = delegate.getDeclaringClass(); |
||||
com.fr.third.javassist.CtClass[] params = delegate.getParameterTypes(); |
||||
int s; |
||||
if (isStatic) { |
||||
s = code.addLoadParameters(params, 0); |
||||
code.addInvokestatic(deleClass, methodName, desc); |
||||
} |
||||
else { |
||||
code.addLoad(0, deleClass); |
||||
s = code.addLoadParameters(params, 1); |
||||
code.addInvokespecial(deleClass, methodName, desc); |
||||
} |
||||
|
||||
code.addReturn(delegate.getReturnType()); |
||||
code.setMaxLocals(++s); |
||||
code.setMaxStack(s < 2 ? 2 : s); // for a 2-word return value
|
||||
minfo.setCodeAttribute(code.toCodeAttribute()); |
||||
// a stack map is not needed.
|
||||
return new com.fr.third.javassist.CtMethod(minfo, declaring); |
||||
} |
||||
|
||||
/** |
||||
* Creates a wrapped method. The wrapped method receives parameters |
||||
* in the form of an array of <code>Object</code>. |
||||
* |
||||
* <p>The body of the created method is a copy of the body of the method |
||||
* specified by <code>body</code>. However, it is wrapped in |
||||
* parameter-conversion code. |
||||
* |
||||
* <p>The method specified by <code>body</code> must have this singature: |
||||
* |
||||
* <ul><code>Object method(Object[] params, <type> cvalue) |
||||
* </code></ul> |
||||
* |
||||
* <p>The type of the <code>cvalue</code> depends on |
||||
* <code>constParam</code>. |
||||
* If <code>constParam</code> is <code>null</code>, the signature |
||||
* must be: |
||||
* |
||||
* <ul><code>Object method(Object[] params)</code></ul> |
||||
* |
||||
* <p>The method body copied from <code>body</code> is wrapped in |
||||
* parameter-conversion code, which converts parameters specified by |
||||
* <code>parameterTypes</code> into an array of <code>Object</code>. |
||||
* The returned value is also converted from the <code>Object</code> |
||||
* type to the type specified by <code>returnType</code>. Thus, |
||||
* the resulting method body is as follows: |
||||
* |
||||
* <ul><pre>Object[] params = new Object[] { p0, p1, ... }; |
||||
* <<i>type</i>> cvalue = <<i>constant-value</i>>; |
||||
* <i>... copied method body ...</i> |
||||
* Object result = <<i>returned value</i>> |
||||
* return (<i><returnType></i>)result; |
||||
* </pre></ul> |
||||
* |
||||
* <p>The variables <code>p0</code>, <code>p2</code>, ... represent |
||||
* formal parameters of the created method. |
||||
* The value of <code>cvalue</code> is specified by |
||||
* <code>constParam</code>. |
||||
* |
||||
* <p>If the type of a parameter or a returned value is a primitive |
||||
* type, then the value is converted into a wrapper object such as |
||||
* <code>java.lang.Integer</code>. If the type of the returned value |
||||
* is <code>void</code>, the returned value is discarded. |
||||
* |
||||
* <p><i>Example:</i> |
||||
* |
||||
* <ul><pre>ClassPool pool = ... ; |
||||
* CtClass vec = pool.makeClass("intVector"); |
||||
* vec.setSuperclass(pool.get("java.util.Vector")); |
||||
* CtMethod addMethod = pool.getMethod("Sample", "add0"); |
||||
* |
||||
* CtClass[] argTypes = { CtClass.intType }; |
||||
* CtMethod m = CtNewMethod.wrapped(CtClass.voidType, "add", argTypes, |
||||
* null, addMethod, null, vec); |
||||
* vec.addMethod(m);</pre></ul> |
||||
* |
||||
* <p>where the class <code>Sample</code> is as follows: |
||||
* |
||||
* <ul><pre>public class Sample extends java.util.Vector { |
||||
* public Object add0(Object[] args) { |
||||
* super.addElement(args[0]); |
||||
* return null; |
||||
* } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>This program produces a class <code>intVector</code>: |
||||
* |
||||
* <ul><pre>public class intVector extends java.util.Vector { |
||||
* public void add(int p0) { |
||||
* Object[] args = new Object[] { p0 }; |
||||
* // begin of the copied body
|
||||
* super.addElement(args[0]); |
||||
* Object result = null; |
||||
* // end
|
||||
* } |
||||
* }</pre></ul> |
||||
* |
||||
* <p>Note that the type of the parameter to <code>add()</code> depends |
||||
* only on the value of <code>argTypes</code> passed to |
||||
* <code>CtNewMethod.wrapped()</code>. Thus, it is easy to |
||||
* modify this program to produce a |
||||
* <code>StringVector</code> class, which is a vector containing |
||||
* only <code>String</code> objects, and other vector classes. |
||||
* |
||||
* @param returnType the type of the returned value. |
||||
* @param mname the method name. |
||||
* @param parameterTypes a list of the parameter types. |
||||
* @param exceptionTypes a list of the exception types. |
||||
* @param body the method body |
||||
* (must not be a static method). |
||||
* @param constParam the constant parameter |
||||
* (maybe <code>null</code>). |
||||
* @param declaring the class to which the created method is |
||||
* added. |
||||
*/ |
||||
public static com.fr.third.javassist.CtMethod wrapped(com.fr.third.javassist.CtClass returnType, |
||||
String mname, |
||||
com.fr.third.javassist.CtClass[] parameterTypes, |
||||
com.fr.third.javassist.CtClass[] exceptionTypes, |
||||
CtMethod body, ConstParameter constParam, |
||||
CtClass declaring) |
||||
throws CannotCompileException |
||||
{ |
||||
return CtNewWrappedMethod.wrapped(returnType, mname, parameterTypes, |
||||
exceptionTypes, body, constParam, declaring); |
||||
} |
||||
} |
@ -1,67 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.ClassFile; |
||||
import com.fr.third.javassist.bytecode.AccessFlag; |
||||
import com.fr.third.javassist.bytecode.InnerClassesAttribute; |
||||
|
||||
/** |
||||
* A newly created public nested class. |
||||
*/ |
||||
class CtNewNestedClass extends com.fr.third.javassist.CtNewClass { |
||||
CtNewNestedClass(String realName, ClassPool cp, boolean isInterface, |
||||
com.fr.third.javassist.CtClass superclass) { |
||||
super(realName, cp, isInterface, superclass); |
||||
} |
||||
|
||||
/** |
||||
* This method does not change the STATIC bit. The original value is kept. |
||||
*/ |
||||
public void setModifiers(int mod) { |
||||
mod = mod & ~Modifier.STATIC; |
||||
super.setModifiers(mod); |
||||
updateInnerEntry(mod, getName(), this, true); |
||||
} |
||||
|
||||
private static void updateInnerEntry(int mod, String name, com.fr.third.javassist.CtClass clazz, boolean outer) { |
||||
ClassFile cf = clazz.getClassFile2(); |
||||
InnerClassesAttribute ica = (InnerClassesAttribute)cf.getAttribute( |
||||
InnerClassesAttribute.tag); |
||||
if (ica == null) |
||||
return; |
||||
|
||||
int n = ica.tableLength(); |
||||
for (int i = 0; i < n; i++) |
||||
if (name.equals(ica.innerClass(i))) { |
||||
int acc = ica.accessFlags(i) & AccessFlag.STATIC; |
||||
ica.setAccessFlags(i, mod | acc); |
||||
String outName = ica.outerClass(i); |
||||
if (outName != null && outer) |
||||
try { |
||||
CtClass parent = clazz.getClassPool().get(outName); |
||||
updateInnerEntry(mod, name, parent, false); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new RuntimeException("cannot find the declaring class: " |
||||
+ outName); |
||||
} |
||||
|
||||
break; |
||||
} |
||||
} |
||||
} |
@ -1,103 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.ClassFile; |
||||
import com.fr.third.javassist.CtMethod.ConstParameter; |
||||
|
||||
class CtNewWrappedConstructor extends CtNewWrappedMethod { |
||||
private static final int PASS_NONE = com.fr.third.javassist.CtNewConstructor.PASS_NONE; |
||||
// private static final int PASS_ARRAY = CtNewConstructor.PASS_ARRAY;
|
||||
private static final int PASS_PARAMS = CtNewConstructor.PASS_PARAMS; |
||||
|
||||
public static com.fr.third.javassist.CtConstructor wrapped(com.fr.third.javassist.CtClass[] parameterTypes, |
||||
com.fr.third.javassist.CtClass[] exceptionTypes, |
||||
int howToCallSuper, |
||||
com.fr.third.javassist.CtMethod body, |
||||
ConstParameter constParam, |
||||
com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
try { |
||||
com.fr.third.javassist.CtConstructor cons = new CtConstructor(parameterTypes, declaring); |
||||
cons.setExceptionTypes(exceptionTypes); |
||||
com.fr.third.javassist.bytecode.Bytecode code = makeBody(declaring, declaring.getClassFile2(), |
||||
howToCallSuper, body, |
||||
parameterTypes, constParam); |
||||
cons.getMethodInfo2().setCodeAttribute(code.toCodeAttribute()); |
||||
// a stack map table is not needed.
|
||||
return cons; |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
protected static com.fr.third.javassist.bytecode.Bytecode makeBody(com.fr.third.javassist.CtClass declaring, ClassFile classfile, |
||||
int howToCallSuper, |
||||
CtMethod wrappedBody, |
||||
com.fr.third.javassist.CtClass[] parameters, |
||||
ConstParameter cparam) |
||||
throws CannotCompileException |
||||
{ |
||||
int stacksize, stacksize2; |
||||
|
||||
int superclazz = classfile.getSuperclassId(); |
||||
com.fr.third.javassist.bytecode.Bytecode code = new com.fr.third.javassist.bytecode.Bytecode(classfile.getConstPool(), 0, 0); |
||||
code.setMaxLocals(false, parameters, 0); |
||||
code.addAload(0); |
||||
if (howToCallSuper == PASS_NONE) { |
||||
stacksize = 1; |
||||
code.addInvokespecial(superclazz, "<init>", "()V"); |
||||
} |
||||
else if (howToCallSuper == PASS_PARAMS) { |
||||
stacksize = code.addLoadParameters(parameters, 1) + 1; |
||||
code.addInvokespecial(superclazz, "<init>", |
||||
com.fr.third.javassist.bytecode.Descriptor.ofConstructor(parameters)); |
||||
} |
||||
else { |
||||
stacksize = compileParameterList(code, parameters, 1); |
||||
String desc; |
||||
if (cparam == null) { |
||||
stacksize2 = 2; |
||||
desc = ConstParameter.defaultConstDescriptor(); |
||||
} |
||||
else { |
||||
stacksize2 = cparam.compile(code) + 2; |
||||
desc = cparam.constDescriptor(); |
||||
} |
||||
|
||||
if (stacksize < stacksize2) |
||||
stacksize = stacksize2; |
||||
|
||||
code.addInvokespecial(superclazz, "<init>", desc); |
||||
} |
||||
|
||||
if (wrappedBody == null) |
||||
code.add(com.fr.third.javassist.bytecode.Bytecode.RETURN); |
||||
else { |
||||
stacksize2 = makeBody0(declaring, classfile, wrappedBody, |
||||
false, parameters, CtClass.voidType, |
||||
cparam, code); |
||||
if (stacksize < stacksize2) |
||||
stacksize = stacksize2; |
||||
} |
||||
|
||||
code.setMaxStack(stacksize); |
||||
return code; |
||||
} |
||||
} |
@ -1,199 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.SyntheticAttribute; |
||||
import com.fr.third.javassist.compiler.JvstCodeGen; |
||||
import java.util.Hashtable; |
||||
import com.fr.third.javassist.CtMethod.ConstParameter; |
||||
|
||||
class CtNewWrappedMethod { |
||||
|
||||
private static final String addedWrappedMethod = "_added_m$"; |
||||
|
||||
public static com.fr.third.javassist.CtMethod wrapped(com.fr.third.javassist.CtClass returnType, String mname, |
||||
com.fr.third.javassist.CtClass[] parameterTypes, |
||||
com.fr.third.javassist.CtClass[] exceptionTypes, |
||||
com.fr.third.javassist.CtMethod body, ConstParameter constParam, |
||||
com.fr.third.javassist.CtClass declaring) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
com.fr.third.javassist.CtMethod mt = new com.fr.third.javassist.CtMethod(returnType, mname, parameterTypes, |
||||
declaring); |
||||
mt.setModifiers(body.getModifiers()); |
||||
try { |
||||
mt.setExceptionTypes(exceptionTypes); |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
|
||||
com.fr.third.javassist.bytecode.Bytecode code = makeBody(declaring, declaring.getClassFile2(), body, |
||||
parameterTypes, returnType, constParam); |
||||
com.fr.third.javassist.bytecode.MethodInfo minfo = mt.getMethodInfo2(); |
||||
minfo.setCodeAttribute(code.toCodeAttribute()); |
||||
// a stack map has been already created.
|
||||
return mt; |
||||
} |
||||
|
||||
static com.fr.third.javassist.bytecode.Bytecode makeBody(com.fr.third.javassist.CtClass clazz, com.fr.third.javassist.bytecode.ClassFile classfile, |
||||
com.fr.third.javassist.CtMethod wrappedBody, |
||||
com.fr.third.javassist.CtClass[] parameters, |
||||
com.fr.third.javassist.CtClass returnType, |
||||
ConstParameter cparam) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
boolean isStatic = Modifier.isStatic(wrappedBody.getModifiers()); |
||||
com.fr.third.javassist.bytecode.Bytecode code = new com.fr.third.javassist.bytecode.Bytecode(classfile.getConstPool(), 0, 0); |
||||
int stacksize = makeBody0(clazz, classfile, wrappedBody, isStatic, |
||||
parameters, returnType, cparam, code); |
||||
code.setMaxStack(stacksize); |
||||
code.setMaxLocals(isStatic, parameters, 0); |
||||
return code; |
||||
} |
||||
|
||||
/* The generated method body does not need a stack map table |
||||
* because it does not contain a branch instruction. |
||||
*/ |
||||
protected static int makeBody0(com.fr.third.javassist.CtClass clazz, com.fr.third.javassist.bytecode.ClassFile classfile, |
||||
com.fr.third.javassist.CtMethod wrappedBody, |
||||
boolean isStatic, com.fr.third.javassist.CtClass[] parameters, |
||||
com.fr.third.javassist.CtClass returnType, ConstParameter cparam, |
||||
com.fr.third.javassist.bytecode.Bytecode code) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
if (!(clazz instanceof com.fr.third.javassist.CtClassType)) |
||||
throw new com.fr.third.javassist.CannotCompileException("bad declaring class" |
||||
+ clazz.getName()); |
||||
|
||||
if (!isStatic) |
||||
code.addAload(0); |
||||
|
||||
int stacksize = compileParameterList(code, parameters, |
||||
(isStatic ? 0 : 1)); |
||||
int stacksize2; |
||||
String desc; |
||||
if (cparam == null) { |
||||
stacksize2 = 0; |
||||
desc = ConstParameter.defaultDescriptor(); |
||||
} |
||||
else { |
||||
stacksize2 = cparam.compile(code); |
||||
desc = cparam.descriptor(); |
||||
} |
||||
|
||||
checkSignature(wrappedBody, desc); |
||||
|
||||
String bodyname; |
||||
try { |
||||
bodyname = addBodyMethod((com.fr.third.javassist.CtClassType)clazz, classfile, |
||||
wrappedBody); |
||||
/* if an exception is thrown below, the method added above |
||||
* should be removed. (future work :<) |
||||
*/ |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
|
||||
if (isStatic) |
||||
code.addInvokestatic(com.fr.third.javassist.bytecode.Bytecode.THIS, bodyname, desc); |
||||
else |
||||
code.addInvokespecial(com.fr.third.javassist.bytecode.Bytecode.THIS, bodyname, desc); |
||||
|
||||
compileReturn(code, returnType); // consumes 2 stack entries
|
||||
|
||||
if (stacksize < stacksize2 + 2) |
||||
stacksize = stacksize2 + 2; |
||||
|
||||
return stacksize; |
||||
} |
||||
|
||||
private static void checkSignature(com.fr.third.javassist.CtMethod wrappedBody, |
||||
String descriptor) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
if (!descriptor.equals(wrappedBody.getMethodInfo2().getDescriptor())) |
||||
throw new com.fr.third.javassist.CannotCompileException( |
||||
"wrapped method with a bad signature: " |
||||
+ wrappedBody.getDeclaringClass().getName() |
||||
+ '.' + wrappedBody.getName()); |
||||
} |
||||
|
||||
private static String addBodyMethod(com.fr.third.javassist.CtClassType clazz, |
||||
com.fr.third.javassist.bytecode.ClassFile classfile, |
||||
com.fr.third.javassist.CtMethod src) |
||||
throws com.fr.third.javassist.bytecode.BadBytecode, CannotCompileException |
||||
{ |
||||
Hashtable bodies = clazz.getHiddenMethods(); |
||||
String bodyname = (String)bodies.get(src); |
||||
if (bodyname == null) { |
||||
do { |
||||
bodyname = addedWrappedMethod + clazz.getUniqueNumber(); |
||||
} while (classfile.getMethod(bodyname) != null); |
||||
com.fr.third.javassist.ClassMap map = new ClassMap(); |
||||
map.put(src.getDeclaringClass().getName(), clazz.getName()); |
||||
com.fr.third.javassist.bytecode.MethodInfo body = new com.fr.third.javassist.bytecode.MethodInfo(classfile.getConstPool(), |
||||
bodyname, src.getMethodInfo2(), |
||||
map); |
||||
int acc = body.getAccessFlags(); |
||||
body.setAccessFlags(com.fr.third.javassist.bytecode.AccessFlag.setPrivate(acc)); |
||||
body.addAttribute(new SyntheticAttribute(classfile.getConstPool())); |
||||
// a stack map is copied. rebuilding it is not needed.
|
||||
classfile.addMethod(body); |
||||
bodies.put(src, bodyname); |
||||
CtMember.Cache cache = clazz.hasMemberCache(); |
||||
if (cache != null) |
||||
cache.addMethod(new CtMethod(body, clazz)); |
||||
} |
||||
|
||||
return bodyname; |
||||
} |
||||
|
||||
/* compileParameterList() returns the stack size used |
||||
* by the produced code. |
||||
* |
||||
* @param regno the index of the local variable in which |
||||
* the first argument is received. |
||||
* (0: static method, 1: regular method.) |
||||
*/ |
||||
static int compileParameterList(com.fr.third.javassist.bytecode.Bytecode code, |
||||
com.fr.third.javassist.CtClass[] params, int regno) { |
||||
return JvstCodeGen.compileParameterList(code, params, regno); |
||||
} |
||||
|
||||
/* |
||||
* The produced codes cosume 1 or 2 stack entries. |
||||
*/ |
||||
private static void compileReturn(com.fr.third.javassist.bytecode.Bytecode code, com.fr.third.javassist.CtClass type) { |
||||
if (type.isPrimitive()) { |
||||
CtPrimitiveType pt = (CtPrimitiveType)type; |
||||
if (pt != CtClass.voidType) { |
||||
String wrapper = pt.getWrapperName(); |
||||
code.addCheckcast(wrapper); |
||||
code.addInvokevirtual(wrapper, pt.getGetMethodName(), |
||||
pt.getGetMethodDescriptor()); |
||||
} |
||||
|
||||
code.addOpcode(pt.getReturnOp()); |
||||
} |
||||
else { |
||||
code.addCheckcast(type); |
||||
code.addOpcode(com.fr.third.javassist.bytecode.Bytecode.ARETURN); |
||||
} |
||||
} |
||||
} |
@ -1,112 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
/** |
||||
* An instance of <code>CtPrimitiveType</code> represents a primitive type. |
||||
* It is obtained from <code>CtClass</code>. |
||||
*/ |
||||
public final class CtPrimitiveType extends CtClass { |
||||
private char descriptor; |
||||
private String wrapperName; |
||||
private String getMethodName; |
||||
private String mDescriptor; |
||||
private int returnOp; |
||||
private int arrayType; |
||||
private int dataSize; |
||||
|
||||
CtPrimitiveType(String name, char desc, String wrapper, |
||||
String methodName, String mDesc, int opcode, int atype, |
||||
int size) { |
||||
super(name); |
||||
descriptor = desc; |
||||
wrapperName = wrapper; |
||||
getMethodName = methodName; |
||||
mDescriptor = mDesc; |
||||
returnOp = opcode; |
||||
arrayType = atype; |
||||
dataSize = size; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>true</code> if this object represents a primitive |
||||
* Java type: boolean, byte, char, short, int, long, float, double, |
||||
* or void. |
||||
*/ |
||||
public boolean isPrimitive() { return true; } |
||||
|
||||
/** |
||||
* Returns the modifiers for this type. |
||||
* For decoding, use <code>javassist.Modifier</code>. |
||||
* |
||||
* @see Modifier |
||||
*/ |
||||
public int getModifiers() { |
||||
return Modifier.PUBLIC | Modifier.FINAL; |
||||
} |
||||
|
||||
/** |
||||
* Returns the descriptor representing this type. |
||||
* For example, if the type is int, then the descriptor is I. |
||||
*/ |
||||
public char getDescriptor() { return descriptor; } |
||||
|
||||
/** |
||||
* Returns the name of the wrapper class. |
||||
* For example, if the type is int, then the wrapper class is |
||||
* <code>java.lang.Integer</code>. |
||||
*/ |
||||
public String getWrapperName() { return wrapperName; } |
||||
|
||||
/** |
||||
* Returns the name of the method for retrieving the value |
||||
* from the wrapper object. |
||||
* For example, if the type is int, then the method name is |
||||
* <code>intValue</code>. |
||||
*/ |
||||
public String getGetMethodName() { return getMethodName; } |
||||
|
||||
/** |
||||
* Returns the descriptor of the method for retrieving the value |
||||
* from the wrapper object. |
||||
* For example, if the type is int, then the method descriptor is |
||||
* <code>()I</code>. |
||||
*/ |
||||
public String getGetMethodDescriptor() { return mDescriptor; } |
||||
|
||||
/** |
||||
* Returns the opcode for returning a value of the type. |
||||
* For example, if the type is int, then the returned opcode is |
||||
* <code>javassit.bytecode.Opcode.IRETURN</code>. |
||||
*/ |
||||
public int getReturnOp() { return returnOp; } |
||||
|
||||
/** |
||||
* Returns the array-type code representing the type. |
||||
* It is used for the newarray instruction. |
||||
* For example, if the type is int, then this method returns |
||||
* <code>javassit.bytecode.Opcode.T_INT</code>. |
||||
*/ |
||||
public int getArrayType() { return arrayType; } |
||||
|
||||
/** |
||||
* Returns the data size of the primitive type. |
||||
* If the type is long or double, this method returns 2. |
||||
* Otherwise, it returns 1. |
||||
*/ |
||||
public int getDataSize() { return dataSize; } |
||||
} |
@ -1,433 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import java.io.*; |
||||
import java.util.Hashtable; |
||||
import java.util.Vector; |
||||
import java.security.ProtectionDomain; |
||||
|
||||
/** |
||||
* The class loader for Javassist. |
||||
* |
||||
* <p>This is a sample class loader using <code>ClassPool</code>. |
||||
* Unlike a regular class loader, this class loader obtains bytecode |
||||
* from a <code>ClassPool</code>. |
||||
* |
||||
* <p>Note that Javassist can be used without this class loader; programmers |
||||
* can define their own versions of class loader. They can run |
||||
* a program even without any user-defined class loader if that program |
||||
* is statically translated with Javassist. |
||||
* This class loader is just provided as a utility class. |
||||
* |
||||
* <p>Suppose that an instance of <code>MyTranslator</code> implementing |
||||
* the interface <code>Translator</code> is responsible for modifying |
||||
* class files. |
||||
* The startup program of an application using <code>MyTranslator</code> |
||||
* should be something like this: |
||||
* |
||||
* <ul><pre> |
||||
* import javassist.*; |
||||
* |
||||
* public class Main { |
||||
* public static void main(String[] args) throws Throwable { |
||||
* MyTranslator myTrans = new MyTranslator(); |
||||
* ClassPool cp = ClassPool.getDefault(); |
||||
* Loader cl = new Loader(cp); |
||||
* cl.addTranslator(cp, myTrans); |
||||
* cl.run("MyApp", args); |
||||
* } |
||||
* } |
||||
* </pre></ul> |
||||
* |
||||
* <p>Class <code>MyApp</code> is the main program of the application. |
||||
* |
||||
* <p>This program should be executed as follows: |
||||
* |
||||
* <ul><pre> |
||||
* % java Main <i>arg1</i> <i>arg2</i>... |
||||
* </pre></ul> |
||||
* |
||||
* <p>It modifies the class <code>MyApp</code> with a <code>MyTranslator</code> |
||||
* object before the JVM loads it. |
||||
* Then it calls <code>main()</code> in <code>MyApp</code> with arguments |
||||
* <i>arg1</i>, <i>arg2</i>, ... |
||||
* |
||||
* <p>This program execution is equivalent to: |
||||
* |
||||
* <ul><pre> |
||||
* % java MyApp <i>arg1</i> <i>arg2</i>... |
||||
* </pre></ul> |
||||
* |
||||
* <p>except that classes are translated by <code>MyTranslator</code> |
||||
* at load time. |
||||
* |
||||
* <p>If only a particular class must be modified when it is loaded, |
||||
* the startup program can be simpler; <code>MyTranslator</code> is |
||||
* unnecessary. For example, if only a class <code>test.Rectangle</code> |
||||
* is modified, the <code>main()</code> method above will be the following: |
||||
* |
||||
* <ul><pre> |
||||
* ClassPool cp = ClassPool.getDefault(); |
||||
* Loader cl = new Loader(cp); |
||||
* CtClass ct = cp.get("test.Rectangle"); |
||||
* ct.setSuperclass(cp.get("test.Point")); |
||||
* cl.run("MyApp", args);</pre></ul> |
||||
* |
||||
* <p>This program changes the super class of the <code>test.Rectangle</code> |
||||
* class. |
||||
* |
||||
* <p><b>Note 1:</b> |
||||
* |
||||
* <p>This class loader does not allow the users to intercept the loading |
||||
* of <code>java.*</code> and <code>javax.*</code> classes (and |
||||
* <code>sun.*</code>, <code>org.xml.*</code>, ...) unless |
||||
* <code>Loader.doDelegation</code> is <code>false</code>. This is because |
||||
* the JVM prohibits a user class loader from loading a system class. |
||||
* Also see Note 2. |
||||
* If this behavior is not appropriate, a subclass of <code>Loader</code> |
||||
* must be defined and <code>loadClassByDelegation()</code> must be overridden. |
||||
* |
||||
* <p><b>Note 2:</b> |
||||
* |
||||
* <p>If classes are loaded with different class loaders, they belong to |
||||
* separate name spaces. If class <code>C</code> is loaded by a class
|
||||
* loader <code>CL</code>, all classes that the class <code>C</code> |
||||
* refers to are also loaded by <code>CL</code>. However, if <code>CL</code> |
||||
* delegates the loading of the class <code>C</code> to <code>CL'</code>, |
||||
* then those classes that the class <code>C</code> refers to |
||||
* are loaded by a parent class loader <code>CL'</code> |
||||
* instead of <code>CL</code>. |
||||
* |
||||
* <p>If an object of class <code>C</code> is assigned |
||||
* to a variable of class <code>C</code> belonging to a different name |
||||
* space, then a <code>ClassCastException</code> is thrown. |
||||
* |
||||
* <p>Because of the fact above, this loader delegates only the loading of |
||||
* <code>javassist.Loader</code> |
||||
* and classes included in package <code>java.*</code> and |
||||
* <code>javax.*</code> to the parent class
|
||||
* loader. Other classes are directly loaded by this loader. |
||||
* |
||||
* <p>For example, suppose that <code>java.lang.String</code> would be loaded |
||||
* by this loader while <code>java.io.File</code> is loaded by the parent |
||||
* class loader. If the constructor of <code>java.io.File</code> is called |
||||
* with an instance of <code>java.lang.String</code>, then it may throw |
||||
* an exception since it accepts an instance of only the |
||||
* <code>java.lang.String</code> loaded by the parent class loader. |
||||
* |
||||
* @see com.fr.third.javassist.ClassPool |
||||
* @see Translator |
||||
*/ |
||||
public class Loader extends ClassLoader { |
||||
private Hashtable notDefinedHere; // must be atomic.
|
||||
private Vector notDefinedPackages; // must be atomic.
|
||||
private com.fr.third.javassist.ClassPool source; |
||||
private Translator translator; |
||||
private ProtectionDomain domain; |
||||
|
||||
/** |
||||
* Specifies the algorithm of class loading. |
||||
* |
||||
* <p>This class loader uses the parent class loader for |
||||
* <code>java.*</code> and <code>javax.*</code> classes. |
||||
* If this variable <code>doDelegation</code> |
||||
* is <code>false</code>, this class loader does not delegate those |
||||
* classes to the parent class loader. |
||||
* |
||||
* <p>The default value is <code>true</code>. |
||||
*/ |
||||
public boolean doDelegation = true; |
||||
|
||||
/** |
||||
* Creates a new class loader. |
||||
*/ |
||||
public Loader() { |
||||
this(null); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new class loader. |
||||
* |
||||
* @param cp the source of class files. |
||||
*/ |
||||
public Loader(com.fr.third.javassist.ClassPool cp) { |
||||
init(cp); |
||||
} |
||||
|
||||
/** |
||||
* Creates a new class loader |
||||
* using the specified parent class loader for delegation. |
||||
* |
||||
* @param parent the parent class loader. |
||||
* @param cp the source of class files. |
||||
*/ |
||||
public Loader(ClassLoader parent, com.fr.third.javassist.ClassPool cp) { |
||||
super(parent); |
||||
init(cp); |
||||
} |
||||
|
||||
private void init(com.fr.third.javassist.ClassPool cp) { |
||||
notDefinedHere = new Hashtable(); |
||||
notDefinedPackages = new Vector(); |
||||
source = cp; |
||||
translator = null; |
||||
domain = null; |
||||
delegateLoadingOf("javassist.Loader"); |
||||
} |
||||
|
||||
/** |
||||
* Records a class so that the loading of that class is delegated |
||||
* to the parent class loader. |
||||
* |
||||
* <p>If the given class name ends with <code>.</code> (dot), then |
||||
* that name is interpreted as a package name. All the classes |
||||
* in that package and the sub packages are delegated. |
||||
*/ |
||||
public void delegateLoadingOf(String classname) { |
||||
if (classname.endsWith(".")) |
||||
notDefinedPackages.addElement(classname); |
||||
else |
||||
notDefinedHere.put(classname, this); |
||||
} |
||||
|
||||
/** |
||||
* Sets the protection domain for the classes handled by this class
|
||||
* loader. Without registering an appropriate protection domain, |
||||
* the program loaded by this loader will not work with a security |
||||
* manager or a signed jar file. |
||||
*/ |
||||
public void setDomain(ProtectionDomain d) { |
||||
domain = d; |
||||
} |
||||
|
||||
/** |
||||
* Sets the soruce <code>ClassPool</code>. |
||||
*/ |
||||
public void setClassPool(com.fr.third.javassist.ClassPool cp) { |
||||
source = cp; |
||||
} |
||||
|
||||
/** |
||||
* Adds a translator, which is called whenever a class is loaded. |
||||
* |
||||
* @param cp the <code>ClassPool</code> object for obtaining |
||||
* a class file. |
||||
* @param t a translator. |
||||
* @throws NotFoundException if <code>t.start()</code> throws an exception. |
||||
* @throws com.fr.third.javassist.CannotCompileException if <code>t.start()</code> throws an exception. |
||||
*/ |
||||
public void addTranslator(ClassPool cp, Translator t) |
||||
throws NotFoundException, CannotCompileException { |
||||
source = cp; |
||||
translator = t; |
||||
t.start(cp); |
||||
} |
||||
|
||||
/** |
||||
* Loads a class with an instance of <code>Loader</code> |
||||
* and calls <code>main()</code> of that class. |
||||
* |
||||
* <p>This method calls <code>run()</code>. |
||||
* |
||||
* @param args command line parameters. |
||||
* <ul> |
||||
* <code>args[0]</code> is the class name to be loaded. |
||||
* <br><code>args[1..n]</code> are parameters passed |
||||
* to the target <code>main()</code>. |
||||
* </ul> |
||||
* |
||||
* @see Loader#run(String[]) |
||||
*/ |
||||
public static void main(String[] args) throws Throwable { |
||||
Loader cl = new Loader(); |
||||
cl.run(args); |
||||
} |
||||
|
||||
/** |
||||
* Loads a class and calls <code>main()</code> in that class. |
||||
* |
||||
* @param args command line parameters. |
||||
* <ul> |
||||
* <code>args[0]</code> is the class name to be loaded. |
||||
* <br><code>args[1..n]</code> are parameters passed |
||||
* to the target <code>main()</code>. |
||||
* </ul> |
||||
*/ |
||||
public void run(String[] args) throws Throwable { |
||||
int n = args.length - 1; |
||||
if (n >= 0) { |
||||
String[] args2 = new String[n]; |
||||
for (int i = 0; i < n; ++i) |
||||
args2[i] = args[i + 1]; |
||||
|
||||
run(args[0], args2); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Loads a class and calls <code>main()</code> in that class. |
||||
* |
||||
* @param classname the loaded class. |
||||
* @param args parameters passed to <code>main()</code>. |
||||
*/ |
||||
public void run(String classname, String[] args) throws Throwable { |
||||
Class c = loadClass(classname); |
||||
try { |
||||
c.getDeclaredMethod("main", new Class[] { String[].class }).invoke( |
||||
null, |
||||
new Object[] { args }); |
||||
} |
||||
catch (java.lang.reflect.InvocationTargetException e) { |
||||
throw e.getTargetException(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Requests the class loader to load a class. |
||||
*/ |
||||
protected Class loadClass(String name, boolean resolve) |
||||
throws ClassFormatError, ClassNotFoundException { |
||||
name = name.intern(); |
||||
synchronized (name) { |
||||
Class c = findLoadedClass(name); |
||||
if (c == null) |
||||
c = loadClassByDelegation(name); |
||||
|
||||
if (c == null) |
||||
c = findClass(name); |
||||
|
||||
if (c == null) |
||||
c = delegateToParent(name); |
||||
|
||||
if (resolve) |
||||
resolveClass(c); |
||||
|
||||
return c; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Finds the specified class using <code>ClassPath</code>. |
||||
* If the source throws an exception, this returns null. |
||||
* |
||||
* <p>This method can be overridden by a subclass of |
||||
* <code>Loader</code>. Note that the overridden method must not throw |
||||
* an exception when it just fails to find a class file. |
||||
* |
||||
* @return null if the specified class could not be found. |
||||
* @throws ClassNotFoundException if an exception is thrown while |
||||
* obtaining a class file. |
||||
*/ |
||||
protected Class findClass(String name) throws ClassNotFoundException { |
||||
byte[] classfile; |
||||
try { |
||||
if (source != null) { |
||||
if (translator != null) |
||||
translator.onLoad(source, name); |
||||
|
||||
try { |
||||
classfile = source.get(name).toBytecode(); |
||||
} |
||||
catch (NotFoundException e) { |
||||
return null; |
||||
} |
||||
} |
||||
else { |
||||
String jarname = "/" + name.replace('.', '/') + ".class"; |
||||
InputStream in = this.getClass().getResourceAsStream(jarname); |
||||
if (in == null) |
||||
return null; |
||||
|
||||
classfile = com.fr.third.javassist.ClassPoolTail.readStream(in); |
||||
} |
||||
} |
||||
catch (Exception e) { |
||||
throw new ClassNotFoundException( |
||||
"caught an exception while obtaining a class file for " |
||||
+ name, e); |
||||
} |
||||
|
||||
int i = name.lastIndexOf('.'); |
||||
if (i != -1) { |
||||
String pname = name.substring(0, i); |
||||
if (getPackage(pname) == null) |
||||
try { |
||||
definePackage( |
||||
pname, null, null, null, null, null, null, null); |
||||
} |
||||
catch (IllegalArgumentException e) { |
||||
// ignore. maybe the package object for the same
|
||||
// name has been created just right away.
|
||||
} |
||||
} |
||||
|
||||
if (domain == null) |
||||
return defineClass(name, classfile, 0, classfile.length); |
||||
else |
||||
return defineClass(name, classfile, 0, classfile.length, domain); |
||||
} |
||||
|
||||
protected Class loadClassByDelegation(String name) |
||||
throws ClassNotFoundException |
||||
{ |
||||
/* The swing components must be loaded by a system |
||||
* class loader. |
||||
* javax.swing.UIManager loads a (concrete) subclass |
||||
* of LookAndFeel by a system class loader and cast |
||||
* an instance of the class to LookAndFeel for |
||||
* (maybe) a security reason. To avoid failure of |
||||
* type conversion, LookAndFeel must not be loaded |
||||
* by this class loader. |
||||
*/ |
||||
|
||||
Class c = null; |
||||
if (doDelegation) |
||||
if (name.startsWith("java.") |
||||
|| name.startsWith("javax.") |
||||
|| name.startsWith("sun.") |
||||
|| name.startsWith("com.sun.") |
||||
|| name.startsWith("org.w3c.") |
||||
|| name.startsWith("org.xml.") |
||||
|| notDelegated(name)) |
||||
c = delegateToParent(name); |
||||
|
||||
return c; |
||||
} |
||||
|
||||
private boolean notDelegated(String name) { |
||||
if (notDefinedHere.get(name) != null) |
||||
return true; |
||||
|
||||
int n = notDefinedPackages.size(); |
||||
for (int i = 0; i < n; ++i) |
||||
if (name.startsWith((String)notDefinedPackages.elementAt(i))) |
||||
return true; |
||||
|
||||
return false; |
||||
} |
||||
|
||||
protected Class delegateToParent(String classname) |
||||
throws ClassNotFoundException |
||||
{ |
||||
ClassLoader cl = getParent(); |
||||
if (cl != null) |
||||
return cl.loadClass(classname); |
||||
else |
||||
return findSystemClass(classname); |
||||
} |
||||
} |
@ -1,96 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import java.io.InputStream; |
||||
import java.net.URL; |
||||
import java.lang.ref.WeakReference; |
||||
|
||||
/** |
||||
* A class search-path representing a class loader. |
||||
* |
||||
* <p>It is used for obtaining a class file from the given |
||||
* class loader by <code>getResourceAsStream()</code>. |
||||
* The <code>LoaderClassPath</code> refers to the class loader through |
||||
* <code>WeakReference</code>. If the class loader is garbage collected, |
||||
* the other search pathes are examined. |
||||
* |
||||
* <p>The given class loader must have both <code>getResourceAsStream()</code> |
||||
* and <code>getResource()</code>. |
||||
* |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author Shigeru Chiba |
||||
* |
||||
* @see com.fr.third.javassist.ClassPool#insertClassPath(com.fr.third.javassist.ClassPath) |
||||
* @see ClassPool#appendClassPath(com.fr.third.javassist.ClassPath) |
||||
* @see ClassClassPath |
||||
*/ |
||||
public class LoaderClassPath implements ClassPath { |
||||
private WeakReference clref; |
||||
|
||||
/** |
||||
* Creates a search path representing a class loader. |
||||
*/ |
||||
public LoaderClassPath(ClassLoader cl) { |
||||
clref = new WeakReference(cl); |
||||
} |
||||
|
||||
public String toString() { |
||||
Object cl = null; |
||||
if (clref != null) |
||||
cl = clref.get(); |
||||
|
||||
return cl == null ? "<null>" : cl.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Obtains a class file from the class loader. |
||||
* This method calls <code>getResourceAsStream(String)</code> |
||||
* on the class loader. |
||||
*/ |
||||
public InputStream openClassfile(String classname) { |
||||
String cname = classname.replace('.', '/') + ".class"; |
||||
ClassLoader cl = (ClassLoader)clref.get(); |
||||
if (cl == null) |
||||
return null; // not found
|
||||
else |
||||
return cl.getResourceAsStream(cname); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the URL of the specified class file. |
||||
* This method calls <code>getResource(String)</code> |
||||
* on the class loader. |
||||
* |
||||
* @return null if the class file could not be found. |
||||
*/ |
||||
public URL find(String classname) { |
||||
String cname = classname.replace('.', '/') + ".class"; |
||||
ClassLoader cl = (ClassLoader)clref.get(); |
||||
if (cl == null) |
||||
return null; // not found
|
||||
else |
||||
return cl.getResource(cname); |
||||
} |
||||
|
||||
/** |
||||
* Closes this class path. |
||||
*/ |
||||
public void close() { |
||||
clref = null; |
||||
} |
||||
} |
@ -1,219 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import com.fr.third.javassist.bytecode.AccessFlag; |
||||
|
||||
/** |
||||
* The Modifier class provides static methods and constants to decode |
||||
* class and member access modifiers. The constant values are equivalent |
||||
* to the corresponding values in <code>javassist.bytecode.AccessFlag</code>. |
||||
* |
||||
* <p>All the methods/constants in this class are compatible with |
||||
* ones in <code>java.lang.reflect.Modifier</code>. |
||||
* |
||||
* @see CtClass#getModifiers() |
||||
*/ |
||||
public class Modifier { |
||||
public static final int PUBLIC = AccessFlag.PUBLIC; |
||||
public static final int PRIVATE = AccessFlag.PRIVATE; |
||||
public static final int PROTECTED = AccessFlag.PROTECTED; |
||||
public static final int STATIC = AccessFlag.STATIC; |
||||
public static final int FINAL = AccessFlag.FINAL; |
||||
public static final int SYNCHRONIZED = AccessFlag.SYNCHRONIZED; |
||||
public static final int VOLATILE = AccessFlag.VOLATILE; |
||||
public static final int VARARGS = AccessFlag.VARARGS; |
||||
public static final int TRANSIENT = AccessFlag.TRANSIENT; |
||||
public static final int NATIVE = AccessFlag.NATIVE; |
||||
public static final int INTERFACE = AccessFlag.INTERFACE; |
||||
public static final int ABSTRACT = AccessFlag.ABSTRACT; |
||||
public static final int STRICT = AccessFlag.STRICT; |
||||
public static final int ANNOTATION = AccessFlag.ANNOTATION; |
||||
public static final int ENUM = AccessFlag.ENUM; |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>public</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isPublic(int mod) { |
||||
return (mod & PUBLIC) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>private</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isPrivate(int mod) { |
||||
return (mod & PRIVATE) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>protected</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isProtected(int mod) { |
||||
return (mod & PROTECTED) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers do not include either |
||||
* <tt>public</tt>, <tt>protected</tt>, or <tt>private</tt>. |
||||
*/ |
||||
public static boolean isPackage(int mod) { |
||||
return (mod & (PUBLIC | PRIVATE | PROTECTED)) == 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>static</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isStatic(int mod) { |
||||
return (mod & STATIC) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>final</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isFinal(int mod) { |
||||
return (mod & FINAL) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>synchronized</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isSynchronized(int mod) { |
||||
return (mod & SYNCHRONIZED) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>volatile</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isVolatile(int mod) { |
||||
return (mod & VOLATILE) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>transient</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isTransient(int mod) { |
||||
return (mod & TRANSIENT) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>native</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isNative(int mod) { |
||||
return (mod & NATIVE) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>interface</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isInterface(int mod) { |
||||
return (mod & INTERFACE) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>annotation</tt> |
||||
* modifier. |
||||
* |
||||
* @since 3.2 |
||||
*/ |
||||
public static boolean isAnnotation(int mod) { |
||||
return (mod & ANNOTATION) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>enum</tt> |
||||
* modifier. |
||||
* |
||||
* @since 3.2 |
||||
*/ |
||||
public static boolean isEnum(int mod) { |
||||
return (mod & ENUM) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>abstract</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isAbstract(int mod) { |
||||
return (mod & ABSTRACT) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the modifiers include the <tt>strictfp</tt> |
||||
* modifier. |
||||
*/ |
||||
public static boolean isStrict(int mod) { |
||||
return (mod & STRICT) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Truns the public bit on. The protected and private bits are |
||||
* cleared. |
||||
*/ |
||||
public static int setPublic(int mod) { |
||||
return (mod & ~(PRIVATE | PROTECTED)) | PUBLIC; |
||||
} |
||||
|
||||
/** |
||||
* Truns the protected bit on. The protected and public bits are |
||||
* cleared. |
||||
*/ |
||||
public static int setProtected(int mod) { |
||||
return (mod & ~(PRIVATE | PUBLIC)) | PROTECTED; |
||||
} |
||||
|
||||
/** |
||||
* Truns the private bit on. The protected and private bits are |
||||
* cleared. |
||||
*/ |
||||
public static int setPrivate(int mod) { |
||||
return (mod & ~(PROTECTED | PUBLIC)) | PRIVATE; |
||||
} |
||||
|
||||
/** |
||||
* Clears the public, protected, and private bits. |
||||
*/ |
||||
public static int setPackage(int mod) { |
||||
return (mod & ~(PROTECTED | PUBLIC | PRIVATE)); |
||||
} |
||||
|
||||
/** |
||||
* Clears a specified bit in <code>mod</code>. |
||||
*/ |
||||
public static int clear(int mod, int clearBit) { |
||||
return mod & ~clearBit; |
||||
} |
||||
|
||||
/** |
||||
* Return a string describing the access modifier flags in |
||||
* the specified modifier. |
||||
* |
||||
* @param mod modifier flags. |
||||
*/ |
||||
public static String toString(int mod) { |
||||
return java.lang.reflect.Modifier.toString(mod); |
||||
} |
||||
} |
@ -1,30 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
/** |
||||
* Signals that something could not be found. |
||||
*/ |
||||
public class NotFoundException extends Exception { |
||||
public NotFoundException(String msg) { |
||||
super(msg); |
||||
} |
||||
|
||||
public NotFoundException(String msg, Exception e) { |
||||
super(msg + " because of " + e.toString()); |
||||
} |
||||
} |
@ -1,212 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import java.io.*; |
||||
import java.lang.reflect.Modifier; |
||||
|
||||
import com.fr.third.javassist.bytecode.ClassFile; |
||||
|
||||
import java.util.*; |
||||
import java.security.*; |
||||
|
||||
/** |
||||
* Utility for calculating serialVersionUIDs for Serializable classes. |
||||
* |
||||
* @author Bob Lee (crazybob@crazybob.org) |
||||
* @author modified by Shigeru Chiba |
||||
*/ |
||||
public class SerialVersionUID { |
||||
|
||||
/** |
||||
* Adds serialVersionUID if one does not already exist. Call this before |
||||
* modifying a class to maintain serialization compatability. |
||||
*/ |
||||
public static void setSerialVersionUID(com.fr.third.javassist.CtClass clazz) |
||||
throws com.fr.third.javassist.CannotCompileException, com.fr.third.javassist.NotFoundException |
||||
{ |
||||
// check for pre-existing field.
|
||||
try { |
||||
clazz.getDeclaredField("serialVersionUID"); |
||||
return; |
||||
} |
||||
catch (com.fr.third.javassist.NotFoundException e) {} |
||||
|
||||
// check if the class is serializable.
|
||||
if (!isSerializable(clazz)) |
||||
return; |
||||
|
||||
// add field with default value.
|
||||
com.fr.third.javassist.CtField field = new com.fr.third.javassist.CtField(com.fr.third.javassist.CtClass.longType, "serialVersionUID", |
||||
clazz); |
||||
field.setModifiers(Modifier.PRIVATE | Modifier.STATIC | |
||||
Modifier.FINAL); |
||||
clazz.addField(field, calculateDefault(clazz) + "L"); |
||||
} |
||||
|
||||
/** |
||||
* Does the class implement Serializable? |
||||
*/ |
||||
private static boolean isSerializable(com.fr.third.javassist.CtClass clazz) |
||||
throws NotFoundException |
||||
{ |
||||
ClassPool pool = clazz.getClassPool(); |
||||
return clazz.subtypeOf(pool.get("java.io.Serializable")); |
||||
} |
||||
|
||||
/** |
||||
* Calculate default value. See Java Serialization Specification, Stream |
||||
* Unique Identifiers. |
||||
*/ |
||||
static long calculateDefault(com.fr.third.javassist.CtClass clazz) |
||||
throws com.fr.third.javassist.CannotCompileException |
||||
{ |
||||
try { |
||||
ByteArrayOutputStream bout = new ByteArrayOutputStream(); |
||||
DataOutputStream out = new DataOutputStream(bout); |
||||
ClassFile classFile = clazz.getClassFile(); |
||||
|
||||
// class name.
|
||||
String javaName = javaName(clazz); |
||||
out.writeUTF(javaName); |
||||
|
||||
com.fr.third.javassist.CtMethod[] methods = clazz.getDeclaredMethods(); |
||||
|
||||
// class modifiers.
|
||||
int classMods = clazz.getModifiers(); |
||||
if ((classMods & Modifier.INTERFACE) != 0) |
||||
if (methods.length > 0) |
||||
classMods = classMods | Modifier.ABSTRACT; |
||||
else |
||||
classMods = classMods & ~Modifier.ABSTRACT; |
||||
|
||||
out.writeInt(classMods); |
||||
|
||||
// interfaces.
|
||||
String[] interfaces = classFile.getInterfaces(); |
||||
for (int i = 0; i < interfaces.length; i++) |
||||
interfaces[i] = javaName(interfaces[i]); |
||||
|
||||
Arrays.sort(interfaces); |
||||
for (int i = 0; i < interfaces.length; i++) |
||||
out.writeUTF(interfaces[i]); |
||||
|
||||
// fields.
|
||||
com.fr.third.javassist.CtField[] fields = clazz.getDeclaredFields(); |
||||
Arrays.sort(fields, new Comparator() { |
||||
public int compare(Object o1, Object o2) { |
||||
com.fr.third.javassist.CtField field1 = (com.fr.third.javassist.CtField)o1; |
||||
com.fr.third.javassist.CtField field2 = (com.fr.third.javassist.CtField)o2; |
||||
return field1.getName().compareTo(field2.getName()); |
||||
} |
||||
}); |
||||
|
||||
for (int i = 0; i < fields.length; i++) { |
||||
com.fr.third.javassist.CtField field = (CtField) fields[i]; |
||||
int mods = field.getModifiers(); |
||||
if (((mods & Modifier.PRIVATE) == 0) || |
||||
((mods & (Modifier.STATIC | Modifier.TRANSIENT)) == 0)) { |
||||
out.writeUTF(field.getName()); |
||||
out.writeInt(mods); |
||||
out.writeUTF(field.getFieldInfo2().getDescriptor()); |
||||
} |
||||
} |
||||
|
||||
// static initializer.
|
||||
if (classFile.getStaticInitializer() != null) { |
||||
out.writeUTF("<clinit>"); |
||||
out.writeInt(Modifier.STATIC); |
||||
out.writeUTF("()V"); |
||||
} |
||||
|
||||
// constructors.
|
||||
com.fr.third.javassist.CtConstructor[] constructors = clazz.getDeclaredConstructors(); |
||||
Arrays.sort(constructors, new Comparator() { |
||||
public int compare(Object o1, Object o2) { |
||||
com.fr.third.javassist.CtConstructor c1 = (com.fr.third.javassist.CtConstructor)o1; |
||||
com.fr.third.javassist.CtConstructor c2 = (com.fr.third.javassist.CtConstructor)o2; |
||||
return c1.getMethodInfo2().getDescriptor().compareTo( |
||||
c2.getMethodInfo2().getDescriptor()); |
||||
} |
||||
}); |
||||
|
||||
for (int i = 0; i < constructors.length; i++) { |
||||
CtConstructor constructor = constructors[i]; |
||||
int mods = constructor.getModifiers(); |
||||
if ((mods & Modifier.PRIVATE) == 0) { |
||||
out.writeUTF("<init>"); |
||||
out.writeInt(mods); |
||||
out.writeUTF(constructor.getMethodInfo2() |
||||
.getDescriptor().replace('/', '.')); |
||||
} |
||||
} |
||||
|
||||
// methods.
|
||||
Arrays.sort(methods, new Comparator() { |
||||
public int compare(Object o1, Object o2) { |
||||
com.fr.third.javassist.CtMethod m1 = (com.fr.third.javassist.CtMethod)o1; |
||||
com.fr.third.javassist.CtMethod m2 = (com.fr.third.javassist.CtMethod)o2; |
||||
int value = m1.getName().compareTo(m2.getName()); |
||||
if (value == 0) |
||||
value = m1.getMethodInfo2().getDescriptor() |
||||
.compareTo(m2.getMethodInfo2().getDescriptor()); |
||||
|
||||
return value; |
||||
} |
||||
}); |
||||
|
||||
for (int i = 0; i < methods.length; i++) { |
||||
CtMethod method = methods[i]; |
||||
int mods = method.getModifiers() |
||||
& (Modifier.PUBLIC | Modifier.PRIVATE |
||||
| Modifier.PROTECTED | Modifier.STATIC |
||||
| Modifier.FINAL | Modifier.SYNCHRONIZED |
||||
| Modifier.NATIVE | Modifier.ABSTRACT | Modifier.STRICT); |
||||
if ((mods & Modifier.PRIVATE) == 0) { |
||||
out.writeUTF(method.getName()); |
||||
out.writeInt(mods); |
||||
out.writeUTF(method.getMethodInfo2() |
||||
.getDescriptor().replace('/', '.')); |
||||
} |
||||
} |
||||
|
||||
// calculate hash.
|
||||
out.flush(); |
||||
MessageDigest digest = MessageDigest.getInstance("SHA"); |
||||
byte[] digested = digest.digest(bout.toByteArray()); |
||||
long hash = 0; |
||||
for (int i = Math.min(digested.length, 8) - 1; i >= 0; i--) |
||||
hash = (hash << 8) | (digested[i] & 0xFF); |
||||
|
||||
return hash; |
||||
} |
||||
catch (IOException e) { |
||||
throw new com.fr.third.javassist.CannotCompileException(e); |
||||
} |
||||
catch (NoSuchAlgorithmException e) { |
||||
throw new CannotCompileException(e); |
||||
} |
||||
} |
||||
|
||||
private static String javaName(CtClass clazz) { |
||||
return com.fr.third.javassist.bytecode.Descriptor.toJavaName(com.fr.third.javassist.bytecode.Descriptor.toJvmName(clazz)); |
||||
} |
||||
|
||||
private static String javaName(String name) { |
||||
return com.fr.third.javassist.bytecode.Descriptor.toJavaName(com.fr.third.javassist.bytecode.Descriptor.toJvmName(name)); |
||||
} |
||||
} |
@ -1,71 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
/** |
||||
* An observer of <code>Loader</code>. |
||||
* The users can define a class implementing this |
||||
* interface and attach an instance of that class to a |
||||
* <code>Loader</code> object so that it can translate a class file |
||||
* when the class file is loaded into the JVM. |
||||
* |
||||
* @see com.fr.third.javassist.Loader#addTranslator(com.fr.third.javassist.ClassPool, Translator) |
||||
*/ |
||||
public interface Translator { |
||||
/** |
||||
* Is invoked by a <code>Loader</code> for initialization |
||||
* when the object is attached to the <code>Loader</code> object. |
||||
* This method can be used for getting (for caching) some |
||||
* <code>CtClass</code> objects that will be accessed |
||||
* in <code>onLoad()</code> in <code>Translator</code>. |
||||
* |
||||
* @param pool the <code>ClassPool</code> that this translator |
||||
* should use. |
||||
* @see com.fr.third.javassist.Loader |
||||
* @throws com.fr.third.javassist.NotFoundException if a <code>CtClass</code> cannot be found. |
||||
* @throws com.fr.third.javassist.CannotCompileException if the initialization by this method |
||||
* fails. |
||||
*/ |
||||
void start(com.fr.third.javassist.ClassPool pool) |
||||
throws com.fr.third.javassist.NotFoundException, com.fr.third.javassist.CannotCompileException; |
||||
|
||||
/** |
||||
* Is invoked by a <code>Loader</code> for notifying that |
||||
* a class is loaded. The <code>Loader</code> calls |
||||
* |
||||
* <ul><pre> |
||||
* pool.get(classname).toBytecode()</pre></ul> |
||||
* |
||||
* to read the class file after <code>onLoad()</code> returns. |
||||
* |
||||
* <p><code>classname</code> may be the name of a class
|
||||
* that has not been created yet. |
||||
* If so, <code>onLoad()</code> must create that class so that |
||||
* the <code>Loader</code> can read it after <code>onLoad()</code> |
||||
* returns. |
||||
* |
||||
* @param pool the <code>ClassPool</code> that this translator |
||||
* should use. |
||||
* @param classname the name of the class being loaded. |
||||
* @see Loader |
||||
* @throws com.fr.third.javassist.NotFoundException if a <code>CtClass</code> cannot be found. |
||||
* @throws com.fr.third.javassist.CannotCompileException if the code transformation |
||||
* by this method fails. |
||||
*/ |
||||
void onLoad(ClassPool pool, String classname) |
||||
throws NotFoundException, CannotCompileException; |
||||
} |
@ -1,179 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist; |
||||
|
||||
import java.io.*; |
||||
import java.net.*; |
||||
|
||||
/** |
||||
* A class search-path specified with URL (http). |
||||
* |
||||
* @see com.fr.third.javassist.ClassPath |
||||
* @see com.fr.third.javassist.ClassPool#insertClassPath(com.fr.third.javassist.ClassPath) |
||||
* @see ClassPool#appendClassPath(com.fr.third.javassist.ClassPath) |
||||
*/ |
||||
public class URLClassPath implements ClassPath { |
||||
protected String hostname; |
||||
protected int port; |
||||
protected String directory; |
||||
protected String packageName; |
||||
|
||||
/** |
||||
* Creates a search path specified with URL (http). |
||||
* |
||||
* <p>This search path is used only if a requested |
||||
* class name starts with the name specified by <code>packageName</code>. |
||||
* If <code>packageName</code> is "org.javassist." and a requested class is |
||||
* "org.javassist.test.Main", then the given URL is used for loading that class. |
||||
* The <code>URLClassPath</code> obtains a class file from: |
||||
* |
||||
* <ul><pre>http://www.javassist.org:80/java/classes/org/javassist/test/Main.class
|
||||
* </pre></ul> |
||||
* |
||||
* <p>Here, we assume that <code>host</code> is "www.javassist.org", |
||||
* <code>port</code> is 80, and <code>directory</code> is "/java/classes/". |
||||
* |
||||
* <p>If <code>packageName</code> is <code>null</code>, the URL is used |
||||
* for loading any class. |
||||
* |
||||
* @param host host name |
||||
* @param port port number |
||||
* @param directory directory name ending with "/". |
||||
* It can be "/" (root directory). |
||||
* It must start with "/". |
||||
* @param packageName package name. It must end with "." (dot). |
||||
*/ |
||||
public URLClassPath(String host, int port, |
||||
String directory, String packageName) { |
||||
hostname = host; |
||||
this.port = port; |
||||
this.directory = directory; |
||||
this.packageName = packageName; |
||||
} |
||||
|
||||
public String toString() { |
||||
return hostname + ":" + port + directory; |
||||
} |
||||
|
||||
/** |
||||
* Opens a class file with http. |
||||
* |
||||
* @return null if the class file could not be found. |
||||
*/ |
||||
public InputStream openClassfile(String classname) { |
||||
try { |
||||
URLConnection con = openClassfile0(classname); |
||||
if (con != null) |
||||
return con.getInputStream(); |
||||
} |
||||
catch (IOException e) {} |
||||
return null; // not found
|
||||
} |
||||
|
||||
private URLConnection openClassfile0(String classname) throws IOException { |
||||
if (packageName == null || classname.startsWith(packageName)) { |
||||
String jarname |
||||
= directory + classname.replace('.', '/') + ".class"; |
||||
return fetchClass0(hostname, port, jarname); |
||||
} |
||||
else |
||||
return null; // not found
|
||||
} |
||||
|
||||
/** |
||||
* Returns the URL. |
||||
* |
||||
* @return null if the class file could not be obtained. |
||||
*/ |
||||
public URL find(String classname) { |
||||
try { |
||||
URLConnection con = openClassfile0(classname); |
||||
InputStream is = con.getInputStream(); |
||||
if (is != null) { |
||||
is.close(); |
||||
return con.getURL(); |
||||
} |
||||
} |
||||
catch (IOException e) {} |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Closes this class path. |
||||
*/ |
||||
public void close() {} |
||||
|
||||
/** |
||||
* Reads a class file on an http server. |
||||
* |
||||
* @param host host name |
||||
* @param port port number |
||||
* @param directory directory name ending with "/". |
||||
* It can be "/" (root directory). |
||||
* It must start with "/". |
||||
* @param classname fully-qualified class name |
||||
*/ |
||||
public static byte[] fetchClass(String host, int port, |
||||
String directory, String classname) |
||||
throws IOException |
||||
{ |
||||
byte[] b; |
||||
URLConnection con = fetchClass0(host, port, |
||||
directory + classname.replace('.', '/') + ".class"); |
||||
int size = con.getContentLength(); |
||||
InputStream s = con.getInputStream(); |
||||
try { |
||||
if (size <= 0) |
||||
b = com.fr.third.javassist.ClassPoolTail.readStream(s); |
||||
else { |
||||
b = new byte[size]; |
||||
int len = 0; |
||||
do { |
||||
int n = s.read(b, len, size - len); |
||||
if (n < 0) |
||||
throw new IOException("the stream was closed: " |
||||
+ classname); |
||||
|
||||
len += n; |
||||
} while (len < size); |
||||
} |
||||
} |
||||
finally { |
||||
s.close(); |
||||
} |
||||
|
||||
return b; |
||||
} |
||||
|
||||
private static URLConnection fetchClass0(String host, int port, |
||||
String filename) |
||||
throws IOException |
||||
{ |
||||
URL url; |
||||
try { |
||||
url = new URL("http", host, port, filename); |
||||
} |
||||
catch (MalformedURLException e) { |
||||
// should never reache here.
|
||||
throw new IOException("invalid URL?"); |
||||
} |
||||
|
||||
URLConnection con = url.openConnection(); |
||||
con.connect(); |
||||
return con; |
||||
} |
||||
} |
@ -1,133 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
/** |
||||
* A support class providing static methods and constants |
||||
* for access modifiers such as public, rivate, ... |
||||
*/ |
||||
public class AccessFlag { |
||||
public static final int PUBLIC = 0x0001; |
||||
public static final int PRIVATE = 0x0002; |
||||
public static final int PROTECTED = 0x0004; |
||||
public static final int STATIC = 0x0008; |
||||
public static final int FINAL = 0x0010; |
||||
public static final int SYNCHRONIZED = 0x0020; |
||||
public static final int VOLATILE = 0x0040; |
||||
public static final int BRIDGE = 0x0040; // for method_info
|
||||
public static final int TRANSIENT = 0x0080; |
||||
public static final int VARARGS = 0x0080; // for method_info
|
||||
public static final int NATIVE = 0x0100; |
||||
public static final int INTERFACE = 0x0200; |
||||
public static final int ABSTRACT = 0x0400; |
||||
public static final int STRICT = 0x0800; |
||||
public static final int SYNTHETIC = 0x1000; |
||||
public static final int ANNOTATION = 0x2000; |
||||
public static final int ENUM = 0x4000; |
||||
|
||||
public static final int SUPER = 0x0020; |
||||
|
||||
// Note: 0x0020 is assigned to both ACC_SUPER and ACC_SYNCHRONIZED
|
||||
// although java.lang.reflect.Modifier does not recognize ACC_SUPER.
|
||||
|
||||
/** |
||||
* Truns the public bit on. The protected and private bits are |
||||
* cleared. |
||||
*/ |
||||
public static int setPublic(int accflags) { |
||||
return (accflags & ~(PRIVATE | PROTECTED)) | PUBLIC; |
||||
} |
||||
|
||||
/** |
||||
* Truns the protected bit on. The protected and public bits are |
||||
* cleared. |
||||
*/ |
||||
public static int setProtected(int accflags) { |
||||
return (accflags & ~(PRIVATE | PUBLIC)) | PROTECTED; |
||||
} |
||||
|
||||
/** |
||||
* Truns the private bit on. The protected and private bits are |
||||
* cleared. |
||||
*/ |
||||
public static int setPrivate(int accflags) { |
||||
return (accflags & ~(PROTECTED | PUBLIC)) | PRIVATE; |
||||
} |
||||
|
||||
/** |
||||
* Clears the public, protected, and private bits. |
||||
*/ |
||||
public static int setPackage(int accflags) { |
||||
return (accflags & ~(PROTECTED | PUBLIC | PRIVATE)); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the access flags include the public bit. |
||||
*/ |
||||
public static boolean isPublic(int accflags) { |
||||
return (accflags & PUBLIC) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the access flags include the protected bit. |
||||
*/ |
||||
public static boolean isProtected(int accflags) { |
||||
return (accflags & PROTECTED) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the access flags include the private bit. |
||||
*/ |
||||
public static boolean isPrivate(int accflags) { |
||||
return (accflags & PRIVATE) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the access flags include neither public, protected, |
||||
* or private. |
||||
*/ |
||||
public static boolean isPackage(int accflags) { |
||||
return (accflags & (PROTECTED | PUBLIC | PRIVATE)) == 0; |
||||
} |
||||
|
||||
/** |
||||
* Clears a specified bit in <code>accflags</code>. |
||||
*/ |
||||
public static int clear(int accflags, int clearBit) { |
||||
return accflags & ~clearBit; |
||||
} |
||||
|
||||
/** |
||||
* Converts a javassist.Modifier into |
||||
* a javassist.bytecode.AccessFlag. |
||||
* |
||||
* @param modifier javassist.Modifier |
||||
*/ |
||||
public static int of(int modifier) { |
||||
return modifier; |
||||
} |
||||
|
||||
/** |
||||
* Converts a javassist.bytecode.AccessFlag |
||||
* into a javassist.Modifier. |
||||
* |
||||
* @param accflags javassist.bytecode.Accessflag |
||||
*/ |
||||
public static int toModifier(int accflags) { |
||||
return accflags; |
||||
} |
||||
} |
@ -1,161 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import com.fr.third.javassist.CtClass; |
||||
import com.fr.third.javassist.bytecode.annotation.Annotation; |
||||
import com.fr.third.javassist.bytecode.annotation.AnnotationsWriter; |
||||
import com.fr.third.javassist.bytecode.annotation.MemberValue; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* A class representing <code>AnnotationDefault_attribute</code>. |
||||
* |
||||
* <p>For example, if you declare the following annotation type: |
||||
* |
||||
* <ul><pre> |
||||
* @interface Author { |
||||
* String name() default "Shakespeare"; |
||||
* int age() default 99; |
||||
* } |
||||
* </pre></ul> |
||||
* |
||||
* <p>The defautl values of <code>name</code> and <code>age</code> |
||||
* are stored as annotation default attributes in <code>Author.class</code>. |
||||
* The following code snippet obtains the default value of <code>name</code>: |
||||
* |
||||
* <ul><pre> |
||||
* ClassPool pool = ... |
||||
* CtClass cc = pool.get("Author"); |
||||
* CtMethod cm = cc.getDeclaredMethod("age"); |
||||
* MethodInfo minfo = cm.getMethodInfo(); |
||||
* AnnotationDefaultAttribute ada |
||||
* = (AnnotationDefaultAttribute) |
||||
* minfo.getAttribute(AnnotationDefaultAttribute.tag); |
||||
* MemberValue value = ada.getDefaultValue()); // default value of age
|
||||
* </pre></ul> |
||||
* |
||||
* <p>If the following statement is executed after the code above, |
||||
* the default value of age is set to 80: |
||||
* |
||||
* <ul><pre> |
||||
* ada.setDefaultValue(new IntegerMemberValue(minfo.getConstPool(), 80)); |
||||
* </pre></ul> |
||||
* |
||||
* @see com.fr.third.javassist.bytecode.AnnotationsAttribute |
||||
* @see MemberValue |
||||
*/ |
||||
|
||||
public class AnnotationDefaultAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of the <code>AnnotationDefault</code> attribute. |
||||
*/ |
||||
public static final String tag = "AnnotationDefault"; |
||||
|
||||
/** |
||||
* Constructs an <code>AnnotationDefault_attribute</code>. |
||||
* |
||||
* @param cp constant pool |
||||
* @param info the contents of this attribute. It does not |
||||
* include <code>attribute_name_index</code> or |
||||
* <code>attribute_length</code>. |
||||
*/ |
||||
public AnnotationDefaultAttribute(com.fr.third.javassist.bytecode.ConstPool cp, byte[] info) { |
||||
super(cp, tag, info); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an empty <code>AnnotationDefault_attribute</code>. |
||||
* The default value can be set by <code>setDefaultValue()</code>. |
||||
* |
||||
* @param cp constant pool |
||||
* @see #setDefaultValue(MemberValue) |
||||
*/ |
||||
public AnnotationDefaultAttribute(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
this(cp, new byte[] { 0, 0 }); |
||||
} |
||||
|
||||
/** |
||||
* @param n the attribute name. |
||||
*/ |
||||
AnnotationDefaultAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Copies this attribute and returns a new copy. |
||||
*/ |
||||
public AttributeInfo copy(com.fr.third.javassist.bytecode.ConstPool newCp, Map classnames) { |
||||
com.fr.third.javassist.bytecode.AnnotationsAttribute.Copier copier |
||||
= new com.fr.third.javassist.bytecode.AnnotationsAttribute.Copier(info, constPool, newCp, classnames); |
||||
try { |
||||
copier.memberValue(0); |
||||
return new AnnotationDefaultAttribute(newCp, copier.close()); |
||||
} |
||||
catch (Exception e) { |
||||
throw new RuntimeException(e.toString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Obtains the default value represented by this attribute. |
||||
*/ |
||||
public MemberValue getDefaultValue() |
||||
{ |
||||
try { |
||||
return new AnnotationsAttribute.Parser(info, constPool) |
||||
.parseMemberValue(); |
||||
} |
||||
catch (Exception e) { |
||||
throw new RuntimeException(e.toString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Changes the default value represented by this attribute. |
||||
* |
||||
* @param value the new value. |
||||
* @see Annotation#createMemberValue(ConstPool, CtClass) |
||||
*/ |
||||
public void setDefaultValue(MemberValue value) { |
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(); |
||||
AnnotationsWriter writer = new AnnotationsWriter(output, constPool); |
||||
try { |
||||
value.write(writer); |
||||
writer.close(); |
||||
} |
||||
catch (IOException e) { |
||||
throw new RuntimeException(e); // should never reach here.
|
||||
} |
||||
|
||||
set(output.toByteArray()); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Returns a string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
return getDefaultValue().toString(); |
||||
} |
||||
} |
@ -1,703 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.util.Map; |
||||
import java.util.HashMap; |
||||
import java.io.IOException; |
||||
import java.io.DataInputStream; |
||||
import java.io.ByteArrayOutputStream; |
||||
|
||||
import com.fr.third.javassist.bytecode.annotation.ClassMemberValue; |
||||
|
||||
/** |
||||
* A class representing |
||||
* <code>RuntimeVisibleAnnotations_attribute</code> and |
||||
* <code>RuntimeInvisibleAnnotations_attribute</code>. |
||||
* |
||||
* <p>To obtain an AnnotationAttribute object, invoke |
||||
* <code>getAttribute(AnnotationsAttribute.visibleTag)</code> |
||||
* in <code>ClassFile</code>, <code>MethodInfo</code>, |
||||
* or <code>FieldInfo</code>. The obtained attribute is a |
||||
* runtime visible annotations attribute. |
||||
* If the parameter is |
||||
* <code>AnnotationAttribute.invisibleTag</code>, then the obtained |
||||
* attribute is a runtime invisible one. |
||||
* |
||||
* <p>For example, |
||||
* |
||||
* <ul><pre> |
||||
* import javassist.bytecode.annotation.Annotation; |
||||
* : |
||||
* CtMethod m = ... ; |
||||
* MethodInfo minfo = m.getMethodInfo(); |
||||
* AnnotationsAttribute attr = (AnnotationsAttribute) |
||||
* minfo.getAttribute(AnnotationsAttribute.invisibleTag); |
||||
* Annotation an = attr.getAnnotation("Author"); |
||||
* String s = ((StringMemberValue)an.getMemberValue("name")).getValue(); |
||||
* System.out.println("@Author(name=" + s + ")"); |
||||
* </pre></ul> |
||||
* |
||||
* <p>This code snippet retrieves an annotation of the type <code>Author</code> |
||||
* from the <code>MethodInfo</code> object specified by <code>minfo</code>. |
||||
* Then, it prints the value of <code>name</code> in <code>Author</code>. |
||||
* |
||||
* <p>If the annotation type <code>Author</code> is annotated by a meta annotation: |
||||
* |
||||
* <ul><pre> |
||||
* @Retention(RetentionPolicy.RUNTIME) |
||||
* </pre></ul> |
||||
* |
||||
* <p>Then <code>Author</code> is visible at runtime. Therefore, the third |
||||
* statement of the code snippet above must be changed into: |
||||
* |
||||
* <ul><pre> |
||||
* AnnotationsAttribute attr = (AnnotationsAttribute) |
||||
* minfo.getAttribute(AnnotationsAttribute.visibleTag); |
||||
* </pre></ul> |
||||
* |
||||
* <p>The attribute tag must be <code>visibleTag</code> instead of |
||||
* <code>invisibleTag</code>. |
||||
* |
||||
* <p>If the member value of an annotation is not specified, the default value |
||||
* is used as that member value. If so, <code>getMemberValue()</code> in |
||||
* <code>Annotation</code> returns <code>null</code> |
||||
* since the default value is not included in the |
||||
* <code>AnnotationsAttribute</code>. It is included in the |
||||
* <code>AnnotationDefaultAttribute</code> of the method declared in the |
||||
* annotation type. |
||||
* |
||||
* <p>If you want to record a new AnnotationAttribute object, execute the |
||||
* following snippet: |
||||
* |
||||
* <ul><pre> |
||||
* ClassFile cf = ... ; |
||||
* ConstPool cp = cf.getConstPool(); |
||||
* AnnotationsAttribute attr |
||||
* = new AnnotationsAttribute(cp, AnnotationsAttribute.visibleTag); |
||||
* Annotation a = new Annotation("Author", cp); |
||||
* a.addMemberValue("name", new StringMemberValue("Chiba", cp)); |
||||
* attr.setAnnotation(a); |
||||
* cf.addAttribute(attr); |
||||
* cf.setVersionToJava5(); |
||||
* </pre></ul> |
||||
* |
||||
* <p>The last statement is necessary if the class file was produced by |
||||
* Javassist or JDK 1.4. Otherwise, it is not necessary. |
||||
* |
||||
* @see AnnotationDefaultAttribute |
||||
* @see com.fr.third.javassist.bytecode.annotation.Annotation |
||||
*/ |
||||
public class AnnotationsAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of the <code>RuntimeVisibleAnnotations</code> attribute. |
||||
*/ |
||||
public static final String visibleTag = "RuntimeVisibleAnnotations"; |
||||
|
||||
/** |
||||
* The name of the <code>RuntimeInvisibleAnnotations</code> attribute. |
||||
*/ |
||||
public static final String invisibleTag = "RuntimeInvisibleAnnotations"; |
||||
|
||||
/** |
||||
* Constructs a <code>Runtime(In)VisibleAnnotations_attribute</code>. |
||||
* |
||||
* @param cp constant pool |
||||
* @param attrname attribute name (<code>visibleTag</code> or |
||||
* <code>invisibleTag</code>). |
||||
* @param info the contents of this attribute. It does not |
||||
* include <code>attribute_name_index</code> or |
||||
* <code>attribute_length</code>. |
||||
*/ |
||||
public AnnotationsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, String attrname, byte[] info) { |
||||
super(cp, attrname, info); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an empty |
||||
* <code>Runtime(In)VisibleAnnotations_attribute</code>. |
||||
* A new annotation can be later added to the created attribute |
||||
* by <code>setAnnotations()</code>. |
||||
* |
||||
* @param cp constant pool |
||||
* @param attrname attribute name (<code>visibleTag</code> or |
||||
* <code>invisibleTag</code>). |
||||
* @see #setAnnotations(com.fr.third.javassist.bytecode.annotation.Annotation[]) |
||||
*/ |
||||
public AnnotationsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, String attrname) { |
||||
this(cp, attrname, new byte[] { 0, 0 }); |
||||
} |
||||
|
||||
/** |
||||
* @param n the attribute name. |
||||
*/ |
||||
AnnotationsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>num_annotations</code>. |
||||
*/ |
||||
public int numAnnotations() { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, 0); |
||||
} |
||||
|
||||
/** |
||||
* Copies this attribute and returns a new copy. |
||||
*/ |
||||
public AttributeInfo copy(com.fr.third.javassist.bytecode.ConstPool newCp, Map classnames) { |
||||
Copier copier = new Copier(info, constPool, newCp, classnames); |
||||
try { |
||||
copier.annotationArray(); |
||||
return new AnnotationsAttribute(newCp, getName(), copier.close()); |
||||
} |
||||
catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Parses the annotations and returns a data structure representing |
||||
* the annotation with the specified type. See also |
||||
* <code>getAnnotations()</code> as to the returned data structure. |
||||
* |
||||
* @param type the annotation type. |
||||
* @return null if the specified annotation type is not included. |
||||
* @see #getAnnotations() |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.annotation.Annotation getAnnotation(String type) { |
||||
com.fr.third.javassist.bytecode.annotation.Annotation[] annotations = getAnnotations(); |
||||
for (int i = 0; i < annotations.length; i++) { |
||||
if (annotations[i].getTypeName().equals(type)) |
||||
return annotations[i]; |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Adds an annotation. If there is an annotation with the same type, |
||||
* it is removed before the new annotation is added. |
||||
* |
||||
* @param annotation the added annotation. |
||||
*/ |
||||
public void addAnnotation(com.fr.third.javassist.bytecode.annotation.Annotation annotation) { |
||||
String type = annotation.getTypeName(); |
||||
com.fr.third.javassist.bytecode.annotation.Annotation[] annotations = getAnnotations(); |
||||
for (int i = 0; i < annotations.length; i++) { |
||||
if (annotations[i].getTypeName().equals(type)) { |
||||
annotations[i] = annotation; |
||||
setAnnotations(annotations); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
com.fr.third.javassist.bytecode.annotation.Annotation[] newlist = new com.fr.third.javassist.bytecode.annotation.Annotation[annotations.length + 1]; |
||||
System.arraycopy(annotations, 0, newlist, 0, annotations.length); |
||||
newlist[annotations.length] = annotation; |
||||
setAnnotations(newlist); |
||||
} |
||||
|
||||
/** |
||||
* Parses the annotations and returns a data structure representing |
||||
* that parsed annotations. Note that changes of the node values of the |
||||
* returned tree are not reflected on the annotations represented by |
||||
* this object unless the tree is copied back to this object by |
||||
* <code>setAnnotations()</code>. |
||||
* |
||||
* @see #setAnnotations(com.fr.third.javassist.bytecode.annotation.Annotation[]) |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.annotation.Annotation[] getAnnotations() { |
||||
try { |
||||
return new Parser(info, constPool).parseAnnotations(); |
||||
} |
||||
catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Changes the annotations represented by this object according to |
||||
* the given array of <code>Annotation</code> objects. |
||||
* |
||||
* @param annotations the data structure representing the |
||||
* new annotations. |
||||
*/ |
||||
public void setAnnotations(com.fr.third.javassist.bytecode.annotation.Annotation[] annotations) { |
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(); |
||||
com.fr.third.javassist.bytecode.annotation.AnnotationsWriter writer = new com.fr.third.javassist.bytecode.annotation.AnnotationsWriter(output, constPool); |
||||
try { |
||||
int n = annotations.length; |
||||
writer.numAnnotations(n); |
||||
for (int i = 0; i < n; ++i) |
||||
annotations[i].write(writer); |
||||
|
||||
writer.close(); |
||||
} |
||||
catch (IOException e) { |
||||
throw new RuntimeException(e); // should never reach here.
|
||||
} |
||||
|
||||
set(output.toByteArray()); |
||||
} |
||||
|
||||
/** |
||||
* Changes the annotations. A call to this method is equivalent to: |
||||
* <ul><pre>setAnnotations(new Annotation[] { annotation })</pre></ul> |
||||
* |
||||
* @param annotation the data structure representing |
||||
* the new annotation. |
||||
*/ |
||||
public void setAnnotation(com.fr.third.javassist.bytecode.annotation.Annotation annotation) { |
||||
setAnnotations(new com.fr.third.javassist.bytecode.annotation.Annotation[] { annotation }); |
||||
} |
||||
|
||||
/** |
||||
* @param oldname a JVM class name. |
||||
* @param newname a JVM class name. |
||||
*/ |
||||
void renameClass(String oldname, String newname) { |
||||
HashMap map = new HashMap(); |
||||
map.put(oldname, newname); |
||||
renameClass(map); |
||||
} |
||||
|
||||
void renameClass(Map classnames) { |
||||
Renamer renamer = new Renamer(info, getConstPool(), classnames); |
||||
try { |
||||
renamer.annotationArray(); |
||||
} catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
void getRefClasses(Map classnames) { renameClass(classnames); } |
||||
|
||||
/** |
||||
* Returns a string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
com.fr.third.javassist.bytecode.annotation.Annotation[] a = getAnnotations(); |
||||
StringBuilder sbuf = new StringBuilder(); |
||||
int i = 0; |
||||
while (i < a.length) { |
||||
sbuf.append(a[i++].toString()); |
||||
if (i != a.length) |
||||
sbuf.append(", "); |
||||
} |
||||
|
||||
return sbuf.toString(); |
||||
} |
||||
|
||||
static class Walker { |
||||
byte[] info; |
||||
|
||||
Walker(byte[] attrInfo) { |
||||
info = attrInfo; |
||||
} |
||||
|
||||
final void parameters() throws Exception { |
||||
int numParam = info[0] & 0xff; |
||||
parameters(numParam, 1); |
||||
} |
||||
|
||||
void parameters(int numParam, int pos) throws Exception { |
||||
for (int i = 0; i < numParam; ++i) |
||||
pos = annotationArray(pos); |
||||
} |
||||
|
||||
final void annotationArray() throws Exception { |
||||
annotationArray(0); |
||||
} |
||||
|
||||
final int annotationArray(int pos) throws Exception { |
||||
int num = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos); |
||||
return annotationArray(pos + 2, num); |
||||
} |
||||
|
||||
int annotationArray(int pos, int num) throws Exception { |
||||
for (int i = 0; i < num; ++i) |
||||
pos = annotation(pos); |
||||
|
||||
return pos; |
||||
} |
||||
|
||||
final int annotation(int pos) throws Exception { |
||||
int type = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos); |
||||
int numPairs = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos + 2); |
||||
return annotation(pos + 4, type, numPairs); |
||||
} |
||||
|
||||
int annotation(int pos, int type, int numPairs) throws Exception { |
||||
for (int j = 0; j < numPairs; ++j) |
||||
pos = memberValuePair(pos); |
||||
|
||||
return pos; |
||||
} |
||||
|
||||
final int memberValuePair(int pos) throws Exception { |
||||
int nameIndex = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos); |
||||
return memberValuePair(pos + 2, nameIndex); |
||||
} |
||||
|
||||
int memberValuePair(int pos, int nameIndex) throws Exception { |
||||
return memberValue(pos); |
||||
} |
||||
|
||||
final int memberValue(int pos) throws Exception { |
||||
int tag = info[pos] & 0xff; |
||||
if (tag == 'e') { |
||||
int typeNameIndex = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos + 1); |
||||
int constNameIndex = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos + 3); |
||||
enumMemberValue(pos, typeNameIndex, constNameIndex); |
||||
return pos + 5; |
||||
} |
||||
else if (tag == 'c') { |
||||
int index = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos + 1); |
||||
classMemberValue(pos, index); |
||||
return pos + 3; |
||||
} |
||||
else if (tag == '@') |
||||
return annotationMemberValue(pos + 1); |
||||
else if (tag == '[') { |
||||
int num = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos + 1); |
||||
return arrayMemberValue(pos + 3, num); |
||||
} |
||||
else { // primitive types or String.
|
||||
int index = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos + 1); |
||||
constValueMember(tag, index); |
||||
return pos + 3; |
||||
} |
||||
} |
||||
|
||||
void constValueMember(int tag, int index) throws Exception {} |
||||
|
||||
void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) |
||||
throws Exception { |
||||
} |
||||
|
||||
void classMemberValue(int pos, int index) throws Exception {} |
||||
|
||||
int annotationMemberValue(int pos) throws Exception { |
||||
return annotation(pos); |
||||
} |
||||
|
||||
int arrayMemberValue(int pos, int num) throws Exception { |
||||
for (int i = 0; i < num; ++i) { |
||||
pos = memberValue(pos); |
||||
} |
||||
|
||||
return pos; |
||||
} |
||||
} |
||||
|
||||
static class Renamer extends Walker { |
||||
com.fr.third.javassist.bytecode.ConstPool cpool; |
||||
Map classnames; |
||||
|
||||
/** |
||||
* Constructs a renamer. It renames some class names |
||||
* into the new names specified by <code>map</code>. |
||||
* |
||||
* @param info the annotations attribute. |
||||
* @param cp the constant pool. |
||||
* @param map pairs of replaced and substituted class names. |
||||
* It can be null. |
||||
*/ |
||||
Renamer(byte[] info, com.fr.third.javassist.bytecode.ConstPool cp, Map map) { |
||||
super(info); |
||||
cpool = cp; |
||||
classnames = map; |
||||
} |
||||
|
||||
int annotation(int pos, int type, int numPairs) throws Exception { |
||||
renameType(pos - 4, type); |
||||
return super.annotation(pos, type, numPairs); |
||||
} |
||||
|
||||
void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) |
||||
throws Exception |
||||
{ |
||||
renameType(pos + 1, typeNameIndex); |
||||
super.enumMemberValue(pos, typeNameIndex, constNameIndex); |
||||
} |
||||
|
||||
void classMemberValue(int pos, int index) throws Exception { |
||||
renameType(pos + 1, index); |
||||
super.classMemberValue(pos, index); |
||||
} |
||||
|
||||
private void renameType(int pos, int index) { |
||||
String name = cpool.getUtf8Info(index); |
||||
String newName = com.fr.third.javassist.bytecode.Descriptor.rename(name, classnames); |
||||
if (!name.equals(newName)) { |
||||
int index2 = cpool.addUtf8Info(newName); |
||||
ByteArray.write16bit(index2, info, pos); |
||||
} |
||||
} |
||||
} |
||||
|
||||
static class Copier extends Walker { |
||||
ByteArrayOutputStream output; |
||||
com.fr.third.javassist.bytecode.annotation.AnnotationsWriter writer; |
||||
com.fr.third.javassist.bytecode.ConstPool srcPool, destPool; |
||||
Map classnames; |
||||
|
||||
/** |
||||
* Constructs a copier. This copier renames some class names |
||||
* into the new names specified by <code>map</code> when it copies |
||||
* an annotation attribute. |
||||
* |
||||
* @param info the source attribute. |
||||
* @param src the constant pool of the source class. |
||||
* @param dest the constant pool of the destination class. |
||||
* @param map pairs of replaced and substituted class names. |
||||
* It can be null. |
||||
*/ |
||||
Copier(byte[] info, com.fr.third.javassist.bytecode.ConstPool src, com.fr.third.javassist.bytecode.ConstPool dest, Map map) { |
||||
super(info); |
||||
output = new ByteArrayOutputStream(); |
||||
writer = new com.fr.third.javassist.bytecode.annotation.AnnotationsWriter(output, dest); |
||||
srcPool = src; |
||||
destPool = dest; |
||||
classnames = map; |
||||
} |
||||
|
||||
byte[] close() throws IOException { |
||||
writer.close(); |
||||
return output.toByteArray(); |
||||
} |
||||
|
||||
void parameters(int numParam, int pos) throws Exception { |
||||
writer.numParameters(numParam); |
||||
super.parameters(numParam, pos); |
||||
} |
||||
|
||||
int annotationArray(int pos, int num) throws Exception { |
||||
writer.numAnnotations(num); |
||||
return super.annotationArray(pos, num); |
||||
} |
||||
|
||||
int annotation(int pos, int type, int numPairs) throws Exception { |
||||
writer.annotation(copyType(type), numPairs); |
||||
return super.annotation(pos, type, numPairs); |
||||
} |
||||
|
||||
int memberValuePair(int pos, int nameIndex) throws Exception { |
||||
writer.memberValuePair(copy(nameIndex)); |
||||
return super.memberValuePair(pos, nameIndex); |
||||
} |
||||
|
||||
void constValueMember(int tag, int index) throws Exception { |
||||
writer.constValueIndex(tag, copy(index)); |
||||
super.constValueMember(tag, index); |
||||
} |
||||
|
||||
void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) |
||||
throws Exception |
||||
{ |
||||
writer.enumConstValue(copyType(typeNameIndex), copy(constNameIndex)); |
||||
super.enumMemberValue(pos, typeNameIndex, constNameIndex); |
||||
} |
||||
|
||||
void classMemberValue(int pos, int index) throws Exception { |
||||
writer.classInfoIndex(copyType(index)); |
||||
super.classMemberValue(pos, index); |
||||
} |
||||
|
||||
int annotationMemberValue(int pos) throws Exception { |
||||
writer.annotationValue(); |
||||
return super.annotationMemberValue(pos); |
||||
} |
||||
|
||||
int arrayMemberValue(int pos, int num) throws Exception { |
||||
writer.arrayValue(num); |
||||
return super.arrayMemberValue(pos, num); |
||||
} |
||||
|
||||
/** |
||||
* Copies a constant pool entry into the destination constant pool |
||||
* and returns the index of the copied entry. |
||||
* |
||||
* @param srcIndex the index of the copied entry into the source |
||||
* constant pool. |
||||
* @return the index of the copied item into the destination |
||||
* constant pool. |
||||
*/ |
||||
int copy(int srcIndex) { |
||||
return srcPool.copy(srcIndex, destPool, classnames); |
||||
} |
||||
|
||||
/** |
||||
* Copies a constant pool entry into the destination constant pool |
||||
* and returns the index of the copied entry. That entry must be |
||||
* a Utf8Info representing a class name in the L<class name>; form. |
||||
* |
||||
* @param srcIndex the index of the copied entry into the source |
||||
* constant pool. |
||||
* @return the index of the copied item into the destination |
||||
* constant pool. |
||||
*/ |
||||
int copyType(int srcIndex) { |
||||
String name = srcPool.getUtf8Info(srcIndex); |
||||
String newName = Descriptor.rename(name, classnames); |
||||
return destPool.addUtf8Info(newName); |
||||
} |
||||
} |
||||
|
||||
static class Parser extends Walker { |
||||
com.fr.third.javassist.bytecode.ConstPool pool; |
||||
com.fr.third.javassist.bytecode.annotation.Annotation[][] allParams; // all parameters
|
||||
com.fr.third.javassist.bytecode.annotation.Annotation[] allAnno; // all annotations
|
||||
com.fr.third.javassist.bytecode.annotation.Annotation currentAnno; // current annotation
|
||||
com.fr.third.javassist.bytecode.annotation.MemberValue currentMember; // current member
|
||||
|
||||
/** |
||||
* Constructs a parser. This parser constructs a parse tree of |
||||
* the annotations. |
||||
* |
||||
* @param info the attribute. |
||||
* @param src the constant pool. |
||||
*/ |
||||
Parser(byte[] info, com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
super(info); |
||||
pool = cp; |
||||
} |
||||
|
||||
com.fr.third.javassist.bytecode.annotation.Annotation[][] parseParameters() throws Exception { |
||||
parameters(); |
||||
return allParams; |
||||
} |
||||
|
||||
com.fr.third.javassist.bytecode.annotation.Annotation[] parseAnnotations() throws Exception { |
||||
annotationArray(); |
||||
return allAnno; |
||||
} |
||||
|
||||
com.fr.third.javassist.bytecode.annotation.MemberValue parseMemberValue() throws Exception { |
||||
memberValue(0); |
||||
return currentMember; |
||||
} |
||||
|
||||
void parameters(int numParam, int pos) throws Exception { |
||||
com.fr.third.javassist.bytecode.annotation.Annotation[][] params = new com.fr.third.javassist.bytecode.annotation.Annotation[numParam][]; |
||||
for (int i = 0; i < numParam; ++i) { |
||||
pos = annotationArray(pos); |
||||
params[i] = allAnno; |
||||
} |
||||
|
||||
allParams = params; |
||||
} |
||||
|
||||
int annotationArray(int pos, int num) throws Exception { |
||||
com.fr.third.javassist.bytecode.annotation.Annotation[] array = new com.fr.third.javassist.bytecode.annotation.Annotation[num]; |
||||
for (int i = 0; i < num; ++i) { |
||||
pos = annotation(pos); |
||||
array[i] = currentAnno; |
||||
} |
||||
|
||||
allAnno = array; |
||||
return pos; |
||||
} |
||||
|
||||
int annotation(int pos, int type, int numPairs) throws Exception { |
||||
currentAnno = new com.fr.third.javassist.bytecode.annotation.Annotation(type, pool); |
||||
return super.annotation(pos, type, numPairs); |
||||
} |
||||
|
||||
int memberValuePair(int pos, int nameIndex) throws Exception { |
||||
pos = super.memberValuePair(pos, nameIndex); |
||||
currentAnno.addMemberValue(nameIndex, currentMember); |
||||
return pos; |
||||
} |
||||
|
||||
void constValueMember(int tag, int index) throws Exception { |
||||
com.fr.third.javassist.bytecode.annotation.MemberValue m; |
||||
ConstPool cp = pool; |
||||
switch (tag) { |
||||
case 'B' : |
||||
m = new com.fr.third.javassist.bytecode.annotation.ByteMemberValue(index, cp); |
||||
break; |
||||
case 'C' : |
||||
m = new com.fr.third.javassist.bytecode.annotation.CharMemberValue(index, cp); |
||||
break; |
||||
case 'D' : |
||||
m = new com.fr.third.javassist.bytecode.annotation.DoubleMemberValue(index, cp); |
||||
break; |
||||
case 'F' : |
||||
m = new com.fr.third.javassist.bytecode.annotation.FloatMemberValue(index, cp); |
||||
break; |
||||
case 'I' : |
||||
m = new com.fr.third.javassist.bytecode.annotation.IntegerMemberValue(index, cp); |
||||
break; |
||||
case 'J' : |
||||
m = new com.fr.third.javassist.bytecode.annotation.LongMemberValue(index, cp); |
||||
break; |
||||
case 'S' : |
||||
m = new com.fr.third.javassist.bytecode.annotation.ShortMemberValue(index, cp); |
||||
break; |
||||
case 'Z' : |
||||
m = new com.fr.third.javassist.bytecode.annotation.BooleanMemberValue(index, cp); |
||||
break; |
||||
case 's' : |
||||
m = new com.fr.third.javassist.bytecode.annotation.StringMemberValue(index, cp); |
||||
break; |
||||
default : |
||||
throw new RuntimeException("unknown tag:" + tag); |
||||
} |
||||
|
||||
currentMember = m; |
||||
super.constValueMember(tag, index); |
||||
} |
||||
|
||||
void enumMemberValue(int pos, int typeNameIndex, int constNameIndex) |
||||
throws Exception |
||||
{ |
||||
currentMember = new com.fr.third.javassist.bytecode.annotation.EnumMemberValue(typeNameIndex, |
||||
constNameIndex, pool); |
||||
super.enumMemberValue(pos, typeNameIndex, constNameIndex); |
||||
} |
||||
|
||||
void classMemberValue(int pos, int index) throws Exception { |
||||
currentMember = new ClassMemberValue(index, pool); |
||||
super.classMemberValue(pos, index); |
||||
} |
||||
|
||||
int annotationMemberValue(int pos) throws Exception { |
||||
com.fr.third.javassist.bytecode.annotation.Annotation anno = currentAnno; |
||||
pos = super.annotationMemberValue(pos); |
||||
currentMember = new com.fr.third.javassist.bytecode.annotation.AnnotationMemberValue(currentAnno, pool); |
||||
currentAnno = anno; |
||||
return pos; |
||||
} |
||||
|
||||
int arrayMemberValue(int pos, int num) throws Exception { |
||||
com.fr.third.javassist.bytecode.annotation.ArrayMemberValue amv = new com.fr.third.javassist.bytecode.annotation.ArrayMemberValue(pool); |
||||
com.fr.third.javassist.bytecode.annotation.MemberValue[] elements = new com.fr.third.javassist.bytecode.annotation.MemberValue[num]; |
||||
for (int i = 0; i < num; ++i) { |
||||
pos = memberValue(pos); |
||||
elements[i] = currentMember; |
||||
} |
||||
|
||||
amv.setValue(elements); |
||||
currentMember = amv; |
||||
return pos; |
||||
} |
||||
} |
||||
} |
@ -1,289 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.DataOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
import java.util.ArrayList; |
||||
import java.util.ListIterator; |
||||
import java.util.List; |
||||
import java.util.Iterator; |
||||
|
||||
// Note: if you define a new subclass of AttributeInfo, then
|
||||
// update AttributeInfo.read(), .copy(), and (maybe) write().
|
||||
|
||||
/** |
||||
* <code>attribute_info</code> structure. |
||||
*/ |
||||
public class AttributeInfo { |
||||
protected com.fr.third.javassist.bytecode.ConstPool constPool; |
||||
int name; |
||||
byte[] info; |
||||
|
||||
protected AttributeInfo(com.fr.third.javassist.bytecode.ConstPool cp, int attrname, byte[] attrinfo) { |
||||
constPool = cp; |
||||
name = attrname; |
||||
info = attrinfo; |
||||
} |
||||
|
||||
protected AttributeInfo(com.fr.third.javassist.bytecode.ConstPool cp, String attrname) { |
||||
this(cp, attrname, (byte[])null); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an <code>attribute_info</code> structure. |
||||
* |
||||
* @param cp constant pool table |
||||
* @param attrname attribute name |
||||
* @param attrinfo <code>info</code> field |
||||
* of <code>attribute_info</code> structure. |
||||
*/ |
||||
public AttributeInfo(com.fr.third.javassist.bytecode.ConstPool cp, String attrname, byte[] attrinfo) { |
||||
this(cp, cp.addUtf8Info(attrname), attrinfo); |
||||
} |
||||
|
||||
protected AttributeInfo(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
constPool = cp; |
||||
name = n; |
||||
int len = in.readInt(); |
||||
info = new byte[len]; |
||||
if (len > 0) |
||||
in.readFully(info); |
||||
} |
||||
|
||||
static AttributeInfo read(com.fr.third.javassist.bytecode.ConstPool cp, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
int name = in.readUnsignedShort(); |
||||
String nameStr = cp.getUtf8Info(name); |
||||
if (nameStr.charAt(0) < 'L') { |
||||
if (nameStr.equals(AnnotationDefaultAttribute.tag)) |
||||
return new AnnotationDefaultAttribute(cp, name, in); |
||||
else if (nameStr.equals(BootstrapMethodsAttribute.tag)) |
||||
return new BootstrapMethodsAttribute(cp, name, in); |
||||
else if (nameStr.equals(CodeAttribute.tag)) |
||||
return new CodeAttribute(cp, name, in); |
||||
else if (nameStr.equals(ConstantAttribute.tag)) |
||||
return new ConstantAttribute(cp, name, in); |
||||
else if (nameStr.equals(DeprecatedAttribute.tag)) |
||||
return new DeprecatedAttribute(cp, name, in); |
||||
else if (nameStr.equals(EnclosingMethodAttribute.tag)) |
||||
return new EnclosingMethodAttribute(cp, name, in); |
||||
else if (nameStr.equals(ExceptionsAttribute.tag)) |
||||
return new ExceptionsAttribute(cp, name, in); |
||||
else if (nameStr.equals(InnerClassesAttribute.tag)) |
||||
return new InnerClassesAttribute(cp, name, in); |
||||
} |
||||
else { |
||||
/* Note that the names of Annotations attributes begin with 'R'. |
||||
*/ |
||||
if (nameStr.equals(LineNumberAttribute.tag)) |
||||
return new LineNumberAttribute(cp, name, in); |
||||
else if (nameStr.equals(LocalVariableAttribute.tag)) |
||||
return new LocalVariableAttribute(cp, name, in); |
||||
else if (nameStr.equals(LocalVariableTypeAttribute.tag)) |
||||
return new LocalVariableTypeAttribute(cp, name, in); |
||||
else if (nameStr.equals(AnnotationsAttribute.visibleTag) |
||||
|| nameStr.equals(AnnotationsAttribute.invisibleTag)) { |
||||
// RuntimeVisibleAnnotations or RuntimeInvisibleAnnotations
|
||||
return new AnnotationsAttribute(cp, name, in); |
||||
} |
||||
else if (nameStr.equals(ParameterAnnotationsAttribute.visibleTag) |
||||
|| nameStr.equals(ParameterAnnotationsAttribute.invisibleTag)) |
||||
return new ParameterAnnotationsAttribute(cp, name, in); |
||||
else if (nameStr.equals(SignatureAttribute.tag)) |
||||
return new SignatureAttribute(cp, name, in); |
||||
else if (nameStr.equals(SourceFileAttribute.tag)) |
||||
return new SourceFileAttribute(cp, name, in); |
||||
else if (nameStr.equals(SyntheticAttribute.tag)) |
||||
return new SyntheticAttribute(cp, name, in); |
||||
else if (nameStr.equals(com.fr.third.javassist.bytecode.StackMap.tag)) |
||||
return new StackMap(cp, name, in); |
||||
else if (nameStr.equals(StackMapTable.tag)) |
||||
return new StackMapTable(cp, name, in); |
||||
} |
||||
|
||||
return new AttributeInfo(cp, name, in); |
||||
} |
||||
|
||||
/** |
||||
* Returns an attribute name. |
||||
*/ |
||||
public String getName() { |
||||
return constPool.getUtf8Info(name); |
||||
} |
||||
|
||||
/** |
||||
* Returns a constant pool table. |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.ConstPool getConstPool() { return constPool; } |
||||
|
||||
/** |
||||
* Returns the length of this <code>attribute_info</code> |
||||
* structure. |
||||
* The returned value is <code>attribute_length + 6</code>. |
||||
*/ |
||||
public int length() { |
||||
return info.length + 6; |
||||
} |
||||
|
||||
/** |
||||
* Returns the <code>info</code> field |
||||
* of this <code>attribute_info</code> structure. |
||||
* |
||||
* <p>This method is not available if the object is an instance |
||||
* of <code>CodeAttribute</code>. |
||||
*/ |
||||
public byte[] get() { return info; } |
||||
|
||||
/** |
||||
* Sets the <code>info</code> field |
||||
* of this <code>attribute_info</code> structure. |
||||
* |
||||
* <p>This method is not available if the object is an instance |
||||
* of <code>CodeAttribute</code>. |
||||
*/ |
||||
public void set(byte[] newinfo) { info = newinfo; } |
||||
|
||||
/** |
||||
* Makes a copy. Class names are replaced according to the |
||||
* given <code>Map</code> object. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
*/ |
||||
public AttributeInfo copy(com.fr.third.javassist.bytecode.ConstPool newCp, Map classnames) { |
||||
int s = info.length; |
||||
byte[] srcInfo = info; |
||||
byte[] newInfo = new byte[s]; |
||||
for (int i = 0; i < s; ++i) |
||||
newInfo[i] = srcInfo[i]; |
||||
|
||||
return new AttributeInfo(newCp, getName(), newInfo); |
||||
} |
||||
|
||||
void write(DataOutputStream out) throws IOException { |
||||
out.writeShort(name); |
||||
out.writeInt(info.length); |
||||
if (info.length > 0) |
||||
out.write(info); |
||||
} |
||||
|
||||
static int getLength(ArrayList list) { |
||||
int size = 0; |
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
AttributeInfo attr = (AttributeInfo)list.get(i); |
||||
size += attr.length(); |
||||
} |
||||
|
||||
return size; |
||||
} |
||||
|
||||
static AttributeInfo lookup(ArrayList list, String name) { |
||||
if (list == null) |
||||
return null; |
||||
|
||||
ListIterator iterator = list.listIterator(); |
||||
while (iterator.hasNext()) { |
||||
AttributeInfo ai = (AttributeInfo)iterator.next(); |
||||
if (ai.getName().equals(name)) |
||||
return ai; |
||||
} |
||||
|
||||
return null; // no such attribute
|
||||
} |
||||
|
||||
static synchronized void remove(ArrayList list, String name) { |
||||
if (list == null) |
||||
return; |
||||
|
||||
ListIterator iterator = list.listIterator(); |
||||
while (iterator.hasNext()) { |
||||
AttributeInfo ai = (AttributeInfo)iterator.next(); |
||||
if (ai.getName().equals(name)) |
||||
iterator.remove(); |
||||
} |
||||
} |
||||
|
||||
static void writeAll(ArrayList list, DataOutputStream out) |
||||
throws IOException |
||||
{ |
||||
if (list == null) |
||||
return; |
||||
|
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
AttributeInfo attr = (AttributeInfo)list.get(i); |
||||
attr.write(out); |
||||
} |
||||
} |
||||
|
||||
static ArrayList copyAll(ArrayList list, ConstPool cp) { |
||||
if (list == null) |
||||
return null; |
||||
|
||||
ArrayList newList = new ArrayList(); |
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
AttributeInfo attr = (AttributeInfo)list.get(i); |
||||
newList.add(attr.copy(cp, null)); |
||||
} |
||||
|
||||
return newList; |
||||
} |
||||
|
||||
/* The following two methods are used to implement |
||||
* ClassFile.renameClass(). |
||||
* Only CodeAttribute, LocalVariableAttribute, |
||||
* AnnotationsAttribute, and SignatureAttribute |
||||
* override these methods. |
||||
*/ |
||||
void renameClass(String oldname, String newname) {} |
||||
void renameClass(Map classnames) {} |
||||
|
||||
static void renameClass(List attributes, String oldname, String newname) { |
||||
Iterator iterator = attributes.iterator(); |
||||
while (iterator.hasNext()) { |
||||
AttributeInfo ai = (AttributeInfo)iterator.next(); |
||||
ai.renameClass(oldname, newname); |
||||
} |
||||
} |
||||
|
||||
static void renameClass(List attributes, Map classnames) { |
||||
Iterator iterator = attributes.iterator(); |
||||
while (iterator.hasNext()) { |
||||
AttributeInfo ai = (AttributeInfo)iterator.next(); |
||||
ai.renameClass(classnames); |
||||
} |
||||
} |
||||
|
||||
void getRefClasses(Map classnames) {} |
||||
|
||||
static void getRefClasses(List attributes, Map classnames) { |
||||
Iterator iterator = attributes.iterator(); |
||||
while (iterator.hasNext()) { |
||||
AttributeInfo ai = (AttributeInfo)iterator.next(); |
||||
ai.getRefClasses(classnames); |
||||
} |
||||
} |
||||
} |
@ -1,40 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
/** |
||||
* Signals that a bad bytecode sequence has been found. |
||||
*/ |
||||
public class BadBytecode extends Exception { |
||||
public BadBytecode(int opcode) { |
||||
super("bytecode " + opcode); |
||||
} |
||||
|
||||
public BadBytecode(String msg) { |
||||
super(msg); |
||||
} |
||||
|
||||
public BadBytecode(String msg, Throwable cause) { |
||||
super(msg, cause); |
||||
} |
||||
|
||||
public BadBytecode(MethodInfo minfo, Throwable cause) { |
||||
super(minfo.toString() + " in " |
||||
+ minfo.getConstPool().getClassName() |
||||
+ ": " + cause.getMessage(), cause); |
||||
} |
||||
} |
@ -1,123 +0,0 @@
|
||||
package com.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
public class BootstrapMethodsAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"BootstrapMethods"</code>. |
||||
*/ |
||||
public static final String tag = "BootstrapMethods"; |
||||
|
||||
/** |
||||
* An element of <code>bootstrap_methods</code>. |
||||
*/ |
||||
public static class BootstrapMethod { |
||||
/** |
||||
* Constructs an element of <code>bootstrap_methods</code>. |
||||
* |
||||
* @param method <code>bootstrap_method_ref</code>. |
||||
* @param args <code>bootstrap_arguments</code>. |
||||
*/ |
||||
public BootstrapMethod(int method, int[] args) { |
||||
methodRef = method; |
||||
arguments = args; |
||||
} |
||||
|
||||
/** |
||||
* <code>bootstrap_method_ref</code>. |
||||
* The value at this index must be a <code>CONSTANT_MethodHandle_info</code>. |
||||
*/ |
||||
public int methodRef; |
||||
|
||||
/** |
||||
* <code>bootstrap_arguments</code>. |
||||
*/ |
||||
public int[] arguments; |
||||
} |
||||
|
||||
BootstrapMethodsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a BootstrapMethods attribute. |
||||
* |
||||
* @param cp a constant pool table. |
||||
* @param methods the contents. |
||||
*/ |
||||
public BootstrapMethodsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, BootstrapMethod[] methods) { |
||||
super(cp, tag); |
||||
int size = 2; |
||||
for (int i = 0; i < methods.length; i++) |
||||
size += 4 + methods[i].arguments.length * 2; |
||||
|
||||
byte[] data = new byte[size]; |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(methods.length, data, 0); // num_bootstrap_methods
|
||||
int pos = 2; |
||||
for (int i = 0; i < methods.length; i++) { |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(methods[i].methodRef, data, pos); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(methods[i].arguments.length, data, pos + 2); |
||||
int[] args = methods[i].arguments; |
||||
pos += 4; |
||||
for (int k = 0; k < args.length; k++) { |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(args[k], data, pos); |
||||
pos += 2; |
||||
} |
||||
} |
||||
|
||||
set(data); |
||||
} |
||||
|
||||
/** |
||||
* Obtains <code>bootstrap_methods</code> in this attribute. |
||||
* |
||||
* @return an array of <code>BootstrapMethod</code>. Since it |
||||
* is a fresh copy, modifying the returned array does not |
||||
* affect the original contents of this attribute. |
||||
*/ |
||||
public BootstrapMethod[] getMethods() { |
||||
byte[] data = this.get(); |
||||
int num = com.fr.third.javassist.bytecode.ByteArray.readU16bit(data, 0); |
||||
BootstrapMethod[] methods = new BootstrapMethod[num]; |
||||
int pos = 2; |
||||
for (int i = 0; i < num; i++) { |
||||
int ref = com.fr.third.javassist.bytecode.ByteArray.readU16bit(data, pos); |
||||
int len = com.fr.third.javassist.bytecode.ByteArray.readU16bit(data, pos + 2); |
||||
int[] args = new int[len]; |
||||
pos += 4; |
||||
for (int k = 0; k < len; k++) { |
||||
args[k] = ByteArray.readU16bit(data, pos); |
||||
pos += 2; |
||||
} |
||||
|
||||
methods[i] = new BootstrapMethod(ref, args); |
||||
} |
||||
|
||||
return methods; |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. Class names are replaced according to the |
||||
* given <code>Map</code> object. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
*/ |
||||
public AttributeInfo copy(com.fr.third.javassist.bytecode.ConstPool newCp, Map classnames) { |
||||
BootstrapMethod[] methods = getMethods(); |
||||
ConstPool thisCp = getConstPool(); |
||||
for (int i = 0; i < methods.length; i++) { |
||||
BootstrapMethod m = methods[i]; |
||||
m.methodRef = thisCp.copy(m.methodRef, newCp, classnames); |
||||
for (int k = 0; k < m.arguments.length; k++) |
||||
m.arguments[k] = thisCp.copy(m.arguments[k], newCp, classnames); |
||||
} |
||||
|
||||
return new BootstrapMethodsAttribute(newCp, methods); |
||||
} |
||||
} |
@ -1,77 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
/** |
||||
* A collection of static methods for reading and writing a byte array. |
||||
*/ |
||||
public class ByteArray { |
||||
/** |
||||
* Reads an unsigned 16bit integer at the index. |
||||
*/ |
||||
public static int readU16bit(byte[] code, int index) { |
||||
return ((code[index] & 0xff) << 8) | (code[index + 1] & 0xff); |
||||
} |
||||
|
||||
/** |
||||
* Reads a signed 16bit integer at the index. |
||||
*/ |
||||
public static int readS16bit(byte[] code, int index) { |
||||
return (code[index] << 8) | (code[index + 1] & 0xff); |
||||
} |
||||
|
||||
/** |
||||
* Writes a 16bit integer at the index. |
||||
*/ |
||||
public static void write16bit(int value, byte[] code, int index) { |
||||
code[index] = (byte)(value >>> 8); |
||||
code[index + 1] = (byte)value; |
||||
} |
||||
|
||||
/** |
||||
* Reads a 32bit integer at the index. |
||||
*/ |
||||
public static int read32bit(byte[] code, int index) { |
||||
return (code[index] << 24) | ((code[index + 1] & 0xff) << 16) |
||||
| ((code[index + 2] & 0xff) << 8) | (code[index + 3] & 0xff); |
||||
} |
||||
|
||||
/** |
||||
* Writes a 32bit integer at the index. |
||||
*/ |
||||
public static void write32bit(int value, byte[] code, int index) { |
||||
code[index] = (byte)(value >>> 24); |
||||
code[index + 1] = (byte)(value >>> 16); |
||||
code[index + 2] = (byte)(value >>> 8); |
||||
code[index + 3] = (byte)value; |
||||
} |
||||
|
||||
/** |
||||
* Copies a 32bit integer. |
||||
* |
||||
* @param src the source byte array. |
||||
* @param isrc the index into the source byte array. |
||||
* @param dest the destination byte array. |
||||
* @param idest the index into the destination byte array. |
||||
*/ |
||||
static void copy32bit(byte[] src, int isrc, byte[] dest, int idest) { |
||||
dest[idest] = src[isrc]; |
||||
dest[idest + 1] = src[isrc + 1]; |
||||
dest[idest + 2] = src[isrc + 2]; |
||||
dest[idest + 3] = src[isrc + 3]; |
||||
} |
||||
} |
@ -1,194 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.OutputStream; |
||||
import java.io.IOException; |
||||
|
||||
final class ByteStream extends OutputStream { |
||||
private byte[] buf; |
||||
private int count; |
||||
|
||||
public ByteStream() { this(32); } |
||||
|
||||
public ByteStream(int size) { |
||||
buf = new byte[size]; |
||||
count = 0; |
||||
} |
||||
|
||||
public int getPos() { return count; } |
||||
public int size() { return count; } |
||||
|
||||
public void writeBlank(int len) { |
||||
enlarge(len); |
||||
count += len; |
||||
} |
||||
|
||||
public void write(byte[] data) { |
||||
write(data, 0, data.length); |
||||
} |
||||
|
||||
public void write(byte[] data, int off, int len) { |
||||
enlarge(len); |
||||
System.arraycopy(data, off, buf, count, len); |
||||
count += len; |
||||
} |
||||
|
||||
public void write(int b) { |
||||
enlarge(1); |
||||
int oldCount = count; |
||||
buf[oldCount] = (byte)b; |
||||
count = oldCount + 1; |
||||
} |
||||
|
||||
public void writeShort(int s) { |
||||
enlarge(2); |
||||
int oldCount = count; |
||||
buf[oldCount] = (byte)(s >>> 8); |
||||
buf[oldCount + 1] = (byte)s; |
||||
count = oldCount + 2; |
||||
} |
||||
|
||||
public void writeInt(int i) { |
||||
enlarge(4); |
||||
int oldCount = count; |
||||
buf[oldCount] = (byte)(i >>> 24); |
||||
buf[oldCount + 1] = (byte)(i >>> 16); |
||||
buf[oldCount + 2] = (byte)(i >>> 8); |
||||
buf[oldCount + 3] = (byte)i; |
||||
count = oldCount + 4; |
||||
} |
||||
|
||||
public void writeLong(long i) { |
||||
enlarge(8); |
||||
int oldCount = count; |
||||
buf[oldCount] = (byte)(i >>> 56); |
||||
buf[oldCount + 1] = (byte)(i >>> 48); |
||||
buf[oldCount + 2] = (byte)(i >>> 40); |
||||
buf[oldCount + 3] = (byte)(i >>> 32); |
||||
buf[oldCount + 4] = (byte)(i >>> 24); |
||||
buf[oldCount + 5] = (byte)(i >>> 16); |
||||
buf[oldCount + 6] = (byte)(i >>> 8); |
||||
buf[oldCount + 7] = (byte)i; |
||||
count = oldCount + 8; |
||||
} |
||||
|
||||
public void writeFloat(float v) { |
||||
writeInt(Float.floatToIntBits(v)); |
||||
} |
||||
|
||||
public void writeDouble(double v) { |
||||
writeLong(Double.doubleToLongBits(v)); |
||||
} |
||||
|
||||
public void writeUTF(String s) { |
||||
int sLen = s.length(); |
||||
int pos = count; |
||||
enlarge(sLen + 2); |
||||
|
||||
byte[] buffer = buf; |
||||
buffer[pos++] = (byte)(sLen >>> 8); |
||||
buffer[pos++] = (byte)sLen; |
||||
for (int i = 0; i < sLen; ++i) { |
||||
char c = s.charAt(i); |
||||
if (0x01 <= c && c <= 0x7f) |
||||
buffer[pos++] = (byte)c; |
||||
else { |
||||
writeUTF2(s, sLen, i); |
||||
return; |
||||
} |
||||
} |
||||
|
||||
count = pos; |
||||
} |
||||
|
||||
private void writeUTF2(String s, int sLen, int offset) { |
||||
int size = sLen; |
||||
for (int i = offset; i < sLen; i++) { |
||||
int c = s.charAt(i); |
||||
if (c > 0x7ff) |
||||
size += 2; // 3 bytes code
|
||||
else if (c == 0 || c > 0x7f) |
||||
++size; // 2 bytes code
|
||||
} |
||||
|
||||
if (size > 65535) |
||||
throw new RuntimeException( |
||||
"encoded string too long: " + sLen + size + " bytes"); |
||||
|
||||
enlarge(size + 2); |
||||
int pos = count; |
||||
byte[] buffer = buf; |
||||
buffer[pos] = (byte)(size >>> 8); |
||||
buffer[pos + 1] = (byte)size; |
||||
pos += 2 + offset; |
||||
for (int j = offset; j < sLen; ++j) { |
||||
int c = s.charAt(j); |
||||
if (0x01 <= c && c <= 0x7f) |
||||
buffer[pos++] = (byte) c; |
||||
else if (c > 0x07ff) { |
||||
buffer[pos] = (byte)(0xe0 | ((c >> 12) & 0x0f)); |
||||
buffer[pos + 1] = (byte)(0x80 | ((c >> 6) & 0x3f)); |
||||
buffer[pos + 2] = (byte)(0x80 | (c & 0x3f)); |
||||
pos += 3; |
||||
} |
||||
else { |
||||
buffer[pos] = (byte)(0xc0 | ((c >> 6) & 0x1f)); |
||||
buffer[pos + 1] = (byte)(0x80 | (c & 0x3f)); |
||||
pos += 2; |
||||
} |
||||
} |
||||
|
||||
count = pos; |
||||
} |
||||
|
||||
public void write(int pos, int value) { |
||||
buf[pos] = (byte)value; |
||||
} |
||||
|
||||
public void writeShort(int pos, int value) { |
||||
buf[pos] = (byte)(value >>> 8); |
||||
buf[pos + 1] = (byte)value; |
||||
} |
||||
|
||||
public void writeInt(int pos, int value) { |
||||
buf[pos] = (byte)(value >>> 24); |
||||
buf[pos + 1] = (byte)(value >>> 16); |
||||
buf[pos + 2] = (byte)(value >>> 8); |
||||
buf[pos + 3] = (byte)value; |
||||
} |
||||
|
||||
public byte[] toByteArray() { |
||||
byte[] buf2 = new byte[count]; |
||||
System.arraycopy(buf, 0, buf2, 0, count); |
||||
return buf2; |
||||
} |
||||
|
||||
public void writeTo(OutputStream out) throws IOException { |
||||
out.write(buf, 0, count); |
||||
} |
||||
|
||||
public void enlarge(int delta) { |
||||
int newCount = count + delta; |
||||
if (newCount > buf.length) { |
||||
int newLen = buf.length << 1; |
||||
byte[] newBuf = new byte[newLen > newCount ? newLen : newCount]; |
||||
System.arraycopy(buf, 0, newBuf, 0, count); |
||||
buf = newBuf; |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,909 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.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.ListIterator; |
||||
import java.util.Map; |
||||
import com.fr.third.javassist.CannotCompileException; |
||||
import com.fr.third.javassist.CtClass; |
||||
|
||||
/** |
||||
* <code>ClassFile</code> represents a Java <code>.class</code> file, which |
||||
* consists of a constant pool, methods, fields, and attributes. |
||||
* |
||||
* @see CtClass#getClassFile() |
||||
*/ |
||||
public final class ClassFile { |
||||
int major, minor; // version number
|
||||
ConstPool constPool; |
||||
int thisClass; |
||||
int accessFlags; |
||||
int superClass; |
||||
int[] interfaces; |
||||
ArrayList fields; |
||||
ArrayList methods; |
||||
ArrayList attributes; |
||||
String thisclassname; // not JVM-internal name
|
||||
String[] cachedInterfaces; |
||||
String cachedSuperclass; |
||||
|
||||
/** |
||||
* The major version number of class files |
||||
* for JDK 1.1. |
||||
*/ |
||||
public static final int JAVA_1 = 45; |
||||
|
||||
/** |
||||
* The major version number of class files |
||||
* for JDK 1.2. |
||||
*/ |
||||
public static final int JAVA_2 = 46; |
||||
|
||||
/** |
||||
* The major version number of class files |
||||
* for JDK 1.3. |
||||
*/ |
||||
public static final int JAVA_3 = 47; |
||||
|
||||
/** |
||||
* The major version number of class files |
||||
* for JDK 1.4. |
||||
*/ |
||||
public static final int JAVA_4 = 48; |
||||
|
||||
/** |
||||
* The major version number of class files |
||||
* for JDK 1.5. |
||||
*/ |
||||
public static final int JAVA_5 = 49; |
||||
|
||||
/** |
||||
* The major version number of class files |
||||
* for JDK 1.6. |
||||
*/ |
||||
public static final int JAVA_6 = 50; |
||||
|
||||
/** |
||||
* The major version number of class files |
||||
* for JDK 1.7. |
||||
*/ |
||||
public static final int JAVA_7 = 51; |
||||
|
||||
/** |
||||
* The major version number of class files |
||||
* for JDK 1.8. |
||||
*/ |
||||
public static final int JAVA_8 = 52; |
||||
|
||||
/** |
||||
* The major version number of class files created |
||||
* from scratch. The default value is 47 (JDK 1.3). |
||||
* It is 49 (JDK 1.5) |
||||
* if the JVM supports <code>java.lang.StringBuilder</code>. |
||||
* It is 50 (JDK 1.6) |
||||
* if the JVM supports <code>java.util.zip.DeflaterInputStream</code>. |
||||
* It is 51 (JDK 1.7) |
||||
* if the JVM supports <code>java.lang.invoke.CallSite</code>. |
||||
*/ |
||||
public static int MAJOR_VERSION = JAVA_3; |
||||
|
||||
static { |
||||
try { |
||||
Class.forName("java.lang.StringBuilder"); |
||||
MAJOR_VERSION = JAVA_5; |
||||
Class.forName("java.util.zip.DeflaterInputStream"); |
||||
MAJOR_VERSION = JAVA_6; |
||||
Class.forName("java.lang.invoke.CallSite"); |
||||
MAJOR_VERSION = JAVA_7; |
||||
} |
||||
catch (Throwable t) {} |
||||
} |
||||
|
||||
/** |
||||
* Constructs a class file from a byte stream. |
||||
*/ |
||||
public ClassFile(DataInputStream in) throws IOException { |
||||
read(in); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a class file including no members. |
||||
* |
||||
* @param isInterface |
||||
* true if this is an interface. false if this is a class. |
||||
* @param classname |
||||
* a fully-qualified class name |
||||
* @param superclass |
||||
* a fully-qualified super class name |
||||
*/ |
||||
public ClassFile(boolean isInterface, String classname, String superclass) { |
||||
major = MAJOR_VERSION; |
||||
minor = 0; // JDK 1.3 or later
|
||||
constPool = new ConstPool(classname); |
||||
thisClass = constPool.getThisClassInfo(); |
||||
if (isInterface) |
||||
accessFlags = AccessFlag.INTERFACE | AccessFlag.ABSTRACT; |
||||
else |
||||
accessFlags = AccessFlag.SUPER; |
||||
|
||||
initSuperclass(superclass); |
||||
interfaces = null; |
||||
fields = new ArrayList(); |
||||
methods = new ArrayList(); |
||||
thisclassname = classname; |
||||
|
||||
attributes = new ArrayList(); |
||||
attributes.add(new SourceFileAttribute(constPool, |
||||
getSourcefileName(thisclassname))); |
||||
} |
||||
|
||||
private void initSuperclass(String superclass) { |
||||
if (superclass != null) { |
||||
this.superClass = constPool.addClassInfo(superclass); |
||||
cachedSuperclass = superclass; |
||||
} |
||||
else { |
||||
this.superClass = constPool.addClassInfo("java.lang.Object"); |
||||
cachedSuperclass = "java.lang.Object"; |
||||
} |
||||
} |
||||
|
||||
private static String getSourcefileName(String qname) { |
||||
int index = qname.lastIndexOf('.'); |
||||
if (index >= 0) |
||||
qname = qname.substring(index + 1); |
||||
|
||||
return qname + ".java"; |
||||
} |
||||
|
||||
/** |
||||
* Eliminates dead constant pool items. If a method or a field is removed, |
||||
* the constant pool items used by that method/field become dead items. This |
||||
* method recreates a constant pool. |
||||
*/ |
||||
public void compact() { |
||||
ConstPool cp = compact0(); |
||||
ArrayList list = methods; |
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
MethodInfo minfo = (MethodInfo)list.get(i); |
||||
minfo.compact(cp); |
||||
} |
||||
|
||||
list = fields; |
||||
n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
FieldInfo finfo = (FieldInfo)list.get(i); |
||||
finfo.compact(cp); |
||||
} |
||||
|
||||
attributes = AttributeInfo.copyAll(attributes, cp); |
||||
constPool = cp; |
||||
} |
||||
|
||||
private ConstPool compact0() { |
||||
ConstPool cp = new ConstPool(thisclassname); |
||||
thisClass = cp.getThisClassInfo(); |
||||
String sc = getSuperclass(); |
||||
if (sc != null) |
||||
superClass = cp.addClassInfo(getSuperclass()); |
||||
|
||||
if (interfaces != null) { |
||||
int n = interfaces.length; |
||||
for (int i = 0; i < n; ++i) |
||||
interfaces[i] |
||||
= cp.addClassInfo(constPool.getClassInfo(interfaces[i])); |
||||
} |
||||
|
||||
return cp; |
||||
} |
||||
|
||||
/** |
||||
* Discards all attributes, associated with both the class file and the |
||||
* members such as a code attribute and exceptions attribute. The unused |
||||
* constant pool entries are also discarded (a new packed constant pool is |
||||
* constructed). |
||||
*/ |
||||
public void prune() { |
||||
ConstPool cp = compact0(); |
||||
ArrayList 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 signature |
||||
= getAttribute(SignatureAttribute.tag); |
||||
if (signature != null) { |
||||
signature = signature.copy(cp, null); |
||||
newAttributes.add(signature); |
||||
} |
||||
|
||||
ArrayList list = methods; |
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
MethodInfo minfo = (MethodInfo)list.get(i); |
||||
minfo.prune(cp); |
||||
} |
||||
|
||||
list = fields; |
||||
n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
FieldInfo finfo = (FieldInfo)list.get(i); |
||||
finfo.prune(cp); |
||||
} |
||||
|
||||
attributes = newAttributes; |
||||
constPool = cp; |
||||
} |
||||
|
||||
/** |
||||
* Returns a constant pool table. |
||||
*/ |
||||
public ConstPool getConstPool() { |
||||
return constPool; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if this is an interface. |
||||
*/ |
||||
public boolean isInterface() { |
||||
return (accessFlags & AccessFlag.INTERFACE) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if this is a final class or interface. |
||||
*/ |
||||
public boolean isFinal() { |
||||
return (accessFlags & AccessFlag.FINAL) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if this is an abstract class or an interface. |
||||
*/ |
||||
public boolean isAbstract() { |
||||
return (accessFlags & AccessFlag.ABSTRACT) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns access flags. |
||||
* |
||||
* @see AccessFlag |
||||
*/ |
||||
public int getAccessFlags() { |
||||
return accessFlags; |
||||
} |
||||
|
||||
/** |
||||
* Changes access flags. |
||||
* |
||||
* @see AccessFlag |
||||
*/ |
||||
public void setAccessFlags(int acc) { |
||||
if ((acc & AccessFlag.INTERFACE) == 0) |
||||
acc |= AccessFlag.SUPER; |
||||
|
||||
accessFlags = acc; |
||||
} |
||||
|
||||
/** |
||||
* Returns access and property flags of this nested class. |
||||
* This method returns -1 if the class is not a nested class. |
||||
* |
||||
* <p>The returned value is obtained from <code>inner_class_access_flags</code> |
||||
* of the entry representing this nested class itself |
||||
* in <code>InnerClasses_attribute</code>>. |
||||
*/ |
||||
public int getInnerAccessFlags() { |
||||
InnerClassesAttribute ica |
||||
= (InnerClassesAttribute)getAttribute(InnerClassesAttribute.tag); |
||||
if (ica == null) |
||||
return -1; |
||||
|
||||
String name = getName(); |
||||
int n = ica.tableLength(); |
||||
for (int i = 0; i < n; ++i) |
||||
if (name.equals(ica.innerClass(i))) |
||||
return ica.accessFlags(i); |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
/** |
||||
* Returns the class name. |
||||
*/ |
||||
public String getName() { |
||||
return thisclassname; |
||||
} |
||||
|
||||
/** |
||||
* Sets the class name. This method substitutes the new name for all |
||||
* occurrences of the old class name in the class file. |
||||
*/ |
||||
public void setName(String name) { |
||||
renameClass(thisclassname, name); |
||||
} |
||||
|
||||
/** |
||||
* Returns the super class name. |
||||
*/ |
||||
public String getSuperclass() { |
||||
if (cachedSuperclass == null) |
||||
cachedSuperclass = constPool.getClassInfo(superClass); |
||||
|
||||
return cachedSuperclass; |
||||
} |
||||
|
||||
/** |
||||
* Returns the index of the constant pool entry representing the super |
||||
* class. |
||||
*/ |
||||
public int getSuperclassId() { |
||||
return superClass; |
||||
} |
||||
|
||||
/** |
||||
* Sets the super class. |
||||
* |
||||
* <p> |
||||
* The new super class should inherit from the old super class. |
||||
* This method modifies constructors so that they call constructors declared |
||||
* in the new super class. |
||||
*/ |
||||
public void setSuperclass(String superclass) throws CannotCompileException { |
||||
if (superclass == null) |
||||
superclass = "java.lang.Object"; |
||||
|
||||
try { |
||||
this.superClass = constPool.addClassInfo(superclass); |
||||
ArrayList list = methods; |
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
MethodInfo minfo = (MethodInfo)list.get(i); |
||||
minfo.setSuperclass(superclass); |
||||
} |
||||
} |
||||
catch (BadBytecode e) { |
||||
throw new CannotCompileException(e); |
||||
} |
||||
cachedSuperclass = superclass; |
||||
} |
||||
|
||||
/** |
||||
* Replaces all occurrences of a class name in the class file. |
||||
* |
||||
* <p> |
||||
* If class X is substituted for class Y in the class file, X and Y must |
||||
* have the same signature. If Y provides a method m(), X must provide it |
||||
* even if X inherits m() from the super class. If this fact is not |
||||
* guaranteed, the bytecode verifier may cause an error. |
||||
* |
||||
* @param oldname |
||||
* the replaced class name |
||||
* @param newname |
||||
* the substituted class name |
||||
*/ |
||||
public final void renameClass(String oldname, String newname) { |
||||
ArrayList list; |
||||
int n; |
||||
|
||||
if (oldname.equals(newname)) |
||||
return; |
||||
|
||||
if (oldname.equals(thisclassname)) |
||||
thisclassname = newname; |
||||
|
||||
oldname = Descriptor.toJvmName(oldname); |
||||
newname = Descriptor.toJvmName(newname); |
||||
constPool.renameClass(oldname, newname); |
||||
|
||||
AttributeInfo.renameClass(attributes, oldname, newname); |
||||
list = methods; |
||||
n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
MethodInfo minfo = (MethodInfo)list.get(i); |
||||
String desc = minfo.getDescriptor(); |
||||
minfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); |
||||
AttributeInfo.renameClass(minfo.getAttributes(), oldname, newname); |
||||
} |
||||
|
||||
list = fields; |
||||
n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
FieldInfo finfo = (FieldInfo)list.get(i); |
||||
String desc = finfo.getDescriptor(); |
||||
finfo.setDescriptor(Descriptor.rename(desc, oldname, newname)); |
||||
AttributeInfo.renameClass(finfo.getAttributes(), oldname, newname); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Replaces all occurrences of several class names in the class file. |
||||
* |
||||
* @param classnames |
||||
* specifies which class name is replaced with which new name. |
||||
* Class names must be described with the JVM-internal |
||||
* representation like <code>java/lang/Object</code>. |
||||
* @see #renameClass(String,String) |
||||
*/ |
||||
public final void renameClass(Map classnames) { |
||||
String jvmNewThisName = (String)classnames.get(Descriptor |
||||
.toJvmName(thisclassname)); |
||||
if (jvmNewThisName != null) |
||||
thisclassname = Descriptor.toJavaName(jvmNewThisName); |
||||
|
||||
constPool.renameClass(classnames); |
||||
|
||||
AttributeInfo.renameClass(attributes, classnames); |
||||
ArrayList list = methods; |
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
MethodInfo minfo = (MethodInfo)list.get(i); |
||||
String desc = minfo.getDescriptor(); |
||||
minfo.setDescriptor(Descriptor.rename(desc, classnames)); |
||||
AttributeInfo.renameClass(minfo.getAttributes(), classnames); |
||||
} |
||||
|
||||
list = fields; |
||||
n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
FieldInfo finfo = (FieldInfo)list.get(i); |
||||
String desc = finfo.getDescriptor(); |
||||
finfo.setDescriptor(Descriptor.rename(desc, classnames)); |
||||
AttributeInfo.renameClass(finfo.getAttributes(), classnames); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Internal-use only. |
||||
* <code>CtClass.getRefClasses()</code> calls this method. |
||||
*/ |
||||
public final void getRefClasses(Map classnames) { |
||||
constPool.renameClass(classnames); |
||||
|
||||
AttributeInfo.getRefClasses(attributes, classnames); |
||||
ArrayList list = methods; |
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
MethodInfo minfo = (MethodInfo)list.get(i); |
||||
String desc = minfo.getDescriptor(); |
||||
Descriptor.rename(desc, classnames); |
||||
AttributeInfo.getRefClasses(minfo.getAttributes(), classnames); |
||||
} |
||||
|
||||
list = fields; |
||||
n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
FieldInfo finfo = (FieldInfo)list.get(i); |
||||
String desc = finfo.getDescriptor(); |
||||
Descriptor.rename(desc, classnames); |
||||
AttributeInfo.getRefClasses(finfo.getAttributes(), classnames); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the names of the interfaces implemented by the class. |
||||
* The returned array is read only. |
||||
*/ |
||||
public String[] getInterfaces() { |
||||
if (cachedInterfaces != null) |
||||
return cachedInterfaces; |
||||
|
||||
String[] rtn = null; |
||||
if (interfaces == null) |
||||
rtn = new String[0]; |
||||
else { |
||||
int n = interfaces.length; |
||||
String[] list = new String[n]; |
||||
for (int i = 0; i < n; ++i) |
||||
list[i] = constPool.getClassInfo(interfaces[i]); |
||||
|
||||
rtn = list; |
||||
} |
||||
|
||||
cachedInterfaces = rtn; |
||||
return rtn; |
||||
} |
||||
|
||||
/** |
||||
* Sets the interfaces. |
||||
* |
||||
* @param nameList |
||||
* the names of the interfaces. |
||||
*/ |
||||
public void setInterfaces(String[] nameList) { |
||||
cachedInterfaces = null; |
||||
if (nameList != null) { |
||||
int n = nameList.length; |
||||
interfaces = new int[n]; |
||||
for (int i = 0; i < n; ++i) |
||||
interfaces[i] = constPool.addClassInfo(nameList[i]); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Appends an interface to the interfaces implemented by the class. |
||||
*/ |
||||
public void addInterface(String name) { |
||||
cachedInterfaces = null; |
||||
int info = constPool.addClassInfo(name); |
||||
if (interfaces == null) { |
||||
interfaces = new int[1]; |
||||
interfaces[0] = info; |
||||
} |
||||
else { |
||||
int n = interfaces.length; |
||||
int[] newarray = new int[n + 1]; |
||||
System.arraycopy(interfaces, 0, newarray, 0, n); |
||||
newarray[n] = info; |
||||
interfaces = newarray; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns all the fields declared in the class. |
||||
* |
||||
* @return a list of <code>FieldInfo</code>. |
||||
* @see FieldInfo |
||||
*/ |
||||
public List getFields() { |
||||
return fields; |
||||
} |
||||
|
||||
/** |
||||
* Appends a field to the class. |
||||
* |
||||
* @throws DuplicateMemberException when the field is already included. |
||||
*/ |
||||
public void addField(FieldInfo finfo) throws DuplicateMemberException { |
||||
testExistingField(finfo.getName(), finfo.getDescriptor()); |
||||
fields.add(finfo); |
||||
} |
||||
|
||||
/** |
||||
* Just appends a field to the class. |
||||
* It does not check field duplication. |
||||
* Use this method only when minimizing performance overheads |
||||
* is seriously required. |
||||
* |
||||
* @since 3.13 |
||||
*/ |
||||
public final void addField2(FieldInfo finfo) { |
||||
fields.add(finfo); |
||||
} |
||||
|
||||
private void testExistingField(String name, String descriptor) |
||||
throws DuplicateMemberException { |
||||
ListIterator it = fields.listIterator(0); |
||||
while (it.hasNext()) { |
||||
FieldInfo minfo = (FieldInfo)it.next(); |
||||
if (minfo.getName().equals(name)) |
||||
throw new DuplicateMemberException("duplicate field: " + name); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns all the methods declared in the class. |
||||
* |
||||
* @return a list of <code>MethodInfo</code>. |
||||
* @see MethodInfo |
||||
*/ |
||||
public List getMethods() { |
||||
return methods; |
||||
} |
||||
|
||||
/** |
||||
* Returns the method with the specified name. If there are multiple methods |
||||
* with that name, this method returns one of them. |
||||
* |
||||
* @return null if no such method is found. |
||||
*/ |
||||
public MethodInfo getMethod(String name) { |
||||
ArrayList list = methods; |
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
MethodInfo minfo = (MethodInfo)list.get(i); |
||||
if (minfo.getName().equals(name)) |
||||
return minfo; |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Returns a static initializer (class initializer), or null if it does not |
||||
* exist. |
||||
*/ |
||||
public MethodInfo getStaticInitializer() { |
||||
return getMethod(MethodInfo.nameClinit); |
||||
} |
||||
|
||||
/** |
||||
* Appends a method to the class. |
||||
* If there is a bridge method with the same name and signature, |
||||
* then the bridge method is removed before a new method is added. |
||||
* |
||||
* @throws DuplicateMemberException when the method is already included. |
||||
*/ |
||||
public void addMethod(MethodInfo minfo) throws DuplicateMemberException { |
||||
testExistingMethod(minfo); |
||||
methods.add(minfo); |
||||
} |
||||
|
||||
/** |
||||
* Just appends a method to the class. |
||||
* It does not check method duplication or remove a bridge method. |
||||
* Use this method only when minimizing performance overheads |
||||
* is seriously required. |
||||
* |
||||
* @since 3.13 |
||||
*/ |
||||
public final void addMethod2(MethodInfo minfo) { |
||||
methods.add(minfo); |
||||
} |
||||
|
||||
private void testExistingMethod(MethodInfo newMinfo) |
||||
throws DuplicateMemberException |
||||
{ |
||||
String name = newMinfo.getName(); |
||||
String descriptor = newMinfo.getDescriptor(); |
||||
ListIterator it = methods.listIterator(0); |
||||
while (it.hasNext()) |
||||
if (isDuplicated(newMinfo, name, descriptor, (MethodInfo)it.next(), it)) |
||||
throw new DuplicateMemberException("duplicate method: " + name |
||||
+ " in " + this.getName()); |
||||
} |
||||
|
||||
private static boolean isDuplicated(MethodInfo newMethod, String newName, |
||||
String newDesc, MethodInfo minfo, |
||||
ListIterator it) |
||||
{ |
||||
if (!minfo.getName().equals(newName)) |
||||
return false; |
||||
|
||||
String desc = minfo.getDescriptor(); |
||||
if (!Descriptor.eqParamTypes(desc, newDesc)) |
||||
return false; |
||||
|
||||
if (desc.equals(newDesc)) { |
||||
if (notBridgeMethod(minfo)) |
||||
return true; |
||||
else { |
||||
// if the bridge method with the same signature
|
||||
// already exists, replace it.
|
||||
it.remove(); |
||||
return false; |
||||
} |
||||
} |
||||
else |
||||
return false; |
||||
// return notBridgeMethod(minfo) && notBridgeMethod(newMethod);
|
||||
} |
||||
|
||||
/* For a bridge method, see Sec. 15.12.4.5 of JLS 3rd Ed. |
||||
*/ |
||||
private static boolean notBridgeMethod(MethodInfo minfo) { |
||||
return (minfo.getAccessFlags() & AccessFlag.BRIDGE) == 0; |
||||
} |
||||
|
||||
/** |
||||
* Returns all the attributes. The returned <code>List</code> object |
||||
* is shared with this object. If you add a new attribute to the list, |
||||
* the attribute is also added to the classs file represented by this |
||||
* object. If you remove an attribute from the list, it is also removed |
||||
* from the class file. |
||||
* |
||||
* @return a list of <code>AttributeInfo</code> objects. |
||||
* @see AttributeInfo |
||||
*/ |
||||
public List getAttributes() { |
||||
return attributes; |
||||
} |
||||
|
||||
/** |
||||
* Returns the attribute with the specified name. If there are multiple |
||||
* attributes with that name, this method returns either of them. It |
||||
* returns null if the specified attributed is not found. |
||||
* |
||||
* @param name attribute name |
||||
* @see #getAttributes() |
||||
*/ |
||||
public AttributeInfo getAttribute(String name) { |
||||
ArrayList list = attributes; |
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
AttributeInfo ai = (AttributeInfo)list.get(i); |
||||
if (ai.getName().equals(name)) |
||||
return ai; |
||||
} |
||||
|
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* 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) { |
||||
AttributeInfo.remove(attributes, info.getName()); |
||||
attributes.add(info); |
||||
} |
||||
|
||||
/** |
||||
* Returns the source file containing this class. |
||||
* |
||||
* @return null if this information is not available. |
||||
*/ |
||||
public String getSourceFile() { |
||||
SourceFileAttribute sf |
||||
= (SourceFileAttribute)getAttribute(SourceFileAttribute.tag); |
||||
if (sf == null) |
||||
return null; |
||||
else |
||||
return sf.getFileName(); |
||||
} |
||||
|
||||
private void read(DataInputStream in) throws IOException { |
||||
int i, n; |
||||
int magic = in.readInt(); |
||||
if (magic != 0xCAFEBABE) |
||||
throw new IOException("bad magic number: " + Integer.toHexString(magic)); |
||||
|
||||
minor = in.readUnsignedShort(); |
||||
major = in.readUnsignedShort(); |
||||
constPool = new ConstPool(in); |
||||
accessFlags = in.readUnsignedShort(); |
||||
thisClass = in.readUnsignedShort(); |
||||
constPool.setThisClassInfo(thisClass); |
||||
superClass = in.readUnsignedShort(); |
||||
n = in.readUnsignedShort(); |
||||
if (n == 0) |
||||
interfaces = null; |
||||
else { |
||||
interfaces = new int[n]; |
||||
for (i = 0; i < n; ++i) |
||||
interfaces[i] = in.readUnsignedShort(); |
||||
} |
||||
|
||||
ConstPool cp = constPool; |
||||
n = in.readUnsignedShort(); |
||||
fields = new ArrayList(); |
||||
for (i = 0; i < n; ++i) |
||||
addField2(new FieldInfo(cp, in)); |
||||
|
||||
n = in.readUnsignedShort(); |
||||
methods = new ArrayList(); |
||||
for (i = 0; i < n; ++i) |
||||
addMethod2(new MethodInfo(cp, in)); |
||||
|
||||
attributes = new ArrayList(); |
||||
n = in.readUnsignedShort(); |
||||
for (i = 0; i < n; ++i) |
||||
addAttribute(AttributeInfo.read(cp, in)); |
||||
|
||||
thisclassname = constPool.getClassInfo(thisClass); |
||||
} |
||||
|
||||
/** |
||||
* Writes a class file represented by this object into an output stream. |
||||
*/ |
||||
public void write(DataOutputStream out) throws IOException { |
||||
int i, n; |
||||
|
||||
out.writeInt(0xCAFEBABE); // magic
|
||||
out.writeShort(minor); // minor version
|
||||
out.writeShort(major); // major version
|
||||
constPool.write(out); // constant pool
|
||||
out.writeShort(accessFlags); |
||||
out.writeShort(thisClass); |
||||
out.writeShort(superClass); |
||||
|
||||
if (interfaces == null) |
||||
n = 0; |
||||
else |
||||
n = interfaces.length; |
||||
|
||||
out.writeShort(n); |
||||
for (i = 0; i < n; ++i) |
||||
out.writeShort(interfaces[i]); |
||||
|
||||
ArrayList list = fields; |
||||
n = list.size(); |
||||
out.writeShort(n); |
||||
for (i = 0; i < n; ++i) { |
||||
FieldInfo finfo = (FieldInfo)list.get(i); |
||||
finfo.write(out); |
||||
} |
||||
|
||||
list = methods; |
||||
n = list.size(); |
||||
out.writeShort(n); |
||||
for (i = 0; i < n; ++i) { |
||||
MethodInfo minfo = (MethodInfo)list.get(i); |
||||
minfo.write(out); |
||||
} |
||||
|
||||
out.writeShort(attributes.size()); |
||||
AttributeInfo.writeAll(attributes, out); |
||||
} |
||||
|
||||
/** |
||||
* Get the Major version. |
||||
* |
||||
* @return the major version |
||||
*/ |
||||
public int getMajorVersion() { |
||||
return major; |
||||
} |
||||
|
||||
/** |
||||
* Set the major version. |
||||
* |
||||
* @param major |
||||
* the major version |
||||
*/ |
||||
public void setMajorVersion(int major) { |
||||
this.major = major; |
||||
} |
||||
|
||||
/** |
||||
* Get the minor version. |
||||
* |
||||
* @return the minor version |
||||
*/ |
||||
public int getMinorVersion() { |
||||
return minor; |
||||
} |
||||
|
||||
/** |
||||
* Set the minor version. |
||||
* |
||||
* @param minor |
||||
* the minor version |
||||
*/ |
||||
public void setMinorVersion(int minor) { |
||||
this.minor = minor; |
||||
} |
||||
|
||||
/** |
||||
* Sets the major and minor version to Java 5. |
||||
* |
||||
* If the major version is older than 49, Java 5 |
||||
* extensions such as annotations are ignored |
||||
* by the JVM. |
||||
*/ |
||||
public void setVersionToJava5() { |
||||
this.major = 49; |
||||
this.minor = 0; |
||||
} |
||||
} |
@ -1,154 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.PrintWriter; |
||||
import com.fr.third.javassist.Modifier; |
||||
|
||||
import java.util.List; |
||||
|
||||
/** |
||||
* A utility class for priting the contents of a class file. |
||||
* It prints a constant pool table, fields, and methods in a |
||||
* human readable representation. |
||||
*/ |
||||
public class ClassFilePrinter { |
||||
/** |
||||
* Prints the contents of a class file to the standard output stream. |
||||
*/ |
||||
public static void print(com.fr.third.javassist.bytecode.ClassFile cf) { |
||||
print(cf, new PrintWriter(System.out, true)); |
||||
} |
||||
|
||||
/** |
||||
* Prints the contents of a class file. |
||||
*/ |
||||
public static void print(ClassFile cf, PrintWriter out) { |
||||
List list; |
||||
int n; |
||||
|
||||
/* 0x0020 (SYNCHRONIZED) means ACC_SUPER if the modifiers |
||||
* are of a class. |
||||
*/ |
||||
int mod |
||||
= com.fr.third.javassist.bytecode.AccessFlag.toModifier(cf.getAccessFlags() |
||||
& ~com.fr.third.javassist.bytecode.AccessFlag.SYNCHRONIZED); |
||||
out.println("major: " + cf.major + ", minor: " + cf.minor |
||||
+ " modifiers: " + Integer.toHexString(cf.getAccessFlags())); |
||||
out.println(Modifier.toString(mod) + " class " |
||||
+ cf.getName() + " extends " + cf.getSuperclass()); |
||||
|
||||
String[] infs = cf.getInterfaces(); |
||||
if (infs != null && infs.length > 0) { |
||||
out.print(" implements "); |
||||
out.print(infs[0]); |
||||
for (int i = 1; i < infs.length; ++i) |
||||
out.print(", " + infs[i]); |
||||
|
||||
out.println(); |
||||
} |
||||
|
||||
out.println(); |
||||
list = cf.getFields(); |
||||
n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
com.fr.third.javassist.bytecode.FieldInfo finfo = (FieldInfo)list.get(i); |
||||
int acc = finfo.getAccessFlags(); |
||||
out.println(Modifier.toString(com.fr.third.javassist.bytecode.AccessFlag.toModifier(acc)) |
||||
+ " " + finfo.getName() + "\t" |
||||
+ finfo.getDescriptor()); |
||||
printAttributes(finfo.getAttributes(), out, 'f'); |
||||
} |
||||
|
||||
out.println(); |
||||
list = cf.getMethods(); |
||||
n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
com.fr.third.javassist.bytecode.MethodInfo minfo = (MethodInfo)list.get(i); |
||||
int acc = minfo.getAccessFlags(); |
||||
out.println(Modifier.toString(AccessFlag.toModifier(acc)) |
||||
+ " " + minfo.getName() + "\t" |
||||
+ minfo.getDescriptor()); |
||||
printAttributes(minfo.getAttributes(), out, 'm'); |
||||
out.println(); |
||||
} |
||||
|
||||
out.println(); |
||||
printAttributes(cf.getAttributes(), out, 'c'); |
||||
} |
||||
|
||||
static void printAttributes(List list, PrintWriter out, char kind) { |
||||
if (list == null) |
||||
return; |
||||
|
||||
int n = list.size(); |
||||
for (int i = 0; i < n; ++i) { |
||||
com.fr.third.javassist.bytecode.AttributeInfo ai = (AttributeInfo)list.get(i); |
||||
if (ai instanceof com.fr.third.javassist.bytecode.CodeAttribute) { |
||||
com.fr.third.javassist.bytecode.CodeAttribute ca = (CodeAttribute)ai; |
||||
out.println("attribute: " + ai.getName() + ": " |
||||
+ ai.getClass().getName()); |
||||
out.println("max stack " + ca.getMaxStack() |
||||
+ ", max locals " + ca.getMaxLocals() |
||||
+ ", " + ca.getExceptionTable().size() |
||||
+ " catch blocks"); |
||||
out.println("<code attribute begin>"); |
||||
printAttributes(ca.getAttributes(), out, kind); |
||||
out.println("<code attribute end>"); |
||||
} |
||||
else if (ai instanceof AnnotationsAttribute) { |
||||
out.println("annnotation: " + ai.toString()); |
||||
} |
||||
else if (ai instanceof ParameterAnnotationsAttribute) { |
||||
out.println("parameter annnotations: " + ai.toString()); |
||||
} |
||||
else if (ai instanceof com.fr.third.javassist.bytecode.StackMapTable) { |
||||
out.println("<stack map table begin>"); |
||||
com.fr.third.javassist.bytecode.StackMapTable.Printer.print((StackMapTable)ai, out); |
||||
out.println("<stack map table end>"); |
||||
} |
||||
else if (ai instanceof com.fr.third.javassist.bytecode.StackMap) { |
||||
out.println("<stack map begin>"); |
||||
((StackMap)ai).print(out); |
||||
out.println("<stack map end>"); |
||||
} |
||||
else if (ai instanceof SignatureAttribute) { |
||||
SignatureAttribute sa = (SignatureAttribute)ai; |
||||
String sig = sa.getSignature(); |
||||
out.println("signature: " + sig); |
||||
try { |
||||
String s; |
||||
if (kind == 'c') |
||||
s = SignatureAttribute.toClassSignature(sig).toString(); |
||||
else if (kind == 'm') |
||||
s = SignatureAttribute.toMethodSignature(sig).toString(); |
||||
else |
||||
s = SignatureAttribute.toFieldSignature(sig).toString(); |
||||
|
||||
out.println(" " + s); |
||||
} |
||||
catch (BadBytecode e) { |
||||
out.println(" syntax error"); |
||||
} |
||||
} |
||||
else |
||||
out.println("attribute: " + ai.getName() |
||||
+ " (" + ai.get().length + " byte): " |
||||
+ ai.getClass().getName()); |
||||
} |
||||
} |
||||
} |
@ -1,782 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.OutputStream; |
||||
import java.io.DataOutputStream; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* A quick class-file writer. This is useful when a generated |
||||
* class file is simple and the code generation should be fast. |
||||
* |
||||
* <p>Example: |
||||
* |
||||
* <blockquote><pre> |
||||
* ClassFileWriter cfw = new ClassFileWriter(ClassFile.JAVA_4, 0); |
||||
* ConstPoolWriter cpw = cfw.getConstPool(); |
||||
* |
||||
* FieldWriter fw = cfw.getFieldWriter(); |
||||
* fw.add(AccessFlag.PUBLIC, "value", "I", null); |
||||
* fw.add(AccessFlag.PUBLIC, "value2", "J", null); |
||||
* |
||||
* int thisClass = cpw.addClassInfo("sample/Test"); |
||||
* int superClass = cpw.addClassInfo("java/lang/Object"); |
||||
* |
||||
* MethodWriter mw = cfw.getMethodWriter(); |
||||
* |
||||
* mw.begin(AccessFlag.PUBLIC, MethodInfo.nameInit, "()V", null, null); |
||||
* mw.add(Opcode.ALOAD_0); |
||||
* mw.add(Opcode.INVOKESPECIAL); |
||||
* int signature = cpw.addNameAndTypeInfo(MethodInfo.nameInit, "()V"); |
||||
* mw.add16(cpw.addMethodrefInfo(superClass, signature)); |
||||
* mw.add(Opcode.RETURN); |
||||
* mw.codeEnd(1, 1); |
||||
* mw.end(null, null); |
||||
* |
||||
* mw.begin(AccessFlag.PUBLIC, "one", "()I", null, null); |
||||
* mw.add(Opcode.ICONST_1); |
||||
* mw.add(Opcode.IRETURN); |
||||
* mw.codeEnd(1, 1); |
||||
* mw.end(null, null); |
||||
* |
||||
* byte[] classfile = cfw.end(AccessFlag.PUBLIC, thisClass, superClass, |
||||
* null, null); |
||||
* </pre></blockquote> |
||||
* |
||||
* <p>The code above generates the following class: |
||||
* |
||||
* <blockquote><pre> |
||||
* package sample; |
||||
* public class Test { |
||||
* public int value; |
||||
* public long value2; |
||||
* public Test() { super(); } |
||||
* public one() { return 1; } |
||||
* } |
||||
* </pre></blockquote> |
||||
* |
||||
* @since 3.13 |
||||
*/ |
||||
public class ClassFileWriter { |
||||
private com.fr.third.javassist.bytecode.ByteStream output; |
||||
private ConstPoolWriter constPool; |
||||
private FieldWriter fields; |
||||
private MethodWriter methods; |
||||
int thisClass, superClass; |
||||
|
||||
/** |
||||
* Constructs a class file writer. |
||||
* |
||||
* @param major the major version ({@link com.fr.third.javassist.bytecode.ClassFile#JAVA_4}, {@link ClassFile#JAVA_5}, ...). |
||||
* @param minor the minor version (0 for JDK 1.3 and later). |
||||
*/ |
||||
public ClassFileWriter(int major, int minor) { |
||||
output = new com.fr.third.javassist.bytecode.ByteStream(512); |
||||
output.writeInt(0xCAFEBABE); // magic
|
||||
output.writeShort(minor); |
||||
output.writeShort(major); |
||||
constPool = new ConstPoolWriter(output); |
||||
fields = new FieldWriter(constPool); |
||||
methods = new MethodWriter(constPool); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Returns a constant pool. |
||||
*/ |
||||
public ConstPoolWriter getConstPool() { return constPool; } |
||||
|
||||
/** |
||||
* Returns a filed writer. |
||||
*/ |
||||
public FieldWriter getFieldWriter() { return fields; } |
||||
|
||||
/** |
||||
* Returns a method writer. |
||||
*/ |
||||
public MethodWriter getMethodWriter() { return methods; } |
||||
|
||||
/** |
||||
* Ends writing and returns the contents of the class file. |
||||
* |
||||
* @param accessFlags access flags. |
||||
* @param thisClass this class. an index indicating its <code>CONSTANT_Class_info</code>. |
||||
* @param superClass super class. an index indicating its <code>CONSTANT_Class_info</code>. |
||||
* @param interfaces implemented interfaces. |
||||
* index numbers indicating their <code>ClassInfo</code>. |
||||
* It may be null. |
||||
* @param aw attributes of the class file. May be null. |
||||
* |
||||
* @see com.fr.third.javassist.bytecode.AccessFlag |
||||
*/ |
||||
public byte[] end(int accessFlags, int thisClass, int superClass, |
||||
int[] interfaces, AttributeWriter aw) { |
||||
constPool.end(); |
||||
output.writeShort(accessFlags); |
||||
output.writeShort(thisClass); |
||||
output.writeShort(superClass); |
||||
if (interfaces == null) |
||||
output.writeShort(0); |
||||
else { |
||||
int n = interfaces.length; |
||||
output.writeShort(n); |
||||
for (int i = 0; i < n; i++) |
||||
output.writeShort(interfaces[i]); |
||||
} |
||||
|
||||
output.enlarge(fields.dataSize() + methods.dataSize() + 6); |
||||
try { |
||||
output.writeShort(fields.size()); |
||||
fields.write(output); |
||||
|
||||
output.writeShort(methods.size()); |
||||
methods.write(output); |
||||
} |
||||
catch (IOException e) {} |
||||
|
||||
writeAttribute(output, aw, 0); |
||||
return output.toByteArray(); |
||||
} |
||||
|
||||
/** |
||||
* Ends writing and writes the contents of the class file into the |
||||
* given output stream. |
||||
* |
||||
* @param accessFlags access flags. |
||||
* @param thisClass this class. an index indicating its <code>CONSTANT_Class_info</code>. |
||||
* @param superClass super class. an index indicating its <code>CONSTANT_Class_info</code>. |
||||
* @param interfaces implemented interfaces. |
||||
* index numbers indicating their <code>CONSTATNT_Class_info</code>. |
||||
* It may be null. |
||||
* @param aw attributes of the class file. May be null. |
||||
* |
||||
* @see com.fr.third.javassist.bytecode.AccessFlag |
||||
*/ |
||||
public void end(DataOutputStream out, |
||||
int accessFlags, int thisClass, int superClass, |
||||
int[] interfaces, AttributeWriter aw) |
||||
throws IOException |
||||
{ |
||||
constPool.end(); |
||||
output.writeTo(out); |
||||
out.writeShort(accessFlags); |
||||
out.writeShort(thisClass); |
||||
out.writeShort(superClass); |
||||
if (interfaces == null) |
||||
out.writeShort(0); |
||||
else { |
||||
int n = interfaces.length; |
||||
out.writeShort(n); |
||||
for (int i = 0; i < n; i++) |
||||
out.writeShort(interfaces[i]); |
||||
} |
||||
|
||||
out.writeShort(fields.size()); |
||||
fields.write(out); |
||||
|
||||
out.writeShort(methods.size()); |
||||
methods.write(out); |
||||
if (aw == null) |
||||
out.writeShort(0); |
||||
else { |
||||
out.writeShort(aw.size()); |
||||
aw.write(out); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* This writes attributes. |
||||
* |
||||
* <p>For example, the following object writes a synthetic attribute: |
||||
* |
||||
* <pre> |
||||
* ConstPoolWriter cpw = ...; |
||||
* final int tag = cpw.addUtf8Info("Synthetic"); |
||||
* AttributeWriter aw = new AttributeWriter() { |
||||
* public int size() { |
||||
* return 1; |
||||
* } |
||||
* public void write(DataOutputStream out) throws java.io.IOException { |
||||
* out.writeShort(tag); |
||||
* out.writeInt(0); |
||||
* } |
||||
* }; |
||||
* </pre> |
||||
*/ |
||||
public static interface AttributeWriter { |
||||
/** |
||||
* Returns the number of attributes that this writer will |
||||
* write. |
||||
*/ |
||||
public int size(); |
||||
|
||||
/** |
||||
* Writes all the contents of the attributes. The binary representation |
||||
* of the contents is an array of <code>attribute_info</code>. |
||||
*/ |
||||
public void write(DataOutputStream out) throws IOException; |
||||
} |
||||
|
||||
static void writeAttribute(com.fr.third.javassist.bytecode.ByteStream bs, AttributeWriter aw, int attrCount) { |
||||
if (aw == null) { |
||||
bs.writeShort(attrCount); |
||||
return; |
||||
} |
||||
|
||||
bs.writeShort(aw.size() + attrCount); |
||||
DataOutputStream dos = new DataOutputStream(bs); |
||||
try { |
||||
aw.write(dos); |
||||
dos.flush(); |
||||
} |
||||
catch (IOException e) {} |
||||
} |
||||
|
||||
/** |
||||
* Field. |
||||
*/ |
||||
public static final class FieldWriter { |
||||
protected com.fr.third.javassist.bytecode.ByteStream output; |
||||
protected ConstPoolWriter constPool; |
||||
private int fieldCount; |
||||
|
||||
FieldWriter(ConstPoolWriter cp) { |
||||
output = new com.fr.third.javassist.bytecode.ByteStream(128); |
||||
constPool = cp; |
||||
fieldCount = 0; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new field. |
||||
* |
||||
* @param accessFlags access flags. |
||||
* @param name the field name. |
||||
* @param descriptor the field type. |
||||
* @param aw the attributes of the field. may be null. |
||||
* @see com.fr.third.javassist.bytecode.AccessFlag |
||||
*/ |
||||
public void add(int accessFlags, String name, String descriptor, AttributeWriter aw) { |
||||
int nameIndex = constPool.addUtf8Info(name); |
||||
int descIndex = constPool.addUtf8Info(descriptor); |
||||
add(accessFlags, nameIndex, descIndex, aw); |
||||
} |
||||
|
||||
/** |
||||
* Adds a new field. |
||||
* |
||||
* @param accessFlags access flags. |
||||
* @param name the field name. an index indicating its <code>CONSTANT_Utf8_info</code>. |
||||
* @param descriptor the field type. an index indicating its <code>CONSTANT_Utf8_info</code>. |
||||
* @param aw the attributes of the field. may be null. |
||||
* @see com.fr.third.javassist.bytecode.AccessFlag |
||||
*/ |
||||
public void add(int accessFlags, int name, int descriptor, AttributeWriter aw) { |
||||
++fieldCount; |
||||
output.writeShort(accessFlags); |
||||
output.writeShort(name); |
||||
output.writeShort(descriptor); |
||||
writeAttribute(output, aw, 0); |
||||
} |
||||
|
||||
int size() { return fieldCount; } |
||||
|
||||
int dataSize() { return output.size(); } |
||||
|
||||
/** |
||||
* Writes the added fields. |
||||
*/ |
||||
void write(OutputStream out) throws IOException { |
||||
output.writeTo(out); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Method. |
||||
*/ |
||||
public static final class MethodWriter { |
||||
protected com.fr.third.javassist.bytecode.ByteStream output; |
||||
protected ConstPoolWriter constPool; |
||||
private int methodCount; |
||||
protected int codeIndex; |
||||
protected int throwsIndex; |
||||
protected int stackIndex; |
||||
|
||||
private int startPos; |
||||
private boolean isAbstract; |
||||
private int catchPos; |
||||
private int catchCount; |
||||
|
||||
MethodWriter(ConstPoolWriter cp) { |
||||
output = new com.fr.third.javassist.bytecode.ByteStream(256); |
||||
constPool = cp; |
||||
methodCount = 0; |
||||
codeIndex = 0; |
||||
throwsIndex = 0; |
||||
stackIndex = 0; |
||||
} |
||||
|
||||
/** |
||||
* Starts Adding a new method. |
||||
* |
||||
* @param accessFlags access flags. |
||||
* @param name the method name. |
||||
* @param descriptor the method signature. |
||||
* @param exceptions throws clause. It may be null. |
||||
* The class names must be the JVM-internal |
||||
* representations like <code>java/lang/Exception</code>. |
||||
* @param aw attributes to the <code>Method_info</code>. |
||||
*/ |
||||
public void begin(int accessFlags, String name, String descriptor, |
||||
String[] exceptions, AttributeWriter aw) { |
||||
int nameIndex = constPool.addUtf8Info(name); |
||||
int descIndex = constPool.addUtf8Info(descriptor); |
||||
int[] intfs; |
||||
if (exceptions == null) |
||||
intfs = null; |
||||
else |
||||
intfs = constPool.addClassInfo(exceptions); |
||||
|
||||
begin(accessFlags, nameIndex, descIndex, intfs, aw); |
||||
} |
||||
|
||||
/** |
||||
* Starts adding a new method. |
||||
* |
||||
* @param accessFlags access flags. |
||||
* @param name the method name. an index indicating its <code>CONSTANT_Utf8_info</code>. |
||||
* @param descriptor the field type. an index indicating its <code>CONSTANT_Utf8_info</code>. |
||||
* @param exceptions throws clause. indexes indicating <code>CONSTANT_Class_info</code>s. |
||||
* It may be null. |
||||
* @param aw attributes to the <code>Method_info</code>. |
||||
*/ |
||||
public void begin(int accessFlags, int name, int descriptor, int[] exceptions, AttributeWriter aw) { |
||||
++methodCount; |
||||
output.writeShort(accessFlags); |
||||
output.writeShort(name); |
||||
output.writeShort(descriptor); |
||||
isAbstract = (accessFlags & AccessFlag.ABSTRACT) != 0; |
||||
|
||||
int attrCount = isAbstract ? 0 : 1; |
||||
if (exceptions != null) |
||||
++attrCount; |
||||
|
||||
writeAttribute(output, aw, attrCount); |
||||
|
||||
if (exceptions != null) |
||||
writeThrows(exceptions); |
||||
|
||||
if (!isAbstract) { |
||||
if (codeIndex == 0) |
||||
codeIndex = constPool.addUtf8Info(CodeAttribute.tag); |
||||
|
||||
startPos = output.getPos(); |
||||
output.writeShort(codeIndex); |
||||
output.writeBlank(12); // attribute_length, maxStack, maxLocals, code_lenth
|
||||
} |
||||
|
||||
catchPos = -1; |
||||
catchCount = 0; |
||||
} |
||||
|
||||
private void writeThrows(int[] exceptions) { |
||||
if (throwsIndex == 0) |
||||
throwsIndex = constPool.addUtf8Info(ExceptionsAttribute.tag); |
||||
|
||||
output.writeShort(throwsIndex); |
||||
output.writeInt(exceptions.length * 2 + 2); |
||||
output.writeShort(exceptions.length); |
||||
for (int i = 0; i < exceptions.length; i++) |
||||
output.writeShort(exceptions[i]); |
||||
} |
||||
|
||||
/** |
||||
* Appends an 8bit value of bytecode. |
||||
* |
||||
* @see com.fr.third.javassist.bytecode.Opcode |
||||
*/ |
||||
public void add(int b) { |
||||
output.write(b); |
||||
} |
||||
|
||||
/** |
||||
* Appends a 16bit value of bytecode. |
||||
*/ |
||||
public void add16(int b) { |
||||
output.writeShort(b); |
||||
} |
||||
|
||||
/** |
||||
* Appends a 32bit value of bytecode. |
||||
*/ |
||||
public void add32(int b) { |
||||
output.writeInt(b); |
||||
} |
||||
|
||||
/** |
||||
* Appends a invokevirtual, inovkespecial, or invokestatic bytecode. |
||||
* |
||||
* @see Opcode |
||||
*/ |
||||
public void addInvoke(int opcode, String targetClass, String methodName, |
||||
String descriptor) { |
||||
int target = constPool.addClassInfo(targetClass); |
||||
int nt = constPool.addNameAndTypeInfo(methodName, descriptor); |
||||
int method = constPool.addMethodrefInfo(target, nt); |
||||
add(opcode); |
||||
add16(method); |
||||
} |
||||
|
||||
/** |
||||
* Ends appending bytecode. |
||||
*/ |
||||
public void codeEnd(int maxStack, int maxLocals) { |
||||
if (!isAbstract) { |
||||
output.writeShort(startPos + 6, maxStack); |
||||
output.writeShort(startPos + 8, maxLocals); |
||||
output.writeInt(startPos + 10, output.getPos() - startPos - 14); // code_length
|
||||
catchPos = output.getPos(); |
||||
catchCount = 0; |
||||
output.writeShort(0); // number of catch clauses
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Appends an <code>exception_table</code> entry to the |
||||
* <code>Code_attribute</code>. This method is available |
||||
* only after the <code>codeEnd</code> method is called. |
||||
* |
||||
* @param catchType an index indicating a <code>CONSTANT_Class_info</code>. |
||||
*/ |
||||
public void addCatch(int startPc, int endPc, int handlerPc, int catchType) { |
||||
++catchCount; |
||||
output.writeShort(startPc); |
||||
output.writeShort(endPc); |
||||
output.writeShort(handlerPc); |
||||
output.writeShort(catchType); |
||||
} |
||||
|
||||
/** |
||||
* Ends adding a new method. The <code>add</code> method must be |
||||
* called before the <code>end</code> method is called. |
||||
* |
||||
* @param smap a stack map table. may be null. |
||||
* @param aw attributes to the <code>Code_attribute</code>. |
||||
* may be null. |
||||
*/ |
||||
public void end(com.fr.third.javassist.bytecode.StackMapTable.Writer smap, AttributeWriter aw) { |
||||
if (isAbstract) |
||||
return; |
||||
|
||||
// exception_table_length
|
||||
output.writeShort(catchPos, catchCount); |
||||
|
||||
int attrCount = smap == null ? 0 : 1; |
||||
writeAttribute(output, aw, attrCount); |
||||
|
||||
if (smap != null) { |
||||
if (stackIndex == 0) |
||||
stackIndex = constPool.addUtf8Info(StackMapTable.tag); |
||||
|
||||
output.writeShort(stackIndex); |
||||
byte[] data = smap.toByteArray(); |
||||
output.writeInt(data.length); |
||||
output.write(data); |
||||
} |
||||
|
||||
// Code attribute_length
|
||||
output.writeInt(startPos + 2, output.getPos() - startPos - 6); |
||||
} |
||||
|
||||
int size() { return methodCount; } |
||||
|
||||
int dataSize() { return output.size(); } |
||||
|
||||
/** |
||||
* Writes the added methods. |
||||
*/ |
||||
void write(OutputStream out) throws IOException { |
||||
output.writeTo(out); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Constant Pool. |
||||
*/ |
||||
public static final class ConstPoolWriter { |
||||
com.fr.third.javassist.bytecode.ByteStream output; |
||||
protected int startPos; |
||||
protected int num; |
||||
|
||||
ConstPoolWriter(com.fr.third.javassist.bytecode.ByteStream out) { |
||||
output = out; |
||||
startPos = out.getPos(); |
||||
num = 1; |
||||
output.writeShort(1); // number of entries
|
||||
} |
||||
|
||||
/** |
||||
* Makes <code>CONSTANT_Class_info</code> objects for each class name. |
||||
* |
||||
* @return an array of indexes indicating <code>CONSTANT_Class_info</code>s. |
||||
*/ |
||||
public int[] addClassInfo(String[] classNames) { |
||||
int n = classNames.length; |
||||
int[] result = new int[n]; |
||||
for (int i = 0; i < n; i++) |
||||
result[i] = addClassInfo(classNames[i]); |
||||
|
||||
return result; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_Class_info</code> structure. |
||||
* |
||||
* <p>This also adds a <code>CONSTANT_Utf8_info</code> structure |
||||
* for storing the class name. |
||||
* |
||||
* @param jvmname the JVM-internal representation of a class name. |
||||
* e.g. <code>java/lang/Object</code>. |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addClassInfo(String jvmname) { |
||||
int utf8 = addUtf8Info(jvmname); |
||||
output.write(com.fr.third.javassist.bytecode.ClassInfo.tag); |
||||
output.writeShort(utf8); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_Class_info</code> structure. |
||||
* |
||||
* @param name <code>name_index</code> |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addClassInfo(int name) { |
||||
output.write(com.fr.third.javassist.bytecode.ClassInfo.tag); |
||||
output.writeShort(name); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_NameAndType_info</code> structure. |
||||
* |
||||
* @param name <code>name_index</code> |
||||
* @param type <code>descriptor_index</code> |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addNameAndTypeInfo(String name, String type) { |
||||
return addNameAndTypeInfo(addUtf8Info(name), addUtf8Info(type)); |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_NameAndType_info</code> structure. |
||||
* |
||||
* @param name <code>name_index</code> |
||||
* @param type <code>descriptor_index</code> |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addNameAndTypeInfo(int name, int type) { |
||||
output.write(com.fr.third.javassist.bytecode.NameAndTypeInfo.tag); |
||||
output.writeShort(name); |
||||
output.writeShort(type); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_Fieldref_info</code> structure. |
||||
* |
||||
* @param classInfo <code>class_index</code> |
||||
* @param nameAndTypeInfo <code>name_and_type_index</code>. |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addFieldrefInfo(int classInfo, int nameAndTypeInfo) { |
||||
output.write(com.fr.third.javassist.bytecode.FieldrefInfo.tag); |
||||
output.writeShort(classInfo); |
||||
output.writeShort(nameAndTypeInfo); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_Methodref_info</code> structure. |
||||
* |
||||
* @param classInfo <code>class_index</code> |
||||
* @param nameAndTypeInfo <code>name_and_type_index</code>. |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addMethodrefInfo(int classInfo, int nameAndTypeInfo) { |
||||
output.write(com.fr.third.javassist.bytecode.MethodrefInfo.tag); |
||||
output.writeShort(classInfo); |
||||
output.writeShort(nameAndTypeInfo); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_InterfaceMethodref_info</code> |
||||
* structure. |
||||
* |
||||
* @param classInfo <code>class_index</code> |
||||
* @param nameAndTypeInfo <code>name_and_type_index</code>. |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addInterfaceMethodrefInfo(int classInfo, |
||||
int nameAndTypeInfo) { |
||||
output.write(com.fr.third.javassist.bytecode.InterfaceMethodrefInfo.tag); |
||||
output.writeShort(classInfo); |
||||
output.writeShort(nameAndTypeInfo); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_MethodHandle_info</code> |
||||
* structure. |
||||
* |
||||
* @param kind <code>reference_kind</code> |
||||
* such as {@link ConstPool#REF_invokeStatic <code>REF_invokeStatic</code>}. |
||||
* @param index <code>reference_index</code>. |
||||
* @return the index of the added entry. |
||||
* |
||||
* @since 3.17.1 |
||||
*/ |
||||
public int addMethodHandleInfo(int kind, int index) { |
||||
output.write(com.fr.third.javassist.bytecode.MethodHandleInfo.tag); |
||||
output.write(kind); |
||||
output.writeShort(index); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_MethodType_info</code> |
||||
* structure. |
||||
* |
||||
* @param desc <code>descriptor_index</code>. |
||||
* @return the index of the added entry. |
||||
* |
||||
* @since 3.17.1 |
||||
*/ |
||||
public int addMethodTypeInfo(int desc) { |
||||
output.write(com.fr.third.javassist.bytecode.MethodTypeInfo.tag); |
||||
output.writeShort(desc); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_InvokeDynamic_info</code> |
||||
* structure. |
||||
* |
||||
* @param bootstrap <code>bootstrap_method_attr_index</code>. |
||||
* @param nameAndTypeInfo <code>name_and_type_index</code>. |
||||
* @return the index of the added entry. |
||||
* |
||||
* @since 3.17.1 |
||||
*/ |
||||
public int addInvokeDynamicInfo(int bootstrap, |
||||
int nameAndTypeInfo) { |
||||
output.write(com.fr.third.javassist.bytecode.InvokeDynamicInfo.tag); |
||||
output.writeShort(bootstrap); |
||||
output.writeShort(nameAndTypeInfo); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_String_info</code> |
||||
* structure. |
||||
* |
||||
* <p>This also adds a new <code>CONSTANT_Utf8_info</code> |
||||
* structure. |
||||
* |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addStringInfo(String str) { |
||||
int utf8 = addUtf8Info(str); |
||||
output.write(com.fr.third.javassist.bytecode.StringInfo.tag); |
||||
output.writeShort(utf8); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_Integer_info</code> |
||||
* structure. |
||||
* |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addIntegerInfo(int i) { |
||||
output.write(com.fr.third.javassist.bytecode.IntegerInfo.tag); |
||||
output.writeInt(i); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_Float_info</code> |
||||
* structure. |
||||
* |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addFloatInfo(float f) { |
||||
output.write(com.fr.third.javassist.bytecode.FloatInfo.tag); |
||||
output.writeFloat(f); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_Long_info</code> |
||||
* structure. |
||||
* |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addLongInfo(long l) { |
||||
output.write(com.fr.third.javassist.bytecode.LongInfo.tag); |
||||
output.writeLong(l); |
||||
int n = num; |
||||
num += 2; |
||||
return n; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_Double_info</code> |
||||
* structure. |
||||
* |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addDoubleInfo(double d) { |
||||
output.write(com.fr.third.javassist.bytecode.DoubleInfo.tag); |
||||
output.writeDouble(d); |
||||
int n = num; |
||||
num += 2; |
||||
return n; |
||||
} |
||||
|
||||
/** |
||||
* Adds a new <code>CONSTANT_Utf8_info</code> |
||||
* structure. |
||||
* |
||||
* @return the index of the added entry. |
||||
*/ |
||||
public int addUtf8Info(String utf8) { |
||||
output.write(com.fr.third.javassist.bytecode.Utf8Info.tag); |
||||
output.writeUTF(utf8); |
||||
return num++; |
||||
} |
||||
|
||||
/** |
||||
* Writes the contents of this class pool. |
||||
*/ |
||||
void end() { |
||||
output.writeShort(startPos, num); |
||||
} |
||||
} |
||||
} |
@ -1,267 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
/** |
||||
* Utility for computing <code>max_stack</code>. |
||||
*/ |
||||
class CodeAnalyzer implements Opcode { |
||||
private ConstPool constPool; |
||||
private CodeAttribute codeAttr; |
||||
|
||||
public CodeAnalyzer(CodeAttribute ca) { |
||||
codeAttr = ca; |
||||
constPool = ca.getConstPool(); |
||||
} |
||||
|
||||
public int computeMaxStack() |
||||
throws com.fr.third.javassist.bytecode.BadBytecode |
||||
{ |
||||
/* d = stack[i] |
||||
* d == 0: not visited |
||||
* d > 0: the depth is d - 1 after executing the bytecode at i. |
||||
* d < 0: not visited. the initial depth (before execution) is 1 - d. |
||||
*/ |
||||
CodeIterator ci = codeAttr.iterator(); |
||||
int length = ci.getCodeLength(); |
||||
int[] stack = new int[length]; |
||||
constPool = codeAttr.getConstPool(); |
||||
initStack(stack, codeAttr); |
||||
boolean repeat; |
||||
do { |
||||
repeat = false; |
||||
for (int i = 0; i < length; ++i) |
||||
if (stack[i] < 0) { |
||||
repeat = true; |
||||
visitBytecode(ci, stack, i); |
||||
} |
||||
} while (repeat); |
||||
|
||||
int maxStack = 1; |
||||
for (int i = 0; i < length; ++i) |
||||
if (stack[i] > maxStack) |
||||
maxStack = stack[i]; |
||||
|
||||
return maxStack - 1; // the base is 1.
|
||||
} |
||||
|
||||
private void initStack(int[] stack, CodeAttribute ca) { |
||||
stack[0] = -1; |
||||
ExceptionTable et = ca.getExceptionTable(); |
||||
if (et != null) { |
||||
int size = et.size(); |
||||
for (int i = 0; i < size; ++i) |
||||
stack[et.handlerPc(i)] = -2; // an exception is on stack
|
||||
} |
||||
} |
||||
|
||||
private void visitBytecode(CodeIterator ci, int[] stack, int index) |
||||
throws com.fr.third.javassist.bytecode.BadBytecode |
||||
{ |
||||
int codeLength = stack.length; |
||||
ci.move(index); |
||||
int stackDepth = -stack[index]; |
||||
int[] jsrDepth = new int[1]; |
||||
jsrDepth[0] = -1; |
||||
while (ci.hasNext()) { |
||||
index = ci.next(); |
||||
stack[index] = stackDepth; |
||||
int op = ci.byteAt(index); |
||||
stackDepth = visitInst(op, ci, index, stackDepth); |
||||
if (stackDepth < 1) |
||||
throw new com.fr.third.javassist.bytecode.BadBytecode("stack underflow at " + index); |
||||
|
||||
if (processBranch(op, ci, index, codeLength, stack, stackDepth, jsrDepth)) |
||||
break; |
||||
|
||||
if (isEnd(op)) // return, ireturn, athrow, ...
|
||||
break; |
||||
|
||||
if (op == JSR || op == JSR_W) |
||||
--stackDepth; |
||||
} |
||||
} |
||||
|
||||
private boolean processBranch(int opcode, CodeIterator ci, int index, |
||||
int codeLength, int[] stack, int stackDepth, int[] jsrDepth) |
||||
throws com.fr.third.javassist.bytecode.BadBytecode |
||||
{ |
||||
if ((IFEQ <= opcode && opcode <= IF_ACMPNE) |
||||
|| opcode == IFNULL || opcode == IFNONNULL) { |
||||
int target = index + ci.s16bitAt(index + 1); |
||||
checkTarget(index, target, codeLength, stack, stackDepth); |
||||
} |
||||
else { |
||||
int target, index2; |
||||
switch (opcode) { |
||||
case GOTO : |
||||
target = index + ci.s16bitAt(index + 1); |
||||
checkTarget(index, target, codeLength, stack, stackDepth); |
||||
return true; |
||||
case GOTO_W : |
||||
target = index + ci.s32bitAt(index + 1); |
||||
checkTarget(index, target, codeLength, stack, stackDepth); |
||||
return true; |
||||
case JSR : |
||||
case JSR_W : |
||||
if (opcode == JSR) |
||||
target = index + ci.s16bitAt(index + 1); |
||||
else |
||||
target = index + ci.s32bitAt(index + 1); |
||||
|
||||
checkTarget(index, target, codeLength, stack, stackDepth); |
||||
/* |
||||
* It is unknown which RET comes back to this JSR. |
||||
* So we assume that if the stack depth at one JSR instruction |
||||
* is N, then it is also N at other JSRs and N - 1 at all RET |
||||
* instructions. Note that STACK_GROW[JSR] is 1 since it pushes |
||||
* a return address on the operand stack. |
||||
*/ |
||||
if (jsrDepth[0] < 0) { |
||||
jsrDepth[0] = stackDepth; |
||||
return false; |
||||
} |
||||
else if (stackDepth == jsrDepth[0]) |
||||
return false; |
||||
else |
||||
throw new com.fr.third.javassist.bytecode.BadBytecode( |
||||
"sorry, cannot compute this data flow due to JSR: " |
||||
+ stackDepth + "," + jsrDepth[0]); |
||||
case RET : |
||||
if (jsrDepth[0] < 0) { |
||||
jsrDepth[0] = stackDepth + 1; |
||||
return false; |
||||
} |
||||
else if (stackDepth + 1 == jsrDepth[0]) |
||||
return true; |
||||
else |
||||
throw new com.fr.third.javassist.bytecode.BadBytecode( |
||||
"sorry, cannot compute this data flow due to RET: " |
||||
+ stackDepth + "," + jsrDepth[0]); |
||||
case LOOKUPSWITCH : |
||||
case TABLESWITCH : |
||||
index2 = (index & ~3) + 4; |
||||
target = index + ci.s32bitAt(index2); |
||||
checkTarget(index, target, codeLength, stack, stackDepth); |
||||
if (opcode == LOOKUPSWITCH) { |
||||
int npairs = ci.s32bitAt(index2 + 4); |
||||
index2 += 12; |
||||
for (int i = 0; i < npairs; ++i) { |
||||
target = index + ci.s32bitAt(index2); |
||||
checkTarget(index, target, codeLength, |
||||
stack, stackDepth); |
||||
index2 += 8; |
||||
} |
||||
} |
||||
else { |
||||
int low = ci.s32bitAt(index2 + 4); |
||||
int high = ci.s32bitAt(index2 + 8); |
||||
int n = high - low + 1; |
||||
index2 += 12; |
||||
for (int i = 0; i < n; ++i) { |
||||
target = index + ci.s32bitAt(index2); |
||||
checkTarget(index, target, codeLength, |
||||
stack, stackDepth); |
||||
index2 += 4; |
||||
} |
||||
} |
||||
|
||||
return true; // always branch.
|
||||
} |
||||
} |
||||
|
||||
return false; // may not branch.
|
||||
} |
||||
|
||||
private void checkTarget(int opIndex, int target, int codeLength, |
||||
int[] stack, int stackDepth) |
||||
throws com.fr.third.javassist.bytecode.BadBytecode |
||||
{ |
||||
if (target < 0 || codeLength <= target) |
||||
throw new com.fr.third.javassist.bytecode.BadBytecode("bad branch offset at " + opIndex); |
||||
|
||||
int d = stack[target]; |
||||
if (d == 0) |
||||
stack[target] = -stackDepth; |
||||
else if (d != stackDepth && d != -stackDepth) |
||||
throw new com.fr.third.javassist.bytecode.BadBytecode("verification error (" + stackDepth + |
||||
"," + d + ") at " + opIndex); |
||||
} |
||||
|
||||
private static boolean isEnd(int opcode) { |
||||
return (IRETURN <= opcode && opcode <= RETURN) || opcode == ATHROW; |
||||
} |
||||
|
||||
/** |
||||
* Visits an instruction. |
||||
*/ |
||||
private int visitInst(int op, CodeIterator ci, int index, int stack) |
||||
throws BadBytecode |
||||
{ |
||||
String desc; |
||||
switch (op) { |
||||
case GETFIELD : |
||||
stack += getFieldSize(ci, index) - 1; |
||||
break; |
||||
case PUTFIELD : |
||||
stack -= getFieldSize(ci, index) + 1; |
||||
break; |
||||
case GETSTATIC : |
||||
stack += getFieldSize(ci, index); |
||||
break; |
||||
case PUTSTATIC : |
||||
stack -= getFieldSize(ci, index); |
||||
break; |
||||
case INVOKEVIRTUAL : |
||||
case INVOKESPECIAL : |
||||
desc = constPool.getMethodrefType(ci.u16bitAt(index + 1)); |
||||
stack += com.fr.third.javassist.bytecode.Descriptor.dataSize(desc) - 1; |
||||
break; |
||||
case INVOKESTATIC : |
||||
desc = constPool.getMethodrefType(ci.u16bitAt(index + 1)); |
||||
stack += com.fr.third.javassist.bytecode.Descriptor.dataSize(desc); |
||||
break; |
||||
case INVOKEINTERFACE : |
||||
desc = constPool.getInterfaceMethodrefType( |
||||
ci.u16bitAt(index + 1)); |
||||
stack += com.fr.third.javassist.bytecode.Descriptor.dataSize(desc) - 1; |
||||
break; |
||||
case INVOKEDYNAMIC : |
||||
desc = constPool.getInvokeDynamicType(ci.u16bitAt(index + 1)); |
||||
stack += com.fr.third.javassist.bytecode.Descriptor.dataSize(desc); // assume CosntPool#REF_invokeStatic
|
||||
break; |
||||
case ATHROW : |
||||
stack = 1; // the stack becomes empty (1 means no values).
|
||||
break; |
||||
case MULTIANEWARRAY : |
||||
stack += 1 - ci.byteAt(index + 3); |
||||
break; |
||||
case WIDE : |
||||
op = ci.byteAt(index + 1); |
||||
// don't break here.
|
||||
default : |
||||
stack += STACK_GROW[op]; |
||||
} |
||||
|
||||
return stack; |
||||
} |
||||
|
||||
private int getFieldSize(CodeIterator ci, int index) { |
||||
String desc = constPool.getFieldrefType(ci.u16bitAt(index + 1)); |
||||
return Descriptor.dataSize(desc); |
||||
} |
||||
} |
@ -1,594 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.DataOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
import java.util.ArrayList; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <code>Code_attribute</code>. |
||||
* |
||||
* <p>To browse the <code>code</code> field of |
||||
* a <code>Code_attribute</code> structure, |
||||
* use <code>CodeIterator</code>. |
||||
* |
||||
* @see com.fr.third.javassist.bytecode.CodeIterator |
||||
* @see #iterator() |
||||
*/ |
||||
public class CodeAttribute extends com.fr.third.javassist.bytecode.AttributeInfo implements Opcode { |
||||
/** |
||||
* The name of this attribute <code>"Code"</code>. |
||||
*/ |
||||
public static final String tag = "Code"; |
||||
|
||||
// code[] is stored in AttributeInfo.info.
|
||||
|
||||
private int maxStack; |
||||
private int maxLocals; |
||||
private ExceptionTable exceptions; |
||||
private ArrayList attributes; |
||||
|
||||
/** |
||||
* Constructs a <code>Code_attribute</code>. |
||||
* |
||||
* @param cp constant pool table |
||||
* @param stack <code>max_stack</code> |
||||
* @param locals <code>max_locals</code> |
||||
* @param code <code>code[]</code> |
||||
* @param etable <code>exception_table[]</code> |
||||
*/ |
||||
public CodeAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int stack, int locals, byte[] code, |
||||
ExceptionTable etable) |
||||
{ |
||||
super(cp, tag); |
||||
maxStack = stack; |
||||
maxLocals = locals; |
||||
info = code; |
||||
exceptions = etable; |
||||
attributes = new ArrayList(); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a copy of <code>Code_attribute</code>. |
||||
* Specified class names are replaced during the copy. |
||||
* |
||||
* @param cp constant pool table. |
||||
* @param src source Code attribute. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
*/ |
||||
private CodeAttribute(com.fr.third.javassist.bytecode.ConstPool cp, CodeAttribute src, Map classnames) |
||||
throws com.fr.third.javassist.bytecode.BadBytecode |
||||
{ |
||||
super(cp, tag); |
||||
|
||||
maxStack = src.getMaxStack(); |
||||
maxLocals = src.getMaxLocals(); |
||||
exceptions = src.getExceptionTable().copy(cp, classnames); |
||||
attributes = new ArrayList(); |
||||
List src_attr = src.getAttributes(); |
||||
int num = src_attr.size(); |
||||
for (int i = 0; i < num; ++i) { |
||||
com.fr.third.javassist.bytecode.AttributeInfo ai = (com.fr.third.javassist.bytecode.AttributeInfo)src_attr.get(i); |
||||
attributes.add(ai.copy(cp, classnames)); |
||||
} |
||||
|
||||
info = src.copyCode(cp, classnames, exceptions, this); |
||||
} |
||||
|
||||
CodeAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int name_id, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, name_id, (byte[])null); |
||||
int attr_len = in.readInt(); |
||||
|
||||
maxStack = in.readUnsignedShort(); |
||||
maxLocals = in.readUnsignedShort(); |
||||
|
||||
int code_len = in.readInt(); |
||||
info = new byte[code_len]; |
||||
in.readFully(info); |
||||
|
||||
exceptions = new ExceptionTable(cp, in); |
||||
|
||||
attributes = new ArrayList(); |
||||
int num = in.readUnsignedShort(); |
||||
for (int i = 0; i < num; ++i) |
||||
attributes.add(com.fr.third.javassist.bytecode.AttributeInfo.read(cp, in)); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. Class names are replaced according to the |
||||
* given <code>Map</code> object. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
* @exception RuntimeCopyException if a <code>BadBytecode</code> |
||||
* exception is thrown, it is |
||||
* converted into |
||||
* <code>RuntimeCopyException</code>. |
||||
* |
||||
* @return <code>CodeAttribute</code> object. |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.AttributeInfo copy(com.fr.third.javassist.bytecode.ConstPool newCp, Map classnames) |
||||
throws RuntimeCopyException |
||||
{ |
||||
try { |
||||
return new CodeAttribute(newCp, this, classnames); |
||||
} |
||||
catch (com.fr.third.javassist.bytecode.BadBytecode e) { |
||||
throw new RuntimeCopyException("bad bytecode. fatal?"); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* An exception that may be thrown by <code>copy()</code> |
||||
* in <code>CodeAttribute</code>. |
||||
*/ |
||||
public static class RuntimeCopyException extends RuntimeException { |
||||
/** |
||||
* Constructs an exception. |
||||
*/ |
||||
public RuntimeCopyException(String s) { |
||||
super(s); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the length of this <code>attribute_info</code> |
||||
* structure. |
||||
* The returned value is <code>attribute_length + 6</code>. |
||||
*/ |
||||
public int length() { |
||||
return 18 + info.length + exceptions.size() * 8 |
||||
+ com.fr.third.javassist.bytecode.AttributeInfo.getLength(attributes); |
||||
} |
||||
|
||||
void write(DataOutputStream out) throws IOException { |
||||
out.writeShort(name); // attribute_name_index
|
||||
out.writeInt(length() - 6); // attribute_length
|
||||
out.writeShort(maxStack); // max_stack
|
||||
out.writeShort(maxLocals); // max_locals
|
||||
out.writeInt(info.length); // code_length
|
||||
out.write(info); // code
|
||||
exceptions.write(out); |
||||
out.writeShort(attributes.size()); // attributes_count
|
||||
com.fr.third.javassist.bytecode.AttributeInfo.writeAll(attributes, out); // attributes
|
||||
} |
||||
|
||||
/** |
||||
* This method is not available. |
||||
* |
||||
* @throws java.lang.UnsupportedOperationException always thrown. |
||||
*/ |
||||
public byte[] get() { |
||||
throw new UnsupportedOperationException("CodeAttribute.get()"); |
||||
} |
||||
|
||||
/** |
||||
* This method is not available. |
||||
* |
||||
* @throws java.lang.UnsupportedOperationException always thrown. |
||||
*/ |
||||
public void set(byte[] newinfo) { |
||||
throw new UnsupportedOperationException("CodeAttribute.set()"); |
||||
} |
||||
|
||||
void renameClass(String oldname, String newname) { |
||||
com.fr.third.javassist.bytecode.AttributeInfo.renameClass(attributes, oldname, newname); |
||||
} |
||||
|
||||
void renameClass(Map classnames) { |
||||
com.fr.third.javassist.bytecode.AttributeInfo.renameClass(attributes, classnames); |
||||
} |
||||
|
||||
void getRefClasses(Map classnames) { |
||||
com.fr.third.javassist.bytecode.AttributeInfo.getRefClasses(attributes, classnames); |
||||
} |
||||
|
||||
/** |
||||
* Returns the name of the class declaring the method including |
||||
* this code attribute. |
||||
*/ |
||||
public String getDeclaringClass() { |
||||
com.fr.third.javassist.bytecode.ConstPool cp = getConstPool(); |
||||
return cp.getClassName(); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>max_stack</code>. |
||||
*/ |
||||
public int getMaxStack() { |
||||
return maxStack; |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>max_stack</code>. |
||||
*/ |
||||
public void setMaxStack(int value) { |
||||
maxStack = value; |
||||
} |
||||
|
||||
/** |
||||
* Computes the maximum stack size and sets <code>max_stack</code> |
||||
* to the computed size. |
||||
* |
||||
* @throws com.fr.third.javassist.bytecode.BadBytecode if this method fails in computing. |
||||
* @return the newly computed value of <code>max_stack</code> |
||||
*/ |
||||
public int computeMaxStack() throws com.fr.third.javassist.bytecode.BadBytecode { |
||||
maxStack = new com.fr.third.javassist.bytecode.CodeAnalyzer(this).computeMaxStack(); |
||||
return maxStack; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>max_locals</code>. |
||||
*/ |
||||
public int getMaxLocals() { |
||||
return maxLocals; |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>max_locals</code>. |
||||
*/ |
||||
public void setMaxLocals(int value) { |
||||
maxLocals = value; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>code_length</code>. |
||||
*/ |
||||
public int getCodeLength() { |
||||
return info.length; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>code[]</code>. |
||||
*/ |
||||
public byte[] getCode() { |
||||
return info; |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>code[]</code>. |
||||
*/ |
||||
void setCode(byte[] newinfo) { super.set(newinfo); } |
||||
|
||||
/** |
||||
* Makes a new iterator for reading this code attribute. |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.CodeIterator iterator() { |
||||
return new com.fr.third.javassist.bytecode.CodeIterator(this); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>exception_table[]</code>. |
||||
*/ |
||||
public ExceptionTable getExceptionTable() { return exceptions; } |
||||
|
||||
/** |
||||
* Returns <code>attributes[]</code>. |
||||
* It returns a list of <code>AttributeInfo</code>. |
||||
* A new element can be added to the returned list |
||||
* and an existing element can be removed from the list. |
||||
* |
||||
* @see com.fr.third.javassist.bytecode.AttributeInfo |
||||
*/ |
||||
public List getAttributes() { return attributes; } |
||||
|
||||
/** |
||||
* Returns the attribute with the specified name. |
||||
* If it is not found, this method returns null. |
||||
* |
||||
* @param name attribute name |
||||
* @return an <code>AttributeInfo</code> object or null. |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.AttributeInfo getAttribute(String name) { |
||||
return com.fr.third.javassist.bytecode.AttributeInfo.lookup(attributes, name); |
||||
} |
||||
|
||||
/** |
||||
* Adds a stack map table. If another copy of stack map table |
||||
* is already contained, the old one is removed. |
||||
* |
||||
* @param smt the stack map table added to this code attribute. |
||||
* If it is null, a new stack map is not added. |
||||
* Only the old stack map is removed. |
||||
*/ |
||||
public void setAttribute(StackMapTable smt) { |
||||
com.fr.third.javassist.bytecode.AttributeInfo.remove(attributes, StackMapTable.tag); |
||||
if (smt != null) |
||||
attributes.add(smt); |
||||
} |
||||
|
||||
/** |
||||
* Adds a stack map table for J2ME (CLDC). If another copy of stack map table |
||||
* is already contained, the old one is removed. |
||||
* |
||||
* @param sm the stack map table added to this code attribute. |
||||
* If it is null, a new stack map is not added. |
||||
* Only the old stack map is removed. |
||||
* @since 3.12 |
||||
*/ |
||||
public void setAttribute(com.fr.third.javassist.bytecode.StackMap sm) { |
||||
AttributeInfo.remove(attributes, com.fr.third.javassist.bytecode.StackMap.tag); |
||||
if (sm != null) |
||||
attributes.add(sm); |
||||
} |
||||
|
||||
/** |
||||
* Copies code. |
||||
*/ |
||||
private byte[] copyCode(com.fr.third.javassist.bytecode.ConstPool destCp, Map classnames, |
||||
ExceptionTable etable, CodeAttribute destCa) |
||||
throws com.fr.third.javassist.bytecode.BadBytecode |
||||
{ |
||||
int len = getCodeLength(); |
||||
byte[] newCode = new byte[len]; |
||||
destCa.info = newCode; |
||||
LdcEntry ldc = copyCode(this.info, 0, len, this.getConstPool(), |
||||
newCode, destCp, classnames); |
||||
return LdcEntry.doit(newCode, ldc, etable, destCa); |
||||
} |
||||
|
||||
private static LdcEntry copyCode(byte[] code, int beginPos, int endPos, |
||||
com.fr.third.javassist.bytecode.ConstPool srcCp, byte[] newcode, |
||||
com.fr.third.javassist.bytecode.ConstPool destCp, Map classnameMap) |
||||
throws com.fr.third.javassist.bytecode.BadBytecode |
||||
{ |
||||
int i2, index; |
||||
LdcEntry ldcEntry = null; |
||||
|
||||
for (int i = beginPos; i < endPos; i = i2) { |
||||
i2 = com.fr.third.javassist.bytecode.CodeIterator.nextOpcode(code, i); |
||||
byte c = code[i]; |
||||
newcode[i] = c; |
||||
switch (c & 0xff) { |
||||
case LDC_W : |
||||
case LDC2_W : |
||||
case GETSTATIC : |
||||
case PUTSTATIC : |
||||
case GETFIELD : |
||||
case PUTFIELD : |
||||
case INVOKEVIRTUAL : |
||||
case INVOKESPECIAL : |
||||
case INVOKESTATIC : |
||||
case NEW : |
||||
case ANEWARRAY : |
||||
case CHECKCAST : |
||||
case INSTANCEOF : |
||||
copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, |
||||
classnameMap); |
||||
break; |
||||
case LDC : |
||||
index = code[i + 1] & 0xff; |
||||
index = srcCp.copy(index, destCp, classnameMap); |
||||
if (index < 0x100) |
||||
newcode[i + 1] = (byte)index; |
||||
else { |
||||
newcode[i] = NOP; |
||||
newcode[i + 1] = NOP; |
||||
LdcEntry ldc = new LdcEntry(); |
||||
ldc.where = i; |
||||
ldc.index = index; |
||||
ldc.next = ldcEntry; |
||||
ldcEntry = ldc; |
||||
} |
||||
break; |
||||
case INVOKEINTERFACE : |
||||
copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, |
||||
classnameMap); |
||||
newcode[i + 3] = code[i + 3]; |
||||
newcode[i + 4] = code[i + 4]; |
||||
break; |
||||
case INVOKEDYNAMIC : |
||||
copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, |
||||
classnameMap); |
||||
newcode[i + 3] = 0; |
||||
newcode[i + 4] = 0; |
||||
break; |
||||
case MULTIANEWARRAY : |
||||
copyConstPoolInfo(i + 1, code, srcCp, newcode, destCp, |
||||
classnameMap); |
||||
newcode[i + 3] = code[i + 3]; |
||||
break; |
||||
default : |
||||
while (++i < i2) |
||||
newcode[i] = code[i]; |
||||
|
||||
break; |
||||
} |
||||
} |
||||
|
||||
return ldcEntry; |
||||
} |
||||
|
||||
private static void copyConstPoolInfo(int i, byte[] code, com.fr.third.javassist.bytecode.ConstPool srcCp, |
||||
byte[] newcode, ConstPool destCp, |
||||
Map classnameMap) { |
||||
int index = ((code[i] & 0xff) << 8) | (code[i + 1] & 0xff); |
||||
index = srcCp.copy(index, destCp, classnameMap); |
||||
newcode[i] = (byte)(index >> 8); |
||||
newcode[i + 1] = (byte)index; |
||||
} |
||||
|
||||
static class LdcEntry { |
||||
LdcEntry next; |
||||
int where; |
||||
int index; |
||||
|
||||
static byte[] doit(byte[] code, LdcEntry ldc, ExceptionTable etable, |
||||
CodeAttribute ca) |
||||
throws com.fr.third.javassist.bytecode.BadBytecode |
||||
{ |
||||
if (ldc != null) |
||||
code = com.fr.third.javassist.bytecode.CodeIterator.changeLdcToLdcW(code, etable, ca, ldc); |
||||
|
||||
/* The original code was the following: |
||||
|
||||
while (ldc != null) { |
||||
int where = ldc.where; |
||||
code = CodeIterator.insertGapCore0(code, where, 1, false, etable, ca); |
||||
code[where] = (byte)Opcode.LDC_W; |
||||
ByteArray.write16bit(ldc.index, code, where + 1); |
||||
ldc = ldc.next; |
||||
} |
||||
|
||||
But this code does not support a large method > 32KB. |
||||
*/ |
||||
|
||||
return code; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Changes the index numbers of the local variables |
||||
* to append a new parameter. |
||||
* This method does not update <code>LocalVariableAttribute</code>, |
||||
* <code>LocalVariableTypeAttribute</code>, |
||||
* <code>StackMapTable</code>, or <code>StackMap</code>. |
||||
* These attributes must be explicitly updated. |
||||
* |
||||
* @param where the index of the new parameter. |
||||
* @param size the type size of the new parameter (1 or 2). |
||||
* |
||||
* @see LocalVariableAttribute#shiftIndex(int, int) |
||||
* @see LocalVariableTypeAttribute#shiftIndex(int, int) |
||||
* @see StackMapTable#insertLocal(int, int, int) |
||||
* @see StackMap#insertLocal(int, int, int) |
||||
*/ |
||||
public void insertLocalVar(int where, int size) throws com.fr.third.javassist.bytecode.BadBytecode { |
||||
com.fr.third.javassist.bytecode.CodeIterator ci = iterator(); |
||||
while (ci.hasNext()) |
||||
shiftIndex(ci, where, size); |
||||
|
||||
setMaxLocals(getMaxLocals() + size); |
||||
} |
||||
|
||||
/** |
||||
* @param lessThan If the index of the local variable is |
||||
* less than this value, it does not change. |
||||
* Otherwise, the index is increased. |
||||
* @param delta the indexes of the local variables are |
||||
* increased by this value. |
||||
*/ |
||||
private static void shiftIndex(com.fr.third.javassist.bytecode.CodeIterator ci, int lessThan, int delta) throws com.fr.third.javassist.bytecode.BadBytecode { |
||||
int index = ci.next(); |
||||
int opcode = ci.byteAt(index); |
||||
if (opcode < ILOAD) |
||||
return; |
||||
else if (opcode < IASTORE) { |
||||
if (opcode < ILOAD_0) { |
||||
// iload, lload, fload, dload, aload
|
||||
shiftIndex8(ci, index, opcode, lessThan, delta); |
||||
} |
||||
else if (opcode < IALOAD) { |
||||
// iload_0, ..., aload_3
|
||||
shiftIndex0(ci, index, opcode, lessThan, delta, ILOAD_0, ILOAD); |
||||
} |
||||
else if (opcode < ISTORE) |
||||
return; |
||||
else if (opcode < ISTORE_0) { |
||||
// istore, lstore, ...
|
||||
shiftIndex8(ci, index, opcode, lessThan, delta); |
||||
} |
||||
else { |
||||
// istore_0, ..., astore_3
|
||||
shiftIndex0(ci, index, opcode, lessThan, delta, ISTORE_0, ISTORE); |
||||
} |
||||
} |
||||
else if (opcode == IINC) { |
||||
int var = ci.byteAt(index + 1); |
||||
if (var < lessThan) |
||||
return; |
||||
|
||||
var += delta; |
||||
if (var < 0x100) |
||||
ci.writeByte(var, index + 1); |
||||
else { |
||||
int plus = (byte)ci.byteAt(index + 2); |
||||
int pos = ci.insertExGap(3); |
||||
ci.writeByte(WIDE, pos - 3); |
||||
ci.writeByte(IINC, pos - 2); |
||||
ci.write16bit(var, pos - 1); |
||||
ci.write16bit(plus, pos + 1); |
||||
} |
||||
} |
||||
else if (opcode == RET) |
||||
shiftIndex8(ci, index, opcode, lessThan, delta); |
||||
else if (opcode == WIDE) { |
||||
int var = ci.u16bitAt(index + 2); |
||||
if (var < lessThan) |
||||
return; |
||||
|
||||
var += delta; |
||||
ci.write16bit(var, index + 2); |
||||
} |
||||
} |
||||
|
||||
private static void shiftIndex8(com.fr.third.javassist.bytecode.CodeIterator ci, int index, int opcode, |
||||
int lessThan, int delta) |
||||
throws com.fr.third.javassist.bytecode.BadBytecode |
||||
{ |
||||
int var = ci.byteAt(index + 1); |
||||
if (var < lessThan) |
||||
return; |
||||
|
||||
var += delta; |
||||
if (var < 0x100) |
||||
ci.writeByte(var, index + 1); |
||||
else { |
||||
int pos = ci.insertExGap(2); |
||||
ci.writeByte(WIDE, pos - 2); |
||||
ci.writeByte(opcode, pos - 1); |
||||
ci.write16bit(var, pos); |
||||
} |
||||
} |
||||
|
||||
private static void shiftIndex0(CodeIterator ci, int index, int opcode, |
||||
int lessThan, int delta, |
||||
int opcode_i_0, int opcode_i) |
||||
throws BadBytecode |
||||
{ |
||||
int var = (opcode - opcode_i_0) % 4; |
||||
if (var < lessThan) |
||||
return; |
||||
|
||||
var += delta; |
||||
if (var < 4) |
||||
ci.writeByte(opcode + delta, index); |
||||
else { |
||||
opcode = (opcode - opcode_i_0) / 4 + opcode_i; |
||||
if (var < 0x100) { |
||||
int pos = ci.insertExGap(1); |
||||
ci.writeByte(opcode, pos - 1); |
||||
ci.writeByte(var, pos); |
||||
} |
||||
else { |
||||
int pos = ci.insertExGap(3); |
||||
ci.writeByte(WIDE, pos - 1); |
||||
ci.writeByte(opcode, pos); |
||||
ci.write16bit(var, pos + 1); |
||||
} |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,73 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.util.Map; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* <code>ConstantValue_attribute</code>. |
||||
*/ |
||||
public class ConstantAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"ConstantValue"</code>. |
||||
*/ |
||||
public static final String tag = "ConstantValue"; |
||||
|
||||
ConstantAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a ConstantValue attribute. |
||||
* |
||||
* @param cp a constant pool table. |
||||
* @param index <code>constantvalue_index</code> |
||||
* of <code>ConstantValue_attribute</code>. |
||||
*/ |
||||
public ConstantAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int index) { |
||||
super(cp, tag); |
||||
byte[] bvalue = new byte[2]; |
||||
bvalue[0] = (byte)(index >>> 8); |
||||
bvalue[1] = (byte)index; |
||||
set(bvalue); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>constantvalue_index</code>. |
||||
*/ |
||||
public int getConstantValue() { |
||||
return ByteArray.readU16bit(get(), 0); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. Class names are replaced according to the |
||||
* given <code>Map</code> object. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
*/ |
||||
public AttributeInfo copy(ConstPool newCp, Map classnames) { |
||||
int index = getConstPool().copy(getConstantValue(), newCp, |
||||
classnames); |
||||
return new ConstantAttribute(newCp, index); |
||||
} |
||||
} |
@ -1,56 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <code>Deprecated_attribute</code>. |
||||
*/ |
||||
public class DeprecatedAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"Deprecated"</code>. |
||||
*/ |
||||
public static final String tag = "Deprecated"; |
||||
|
||||
DeprecatedAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a Deprecated attribute. |
||||
* |
||||
* @param cp a constant pool table. |
||||
*/ |
||||
public DeprecatedAttribute(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
super(cp, tag, new byte[0]); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames should be null. |
||||
*/ |
||||
public AttributeInfo copy(ConstPool newCp, Map classnames) { |
||||
return new DeprecatedAttribute(newCp); |
||||
} |
||||
} |
@ -1,872 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.CtClass; |
||||
import com.fr.third.javassist.CtPrimitiveType; |
||||
import com.fr.third.javassist.NotFoundException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* A support class for dealing with descriptors. |
||||
* |
||||
* <p>See chapter 4.3 in "The Java Virtual Machine Specification (2nd ed.)" |
||||
*/ |
||||
public class Descriptor { |
||||
/** |
||||
* Converts a class name into the internal representation used in |
||||
* the JVM. |
||||
* |
||||
* <p>Note that <code>toJvmName(toJvmName(s))</code> is equivalent |
||||
* to <code>toJvmName(s)</code>. |
||||
*/ |
||||
public static String toJvmName(String classname) { |
||||
return classname.replace('.', '/'); |
||||
} |
||||
|
||||
/** |
||||
* Converts a class name from the internal representation used in |
||||
* the JVM to the normal one used in Java. |
||||
* This method does not deal with an array type name such as |
||||
* "[Ljava/lang/Object;" and "[I;". For such names, use |
||||
* <code>toClassName()</code>. |
||||
* |
||||
* @see #toClassName(String) |
||||
*/ |
||||
public static String toJavaName(String classname) { |
||||
return classname.replace('/', '.'); |
||||
} |
||||
|
||||
/** |
||||
* Returns the internal representation of the class name in the |
||||
* JVM. |
||||
*/ |
||||
public static String toJvmName(CtClass clazz) { |
||||
if (clazz.isArray()) |
||||
return of(clazz); |
||||
else |
||||
return toJvmName(clazz.getName()); |
||||
} |
||||
|
||||
/** |
||||
* Converts to a Java class name from a descriptor. |
||||
* |
||||
* @param descriptor type descriptor. |
||||
*/ |
||||
public static String toClassName(String descriptor) { |
||||
int arrayDim = 0; |
||||
int i = 0; |
||||
char c = descriptor.charAt(0); |
||||
while (c == '[') { |
||||
++arrayDim; |
||||
c = descriptor.charAt(++i); |
||||
} |
||||
|
||||
String name; |
||||
if (c == 'L') { |
||||
int i2 = descriptor.indexOf(';', i++); |
||||
name = descriptor.substring(i, i2).replace('/', '.'); |
||||
i = i2; |
||||
} |
||||
else if (c == 'V') |
||||
name = "void"; |
||||
else if (c == 'I') |
||||
name = "int"; |
||||
else if (c == 'B') |
||||
name = "byte"; |
||||
else if (c == 'J') |
||||
name = "long"; |
||||
else if (c == 'D') |
||||
name = "double"; |
||||
else if (c == 'F') |
||||
name = "float"; |
||||
else if (c == 'C') |
||||
name = "char"; |
||||
else if (c == 'S') |
||||
name = "short"; |
||||
else if (c == 'Z') |
||||
name = "boolean"; |
||||
else |
||||
throw new RuntimeException("bad descriptor: " + descriptor); |
||||
|
||||
if (i + 1 != descriptor.length()) |
||||
throw new RuntimeException("multiple descriptors?: " + descriptor); |
||||
|
||||
if (arrayDim == 0) |
||||
return name; |
||||
else { |
||||
StringBuffer sbuf = new StringBuffer(name); |
||||
do { |
||||
sbuf.append("[]"); |
||||
} while (--arrayDim > 0); |
||||
|
||||
return sbuf.toString(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Converts to a descriptor from a Java class name |
||||
*/ |
||||
public static String of(String classname) { |
||||
if (classname.equals("void")) |
||||
return "V"; |
||||
else if (classname.equals("int")) |
||||
return "I"; |
||||
else if (classname.equals("byte")) |
||||
return "B"; |
||||
else if (classname.equals("long")) |
||||
return "J"; |
||||
else if (classname.equals("double")) |
||||
return "D"; |
||||
else if (classname.equals("float")) |
||||
return "F"; |
||||
else if (classname.equals("char")) |
||||
return "C"; |
||||
else if (classname.equals("short")) |
||||
return "S"; |
||||
else if (classname.equals("boolean")) |
||||
return "Z"; |
||||
else |
||||
return "L" + toJvmName(classname) + ";"; |
||||
} |
||||
|
||||
/** |
||||
* Substitutes a class name |
||||
* in the given descriptor string. |
||||
* |
||||
* @param desc descriptor string |
||||
* @param oldname replaced JVM class name |
||||
* @param newname substituted JVM class name |
||||
* |
||||
* @see Descriptor#toJvmName(String) |
||||
*/ |
||||
public static String rename(String desc, String oldname, String newname) { |
||||
if (desc.indexOf(oldname) < 0) |
||||
return desc; |
||||
|
||||
StringBuffer newdesc = new StringBuffer(); |
||||
int head = 0; |
||||
int i = 0; |
||||
for (;;) { |
||||
int j = desc.indexOf('L', i); |
||||
if (j < 0) |
||||
break; |
||||
else if (desc.startsWith(oldname, j + 1) |
||||
&& desc.charAt(j + oldname.length() + 1) == ';') { |
||||
newdesc.append(desc.substring(head, j)); |
||||
newdesc.append('L'); |
||||
newdesc.append(newname); |
||||
newdesc.append(';'); |
||||
head = i = j + oldname.length() + 2; |
||||
} |
||||
else { |
||||
i = desc.indexOf(';', j) + 1; |
||||
if (i < 1) |
||||
break; // ';' was not found.
|
||||
} |
||||
} |
||||
|
||||
if (head == 0) |
||||
return desc; |
||||
else { |
||||
int len = desc.length(); |
||||
if (head < len) |
||||
newdesc.append(desc.substring(head, len)); |
||||
|
||||
return newdesc.toString(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Substitutes class names in the given descriptor string |
||||
* according to the given <code>map</code>. |
||||
* |
||||
* @param map a map between replaced and substituted |
||||
* JVM class names. |
||||
* @see Descriptor#toJvmName(String) |
||||
*/ |
||||
public static String rename(String desc, Map map) { |
||||
if (map == null) |
||||
return desc; |
||||
|
||||
StringBuffer newdesc = new StringBuffer(); |
||||
int head = 0; |
||||
int i = 0; |
||||
for (;;) { |
||||
int j = desc.indexOf('L', i); |
||||
if (j < 0) |
||||
break; |
||||
|
||||
int k = desc.indexOf(';', j); |
||||
if (k < 0) |
||||
break; |
||||
|
||||
i = k + 1; |
||||
String name = desc.substring(j + 1, k); |
||||
String name2 = (String)map.get(name); |
||||
if (name2 != null) { |
||||
newdesc.append(desc.substring(head, j)); |
||||
newdesc.append('L'); |
||||
newdesc.append(name2); |
||||
newdesc.append(';'); |
||||
head = i; |
||||
} |
||||
} |
||||
|
||||
if (head == 0) |
||||
return desc; |
||||
else { |
||||
int len = desc.length(); |
||||
if (head < len) |
||||
newdesc.append(desc.substring(head, len)); |
||||
|
||||
return newdesc.toString(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the descriptor representing the given type. |
||||
*/ |
||||
public static String of(CtClass type) { |
||||
StringBuffer sbuf = new StringBuffer(); |
||||
toDescriptor(sbuf, type); |
||||
return sbuf.toString(); |
||||
} |
||||
|
||||
private static void toDescriptor(StringBuffer desc, CtClass type) { |
||||
if (type.isArray()) { |
||||
desc.append('['); |
||||
try { |
||||
toDescriptor(desc, type.getComponentType()); |
||||
} |
||||
catch (NotFoundException e) { |
||||
desc.append('L'); |
||||
String name = type.getName(); |
||||
desc.append(toJvmName(name.substring(0, name.length() - 2))); |
||||
desc.append(';'); |
||||
} |
||||
} |
||||
else if (type.isPrimitive()) { |
||||
CtPrimitiveType pt = (CtPrimitiveType)type; |
||||
desc.append(pt.getDescriptor()); |
||||
} |
||||
else { // class type
|
||||
desc.append('L'); |
||||
desc.append(type.getName().replace('.', '/')); |
||||
desc.append(';'); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the descriptor representing a constructor receiving |
||||
* the given parameter types. |
||||
* |
||||
* @param paramTypes parameter types |
||||
*/ |
||||
public static String ofConstructor(CtClass[] paramTypes) { |
||||
return ofMethod(CtClass.voidType, paramTypes); |
||||
} |
||||
|
||||
/** |
||||
* Returns the descriptor representing a method that receives |
||||
* the given parameter types and returns the given type. |
||||
* |
||||
* @param returnType return type |
||||
* @param paramTypes parameter types |
||||
*/ |
||||
public static String ofMethod(CtClass returnType, CtClass[] paramTypes) { |
||||
StringBuffer desc = new StringBuffer(); |
||||
desc.append('('); |
||||
if (paramTypes != null) { |
||||
int n = paramTypes.length; |
||||
for (int i = 0; i < n; ++i) |
||||
toDescriptor(desc, paramTypes[i]); |
||||
} |
||||
|
||||
desc.append(')'); |
||||
if (returnType != null) |
||||
toDescriptor(desc, returnType); |
||||
|
||||
return desc.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the descriptor representing a list of parameter types. |
||||
* For example, if the given parameter types are two <code>int</code>, |
||||
* then this method returns <code>"(II)"</code>. |
||||
* |
||||
* @param paramTypes parameter types |
||||
*/ |
||||
public static String ofParameters(CtClass[] paramTypes) { |
||||
return ofMethod(null, paramTypes); |
||||
} |
||||
|
||||
/** |
||||
* Appends a parameter type to the parameter list represented |
||||
* by the given descriptor. |
||||
* |
||||
* <p><code>classname</code> must not be an array type. |
||||
* |
||||
* @param classname parameter type (not primitive type) |
||||
* @param desc descriptor |
||||
*/ |
||||
public static String appendParameter(String classname, String desc) { |
||||
int i = desc.indexOf(')'); |
||||
if (i < 0) |
||||
return desc; |
||||
else { |
||||
StringBuffer newdesc = new StringBuffer(); |
||||
newdesc.append(desc.substring(0, i)); |
||||
newdesc.append('L'); |
||||
newdesc.append(classname.replace('.', '/')); |
||||
newdesc.append(';'); |
||||
newdesc.append(desc.substring(i)); |
||||
return newdesc.toString(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Inserts a parameter type at the beginning of the parameter |
||||
* list represented |
||||
* by the given descriptor. |
||||
* |
||||
* <p><code>classname</code> must not be an array type. |
||||
* |
||||
* @param classname parameter type (not primitive type) |
||||
* @param desc descriptor |
||||
*/ |
||||
public static String insertParameter(String classname, String desc) { |
||||
if (desc.charAt(0) != '(') |
||||
return desc; |
||||
else |
||||
return "(L" + classname.replace('.', '/') + ';' |
||||
+ desc.substring(1); |
||||
} |
||||
|
||||
/** |
||||
* Appends a parameter type to the parameter list represented |
||||
* by the given descriptor. The appended parameter becomes |
||||
* the last parameter. |
||||
* |
||||
* @param type the type of the appended parameter. |
||||
* @param descriptor the original descriptor. |
||||
*/ |
||||
public static String appendParameter(CtClass type, String descriptor) { |
||||
int i = descriptor.indexOf(')'); |
||||
if (i < 0) |
||||
return descriptor; |
||||
else { |
||||
StringBuffer newdesc = new StringBuffer(); |
||||
newdesc.append(descriptor.substring(0, i)); |
||||
toDescriptor(newdesc, type); |
||||
newdesc.append(descriptor.substring(i)); |
||||
return newdesc.toString(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Inserts a parameter type at the beginning of the parameter |
||||
* list represented |
||||
* by the given descriptor. |
||||
* |
||||
* @param type the type of the inserted parameter. |
||||
* @param descriptor the descriptor of the method. |
||||
*/ |
||||
public static String insertParameter(CtClass type, |
||||
String descriptor) { |
||||
if (descriptor.charAt(0) != '(') |
||||
return descriptor; |
||||
else |
||||
return "(" + of(type) + descriptor.substring(1); |
||||
} |
||||
|
||||
/** |
||||
* Changes the return type included in the given descriptor. |
||||
* |
||||
* <p><code>classname</code> must not be an array type. |
||||
* |
||||
* @param classname return type |
||||
* @param desc descriptor |
||||
*/ |
||||
public static String changeReturnType(String classname, String desc) { |
||||
int i = desc.indexOf(')'); |
||||
if (i < 0) |
||||
return desc; |
||||
else { |
||||
StringBuffer newdesc = new StringBuffer(); |
||||
newdesc.append(desc.substring(0, i + 1)); |
||||
newdesc.append('L'); |
||||
newdesc.append(classname.replace('.', '/')); |
||||
newdesc.append(';'); |
||||
return newdesc.toString(); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the <code>CtClass</code> objects representing the parameter |
||||
* types specified by the given descriptor. |
||||
* |
||||
* @param desc descriptor |
||||
* @param cp the class pool used for obtaining |
||||
* a <code>CtClass</code> object. |
||||
*/ |
||||
public static CtClass[] getParameterTypes(String desc, ClassPool cp) |
||||
throws NotFoundException |
||||
{ |
||||
if (desc.charAt(0) != '(') |
||||
return null; |
||||
else { |
||||
int num = numOfParameters(desc); |
||||
CtClass[] args = new CtClass[num]; |
||||
int n = 0; |
||||
int i = 1; |
||||
do { |
||||
i = toCtClass(cp, desc, i, args, n++); |
||||
} while (i > 0); |
||||
return args; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the list of the parameter types of desc1 is equal to |
||||
* that of desc2. |
||||
* For example, "(II)V" and "(II)I" are equal. |
||||
*/ |
||||
public static boolean eqParamTypes(String desc1, String desc2) { |
||||
if (desc1.charAt(0) != '(') |
||||
return false; |
||||
|
||||
for (int i = 0; true; ++i) { |
||||
char c = desc1.charAt(i); |
||||
if (c != desc2.charAt(i)) |
||||
return false; |
||||
|
||||
if (c == ')') |
||||
return true; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the signature of the given descriptor. The signature does |
||||
* not include the return type. For example, the signature of "(I)V" |
||||
* is "(I)". |
||||
*/ |
||||
public static String getParamDescriptor(String decl) { |
||||
return decl.substring(0, decl.indexOf(')') + 1); |
||||
} |
||||
|
||||
/** |
||||
* Returns the <code>CtClass</code> object representing the return |
||||
* type specified by the given descriptor. |
||||
* |
||||
* @param desc descriptor |
||||
* @param cp the class pool used for obtaining |
||||
* a <code>CtClass</code> object. |
||||
*/ |
||||
public static CtClass getReturnType(String desc, ClassPool cp) |
||||
throws NotFoundException |
||||
{ |
||||
int i = desc.indexOf(')'); |
||||
if (i < 0) |
||||
return null; |
||||
else { |
||||
CtClass[] type = new CtClass[1]; |
||||
toCtClass(cp, desc, i + 1, type, 0); |
||||
return type[0]; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of the prameters included in the given |
||||
* descriptor. |
||||
* |
||||
* @param desc descriptor |
||||
*/ |
||||
public static int numOfParameters(String desc) { |
||||
int n = 0; |
||||
int i = 1; |
||||
for (;;) { |
||||
char c = desc.charAt(i); |
||||
if (c == ')') |
||||
break; |
||||
|
||||
while (c == '[') |
||||
c = desc.charAt(++i); |
||||
|
||||
if (c == 'L') { |
||||
i = desc.indexOf(';', i) + 1; |
||||
if (i <= 0) |
||||
throw new IndexOutOfBoundsException("bad descriptor"); |
||||
} |
||||
else |
||||
++i; |
||||
|
||||
++n; |
||||
} |
||||
|
||||
return n; |
||||
} |
||||
|
||||
/** |
||||
* Returns a <code>CtClass</code> object representing the type |
||||
* specified by the given descriptor. |
||||
* |
||||
* <p>This method works even if the package-class separator is |
||||
* not <code>/</code> but <code>.</code> (period). For example, |
||||
* it accepts <code>Ljava.lang.Object;</code> |
||||
* as well as <code>Ljava/lang/Object;</code>. |
||||
* |
||||
* @param desc descriptor. |
||||
* @param cp the class pool used for obtaining |
||||
* a <code>CtClass</code> object. |
||||
*/ |
||||
public static CtClass toCtClass(String desc, ClassPool cp) |
||||
throws NotFoundException |
||||
{ |
||||
CtClass[] clazz = new CtClass[1]; |
||||
int res = toCtClass(cp, desc, 0, clazz, 0); |
||||
if (res >= 0) |
||||
return clazz[0]; |
||||
else { |
||||
// maybe, you forgot to surround the class name with
|
||||
// L and ;. It violates the protocol, but I'm tolerant...
|
||||
return cp.get(desc.replace('/', '.')); |
||||
} |
||||
} |
||||
|
||||
private static int toCtClass(ClassPool cp, String desc, int i, |
||||
CtClass[] args, int n) |
||||
throws NotFoundException |
||||
{ |
||||
int i2; |
||||
String name; |
||||
|
||||
int arrayDim = 0; |
||||
char c = desc.charAt(i); |
||||
while (c == '[') { |
||||
++arrayDim; |
||||
c = desc.charAt(++i); |
||||
} |
||||
|
||||
if (c == 'L') { |
||||
i2 = desc.indexOf(';', ++i); |
||||
name = desc.substring(i, i2++).replace('/', '.'); |
||||
} |
||||
else { |
||||
CtClass type = toPrimitiveClass(c); |
||||
if (type == null) |
||||
return -1; // error
|
||||
|
||||
i2 = i + 1; |
||||
if (arrayDim == 0) { |
||||
args[n] = type; |
||||
return i2; // neither an array type or a class type
|
||||
} |
||||
else |
||||
name = type.getName(); |
||||
} |
||||
|
||||
if (arrayDim > 0) { |
||||
StringBuffer sbuf = new StringBuffer(name); |
||||
while (arrayDim-- > 0) |
||||
sbuf.append("[]"); |
||||
|
||||
name = sbuf.toString(); |
||||
} |
||||
|
||||
args[n] = cp.get(name); |
||||
return i2; |
||||
} |
||||
|
||||
static CtClass toPrimitiveClass(char c) { |
||||
CtClass type = null; |
||||
switch (c) { |
||||
case 'Z' : |
||||
type = CtClass.booleanType; |
||||
break; |
||||
case 'C' : |
||||
type = CtClass.charType; |
||||
break; |
||||
case 'B' : |
||||
type = CtClass.byteType; |
||||
break; |
||||
case 'S' : |
||||
type = CtClass.shortType; |
||||
break; |
||||
case 'I' : |
||||
type = CtClass.intType; |
||||
break; |
||||
case 'J' : |
||||
type = CtClass.longType; |
||||
break; |
||||
case 'F' : |
||||
type = CtClass.floatType; |
||||
break; |
||||
case 'D' : |
||||
type = CtClass.doubleType; |
||||
break; |
||||
case 'V' : |
||||
type = CtClass.voidType; |
||||
break; |
||||
} |
||||
|
||||
return type; |
||||
} |
||||
|
||||
/** |
||||
* Computes the dimension of the array represented by the given |
||||
* descriptor. For example, if the descriptor is <code>"[[I"</code>, |
||||
* then this method returns 2. |
||||
* |
||||
* @param desc the descriptor. |
||||
* @return 0 if the descriptor does not represent an array type. |
||||
*/ |
||||
public static int arrayDimension(String desc) { |
||||
int dim = 0; |
||||
while (desc.charAt(dim) == '[') |
||||
++dim; |
||||
|
||||
return dim; |
||||
} |
||||
|
||||
/** |
||||
* Returns the descriptor of the type of the array component. |
||||
* For example, if the given descriptor is |
||||
* <code>"[[Ljava/lang/String;"</code> and the given dimension is 2, |
||||
* then this method returns <code>"Ljava/lang/String;"</code>. |
||||
* |
||||
* @param desc the descriptor. |
||||
* @param dim the array dimension. |
||||
*/ |
||||
public static String toArrayComponent(String desc, int dim) { |
||||
return desc.substring(dim); |
||||
} |
||||
|
||||
/** |
||||
* Computes the data size specified by the given descriptor. |
||||
* For example, if the descriptor is "D", this method returns 2. |
||||
* |
||||
* <p>If the descriptor represents a method type, this method returns |
||||
* (the size of the returned value) - (the sum of the data sizes |
||||
* of all the parameters). For example, if the descriptor is |
||||
* <code>"(I)D"</code>, then this method returns 1 (= 2 - 1). |
||||
* |
||||
* @param desc descriptor |
||||
*/ |
||||
public static int dataSize(String desc) { |
||||
return dataSize(desc, true); |
||||
} |
||||
|
||||
/** |
||||
* Computes the data size of parameters. |
||||
* If one of the parameters is double type, the size of that parameter |
||||
* is 2 words. For example, if the given descriptor is |
||||
* <code>"(IJ)D"</code>, then this method returns 3. The size of the |
||||
* return type is not computed. |
||||
* |
||||
* @param desc a method descriptor. |
||||
*/ |
||||
public static int paramSize(String desc) { |
||||
return -dataSize(desc, false); |
||||
} |
||||
|
||||
private static int dataSize(String desc, boolean withRet) { |
||||
int n = 0; |
||||
char c = desc.charAt(0); |
||||
if (c == '(') { |
||||
int i = 1; |
||||
for (;;) { |
||||
c = desc.charAt(i); |
||||
if (c == ')') { |
||||
c = desc.charAt(i + 1); |
||||
break; |
||||
} |
||||
|
||||
boolean array = false; |
||||
while (c == '[') { |
||||
array = true; |
||||
c = desc.charAt(++i); |
||||
} |
||||
|
||||
if (c == 'L') { |
||||
i = desc.indexOf(';', i) + 1; |
||||
if (i <= 0) |
||||
throw new IndexOutOfBoundsException("bad descriptor"); |
||||
} |
||||
else |
||||
++i; |
||||
|
||||
if (!array && (c == 'J' || c == 'D')) |
||||
n -= 2; |
||||
else |
||||
--n; |
||||
} |
||||
} |
||||
|
||||
if (withRet) |
||||
if (c == 'J' || c == 'D') |
||||
n += 2; |
||||
else if (c != 'V') |
||||
++n; |
||||
|
||||
return n; |
||||
} |
||||
|
||||
/** |
||||
* Returns a human-readable representation of the |
||||
* given descriptor. For example, <code>Ljava/lang/Object;</code> |
||||
* is converted into <code>java.lang.Object</code>. |
||||
* <code>(I[I)V</code> is converted into <code>(int, int[])</code> |
||||
* (the return type is ignored). |
||||
*/ |
||||
public static String toString(String desc) { |
||||
return PrettyPrinter.toString(desc); |
||||
} |
||||
|
||||
static class PrettyPrinter { |
||||
static String toString(String desc) { |
||||
StringBuffer sbuf = new StringBuffer(); |
||||
if (desc.charAt(0) == '(') { |
||||
int pos = 1; |
||||
sbuf.append('('); |
||||
while (desc.charAt(pos) != ')') { |
||||
if (pos > 1) |
||||
sbuf.append(','); |
||||
|
||||
pos = readType(sbuf, pos, desc); |
||||
} |
||||
|
||||
sbuf.append(')'); |
||||
} |
||||
else |
||||
readType(sbuf, 0, desc); |
||||
|
||||
return sbuf.toString(); |
||||
} |
||||
|
||||
static int readType(StringBuffer sbuf, int pos, String desc) { |
||||
char c = desc.charAt(pos); |
||||
int arrayDim = 0; |
||||
while (c == '[') { |
||||
arrayDim++; |
||||
c = desc.charAt(++pos); |
||||
} |
||||
|
||||
if (c == 'L') |
||||
while (true) { |
||||
c = desc.charAt(++pos); |
||||
if (c == ';') |
||||
break; |
||||
|
||||
if (c == '/') |
||||
c = '.'; |
||||
|
||||
sbuf.append(c); |
||||
} |
||||
else { |
||||
CtClass t = toPrimitiveClass(c); |
||||
sbuf.append(t.getName()); |
||||
} |
||||
|
||||
while (arrayDim-- > 0) |
||||
sbuf.append("[]"); |
||||
|
||||
return pos + 1; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* An Iterator over a descriptor. |
||||
*/ |
||||
public static class Iterator { |
||||
private String desc; |
||||
private int index, curPos; |
||||
private boolean param; |
||||
|
||||
/** |
||||
* Constructs an iterator. |
||||
* |
||||
* @param s descriptor. |
||||
*/ |
||||
public Iterator(String s) { |
||||
desc = s; |
||||
index = curPos = 0; |
||||
param = false; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the iteration has more elements. |
||||
*/ |
||||
public boolean hasNext() { |
||||
return index < desc.length(); |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the current element is a parameter type. |
||||
*/ |
||||
public boolean isParameter() { return param; } |
||||
|
||||
/** |
||||
* Returns the first character of the current element. |
||||
*/ |
||||
public char currentChar() { return desc.charAt(curPos); } |
||||
|
||||
/** |
||||
* Returns true if the current element is double or long type. |
||||
*/ |
||||
public boolean is2byte() { |
||||
char c = currentChar(); |
||||
return c == 'D' || c == 'J'; |
||||
} |
||||
|
||||
/** |
||||
* Returns the position of the next type character. |
||||
* That type character becomes a new current element. |
||||
*/ |
||||
public int next() { |
||||
int nextPos = index; |
||||
char c = desc.charAt(nextPos); |
||||
if (c == '(') { |
||||
++index; |
||||
c = desc.charAt(++nextPos); |
||||
param = true; |
||||
} |
||||
|
||||
if (c == ')') { |
||||
++index; |
||||
c = desc.charAt(++nextPos); |
||||
param = false; |
||||
} |
||||
|
||||
while (c == '[') |
||||
c = desc.charAt(++nextPos); |
||||
|
||||
if (c == 'L') { |
||||
nextPos = desc.indexOf(';', nextPos) + 1; |
||||
if (nextPos <= 0) |
||||
throw new IndexOutOfBoundsException("bad descriptor"); |
||||
} |
||||
else |
||||
++nextPos; |
||||
|
||||
curPos = index; |
||||
index = nextPos; |
||||
return curPos; |
||||
} |
||||
} |
||||
} |
@ -1,31 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import com.fr.third.javassist.CannotCompileException; |
||||
|
||||
/** |
||||
* An exception thrown when adding a duplicate member is requested. |
||||
* |
||||
* @see com.fr.third.javassist.bytecode.ClassFile#addMethod(MethodInfo) |
||||
* @see ClassFile#addField(FieldInfo) |
||||
*/ |
||||
public class DuplicateMemberException extends CannotCompileException { |
||||
public DuplicateMemberException(String msg) { |
||||
super(msg); |
||||
} |
||||
} |
@ -1,134 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <code>EnclosingMethod_attribute</code>. |
||||
*/ |
||||
public class EnclosingMethodAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"EnclosingMethod"</code>. |
||||
*/ |
||||
public static final String tag = "EnclosingMethod"; |
||||
|
||||
EnclosingMethodAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an EnclosingMethod attribute. |
||||
* |
||||
* @param cp a constant pool table. |
||||
* @param className the name of the innermost enclosing class. |
||||
* @param methodName the name of the enclosing method. |
||||
* @param methodDesc the descriptor of the enclosing method. |
||||
*/ |
||||
public EnclosingMethodAttribute(com.fr.third.javassist.bytecode.ConstPool cp, String className, |
||||
String methodName, String methodDesc) { |
||||
super(cp, tag); |
||||
int ci = cp.addClassInfo(className); |
||||
int ni = cp.addNameAndTypeInfo(methodName, methodDesc); |
||||
byte[] bvalue = new byte[4]; |
||||
bvalue[0] = (byte)(ci >>> 8); |
||||
bvalue[1] = (byte)ci; |
||||
bvalue[2] = (byte)(ni >>> 8); |
||||
bvalue[3] = (byte)ni; |
||||
set(bvalue); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an EnclosingMethod attribute. |
||||
* The value of <code>method_index</code> is set to 0. |
||||
* |
||||
* @param cp a constant pool table. |
||||
* @param className the name of the innermost enclosing class. |
||||
*/ |
||||
public EnclosingMethodAttribute(com.fr.third.javassist.bytecode.ConstPool cp, String className) { |
||||
super(cp, tag); |
||||
int ci = cp.addClassInfo(className); |
||||
int ni = 0; |
||||
byte[] bvalue = new byte[4]; |
||||
bvalue[0] = (byte)(ci >>> 8); |
||||
bvalue[1] = (byte)ci; |
||||
bvalue[2] = (byte)(ni >>> 8); |
||||
bvalue[3] = (byte)ni; |
||||
set(bvalue); |
||||
} |
||||
|
||||
/** |
||||
* Returns the value of <code>class_index</code>. |
||||
*/ |
||||
public int classIndex() { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(get(), 0); |
||||
} |
||||
|
||||
/** |
||||
* Returns the value of <code>method_index</code>. |
||||
*/ |
||||
public int methodIndex() { |
||||
return ByteArray.readU16bit(get(), 2); |
||||
} |
||||
|
||||
/** |
||||
* Returns the name of the class specified by <code>class_index</code>. |
||||
*/ |
||||
public String className() { |
||||
return getConstPool().getClassInfo(classIndex()); |
||||
} |
||||
|
||||
/** |
||||
* Returns the method name specified by <code>method_index</code>. |
||||
*/ |
||||
public String methodName() { |
||||
com.fr.third.javassist.bytecode.ConstPool cp = getConstPool(); |
||||
int mi = methodIndex(); |
||||
int ni = cp.getNameAndTypeName(mi); |
||||
return cp.getUtf8Info(ni); |
||||
} |
||||
|
||||
/** |
||||
* Returns the method descriptor specified by <code>method_index</code>. |
||||
*/ |
||||
public String methodDescriptor() { |
||||
com.fr.third.javassist.bytecode.ConstPool cp = getConstPool(); |
||||
int mi = methodIndex(); |
||||
int ti = cp.getNameAndTypeDescriptor(mi); |
||||
return cp.getUtf8Info(ti); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. Class names are replaced according to the |
||||
* given <code>Map</code> object. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
*/ |
||||
public AttributeInfo copy(ConstPool newCp, Map classnames) { |
||||
if (methodIndex() == 0) |
||||
return new EnclosingMethodAttribute(newCp, className()); |
||||
else |
||||
return new EnclosingMethodAttribute(newCp, className(), |
||||
methodName(), methodDescriptor()); |
||||
} |
||||
} |
@ -1,281 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.DataOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.ArrayList; |
||||
import java.util.Map; |
||||
|
||||
class ExceptionTableEntry { |
||||
int startPc; |
||||
int endPc; |
||||
int handlerPc; |
||||
int catchType; |
||||
|
||||
ExceptionTableEntry(int start, int end, int handle, int type) { |
||||
startPc = start; |
||||
endPc = end; |
||||
handlerPc = handle; |
||||
catchType = type; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* <code>exception_table[]</code> of <code>Code_attribute</code>. |
||||
*/ |
||||
public class ExceptionTable implements Cloneable { |
||||
private com.fr.third.javassist.bytecode.ConstPool constPool; |
||||
private ArrayList entries; |
||||
|
||||
/** |
||||
* Constructs an <code>exception_table[]</code>. |
||||
* |
||||
* @param cp constant pool table. |
||||
*/ |
||||
public ExceptionTable(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
constPool = cp; |
||||
entries = new ArrayList(); |
||||
} |
||||
|
||||
ExceptionTable(com.fr.third.javassist.bytecode.ConstPool cp, DataInputStream in) throws IOException { |
||||
constPool = cp; |
||||
int length = in.readUnsignedShort(); |
||||
ArrayList list = new ArrayList(length); |
||||
for (int i = 0; i < length; ++i) { |
||||
int start = in.readUnsignedShort(); |
||||
int end = in.readUnsignedShort(); |
||||
int handle = in.readUnsignedShort(); |
||||
int type = in.readUnsignedShort(); |
||||
list.add(new ExceptionTableEntry(start, end, handle, type)); |
||||
} |
||||
|
||||
entries = list; |
||||
} |
||||
|
||||
/** |
||||
* Creates and returns a copy of this object. |
||||
* The constant pool object is shared between this object |
||||
* and the cloned object. |
||||
*/ |
||||
public Object clone() throws CloneNotSupportedException { |
||||
ExceptionTable r = (ExceptionTable)super.clone(); |
||||
r.entries = new ArrayList(entries); |
||||
return r; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>exception_table_length</code>, which is the number |
||||
* of entries in the <code>exception_table[]</code>. |
||||
*/ |
||||
public int size() { |
||||
return entries.size(); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>startPc</code> of the <i>n</i>-th entry. |
||||
* |
||||
* @param nth the <i>n</i>-th (>= 0). |
||||
*/ |
||||
public int startPc(int nth) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth); |
||||
return e.startPc; |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>startPc</code> of the <i>n</i>-th entry. |
||||
* |
||||
* @param nth the <i>n</i>-th (>= 0). |
||||
* @param value new value. |
||||
*/ |
||||
public void setStartPc(int nth, int value) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth); |
||||
e.startPc = value; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>endPc</code> of the <i>n</i>-th entry. |
||||
* |
||||
* @param nth the <i>n</i>-th (>= 0). |
||||
*/ |
||||
public int endPc(int nth) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth); |
||||
return e.endPc; |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>endPc</code> of the <i>n</i>-th entry. |
||||
* |
||||
* @param nth the <i>n</i>-th (>= 0). |
||||
* @param value new value. |
||||
*/ |
||||
public void setEndPc(int nth, int value) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth); |
||||
e.endPc = value; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>handlerPc</code> of the <i>n</i>-th entry. |
||||
* |
||||
* @param nth the <i>n</i>-th (>= 0). |
||||
*/ |
||||
public int handlerPc(int nth) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth); |
||||
return e.handlerPc; |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>handlerPc</code> of the <i>n</i>-th entry. |
||||
* |
||||
* @param nth the <i>n</i>-th (>= 0). |
||||
* @param value new value. |
||||
*/ |
||||
public void setHandlerPc(int nth, int value) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth); |
||||
e.handlerPc = value; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>catchType</code> of the <i>n</i>-th entry. |
||||
* |
||||
* @param nth the <i>n</i>-th (>= 0). |
||||
* @return an index into the <code>constant_pool</code> table, |
||||
* or zero if this exception handler is for all exceptions. |
||||
*/ |
||||
public int catchType(int nth) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth); |
||||
return e.catchType; |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>catchType</code> of the <i>n</i>-th entry. |
||||
* |
||||
* @param nth the <i>n</i>-th (>= 0). |
||||
* @param value new value. |
||||
*/ |
||||
public void setCatchType(int nth, int value) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(nth); |
||||
e.catchType = value; |
||||
} |
||||
|
||||
/** |
||||
* Copies the given exception table at the specified position |
||||
* in the table. |
||||
* |
||||
* @param index index (>= 0) at which the entry is to be inserted. |
||||
* @param offset the offset added to the code position. |
||||
*/ |
||||
public void add(int index, ExceptionTable table, int offset) { |
||||
int len = table.size(); |
||||
while (--len >= 0) { |
||||
ExceptionTableEntry e |
||||
= (ExceptionTableEntry)table.entries.get(len); |
||||
add(index, e.startPc + offset, e.endPc + offset, |
||||
e.handlerPc + offset, e.catchType); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Adds a new entry at the specified position in the table. |
||||
* |
||||
* @param index index (>= 0) at which the entry is to be inserted. |
||||
* @param start <code>startPc</code> |
||||
* @param end <code>endPc</code> |
||||
* @param handler <code>handlerPc</code> |
||||
* @param type <code>catchType</code> |
||||
*/ |
||||
public void add(int index, int start, int end, int handler, int type) { |
||||
if (start < end) |
||||
entries.add(index, |
||||
new ExceptionTableEntry(start, end, handler, type)); |
||||
} |
||||
|
||||
/** |
||||
* Appends a new entry at the end of the table. |
||||
* |
||||
* @param start <code>startPc</code> |
||||
* @param end <code>endPc</code> |
||||
* @param handler <code>handlerPc</code> |
||||
* @param type <code>catchType</code> |
||||
*/ |
||||
public void add(int start, int end, int handler, int type) { |
||||
if (start < end) |
||||
entries.add(new ExceptionTableEntry(start, end, handler, type)); |
||||
} |
||||
|
||||
/** |
||||
* Removes the entry at the specified position in the table. |
||||
* |
||||
* @param index the index of the removed entry. |
||||
*/ |
||||
public void remove(int index) { |
||||
entries.remove(index); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy of this <code>exception_table[]</code>. |
||||
* Class names are replaced according to the |
||||
* given <code>Map</code> object. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
*/ |
||||
public ExceptionTable copy(com.fr.third.javassist.bytecode.ConstPool newCp, Map classnames) { |
||||
ExceptionTable et = new ExceptionTable(newCp); |
||||
ConstPool srcCp = constPool; |
||||
int len = size(); |
||||
for (int i = 0; i < len; ++i) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(i); |
||||
int type = srcCp.copy(e.catchType, newCp, classnames); |
||||
et.add(e.startPc, e.endPc, e.handlerPc, type); |
||||
} |
||||
|
||||
return et; |
||||
} |
||||
|
||||
void shiftPc(int where, int gapLength, boolean exclusive) { |
||||
int len = size(); |
||||
for (int i = 0; i < len; ++i) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(i); |
||||
e.startPc = shiftPc(e.startPc, where, gapLength, exclusive); |
||||
e.endPc = shiftPc(e.endPc, where, gapLength, exclusive); |
||||
e.handlerPc = shiftPc(e.handlerPc, where, gapLength, exclusive); |
||||
} |
||||
} |
||||
|
||||
private static int shiftPc(int pc, int where, int gapLength, |
||||
boolean exclusive) { |
||||
if (pc > where || (exclusive && pc == where)) |
||||
pc += gapLength; |
||||
|
||||
return pc; |
||||
} |
||||
|
||||
void write(DataOutputStream out) throws IOException { |
||||
int len = size(); |
||||
out.writeShort(len); // exception_table_length
|
||||
for (int i = 0; i < len; ++i) { |
||||
ExceptionTableEntry e = (ExceptionTableEntry)entries.get(i); |
||||
out.writeShort(e.startPc); |
||||
out.writeShort(e.endPc); |
||||
out.writeShort(e.handlerPc); |
||||
out.writeShort(e.catchType); |
||||
} |
||||
} |
||||
} |
@ -1,174 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <code>Exceptions_attribute</code>. |
||||
*/ |
||||
public class ExceptionsAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"Exceptions"</code>. |
||||
*/ |
||||
public static final String tag = "Exceptions"; |
||||
|
||||
ExceptionsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a copy of an exceptions attribute. |
||||
* |
||||
* @param cp constant pool table. |
||||
* @param src source attribute. |
||||
*/ |
||||
private ExceptionsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, ExceptionsAttribute src, |
||||
Map classnames) { |
||||
super(cp, tag); |
||||
copyFrom(src, classnames); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a new exceptions attribute. |
||||
* |
||||
* @param cp constant pool table. |
||||
*/ |
||||
public ExceptionsAttribute(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
super(cp, tag); |
||||
byte[] data = new byte[2]; |
||||
data[0] = data[1] = 0; // empty
|
||||
this.info = data; |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. Class names are replaced according to the |
||||
* given <code>Map</code> object. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. It can be <code>null</code>. |
||||
*/ |
||||
public AttributeInfo copy(com.fr.third.javassist.bytecode.ConstPool newCp, Map classnames) { |
||||
return new ExceptionsAttribute(newCp, this, classnames); |
||||
} |
||||
|
||||
/** |
||||
* Copies the contents from a source attribute. |
||||
* Specified class names are replaced during the copy. |
||||
* |
||||
* @param srcAttr source Exceptions attribute |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
*/ |
||||
private void copyFrom(ExceptionsAttribute srcAttr, Map classnames) { |
||||
com.fr.third.javassist.bytecode.ConstPool srcCp = srcAttr.constPool; |
||||
ConstPool destCp = this.constPool; |
||||
byte[] src = srcAttr.info; |
||||
int num = src.length; |
||||
byte[] dest = new byte[num]; |
||||
dest[0] = src[0]; |
||||
dest[1] = src[1]; // the number of elements.
|
||||
for (int i = 2; i < num; i += 2) { |
||||
int index = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, i); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(srcCp.copy(index, destCp, classnames), |
||||
dest, i); |
||||
} |
||||
|
||||
this.info = dest; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>exception_index_table[]</code>. |
||||
*/ |
||||
public int[] getExceptionIndexes() { |
||||
byte[] blist = info; |
||||
int n = blist.length; |
||||
if (n <= 2) |
||||
return null; |
||||
|
||||
int[] elist = new int[n / 2 - 1]; |
||||
int k = 0; |
||||
for (int j = 2; j < n; j += 2) |
||||
elist[k++] = ((blist[j] & 0xff) << 8) | (blist[j + 1] & 0xff); |
||||
|
||||
return elist; |
||||
} |
||||
|
||||
/** |
||||
* Returns the names of exceptions that the method may throw. |
||||
*/ |
||||
public String[] getExceptions() { |
||||
byte[] blist = info; |
||||
int n = blist.length; |
||||
if (n <= 2) |
||||
return null; |
||||
|
||||
String[] elist = new String[n / 2 - 1]; |
||||
int k = 0; |
||||
for (int j = 2; j < n; j += 2) { |
||||
int index = ((blist[j] & 0xff) << 8) | (blist[j + 1] & 0xff); |
||||
elist[k++] = constPool.getClassInfo(index); |
||||
} |
||||
|
||||
return elist; |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>exception_index_table[]</code>. |
||||
*/ |
||||
public void setExceptionIndexes(int[] elist) { |
||||
int n = elist.length; |
||||
byte[] blist = new byte[n * 2 + 2]; |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(n, blist, 0); |
||||
for (int i = 0; i < n; ++i) |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(elist[i], blist, i * 2 + 2); |
||||
|
||||
info = blist; |
||||
} |
||||
|
||||
/** |
||||
* Sets the names of exceptions that the method may throw. |
||||
*/ |
||||
public void setExceptions(String[] elist) { |
||||
int n = elist.length; |
||||
byte[] blist = new byte[n * 2 + 2]; |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(n, blist, 0); |
||||
for (int i = 0; i < n; ++i) |
||||
ByteArray.write16bit(constPool.addClassInfo(elist[i]), |
||||
blist, i * 2 + 2); |
||||
|
||||
info = blist; |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>number_of_exceptions</code>. |
||||
*/ |
||||
public int tableLength() { return info.length / 2 - 1; } |
||||
|
||||
/** |
||||
* Returns the value of <code>exception_index_table[nth]</code>. |
||||
*/ |
||||
public int getException(int nth) { |
||||
int index = nth * 2 + 2; // nth >= 0
|
||||
return ((info[index] & 0xff) << 8) | (info[index + 1] & 0xff); |
||||
} |
||||
} |
@ -1,269 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import com.fr.third.javassist.CtField; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.DataOutputStream; |
||||
import java.io.IOException; |
||||
import java.util.List; |
||||
import java.util.ArrayList; |
||||
|
||||
/** |
||||
* <code>field_info</code> structure. |
||||
* |
||||
* @see CtField#getFieldInfo() |
||||
*/ |
||||
public final class FieldInfo { |
||||
com.fr.third.javassist.bytecode.ConstPool constPool; |
||||
int accessFlags; |
||||
int name; |
||||
String cachedName; |
||||
String cachedType; |
||||
int descriptor; |
||||
ArrayList attribute; // may be null.
|
||||
|
||||
private FieldInfo(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
constPool = cp; |
||||
accessFlags = 0; |
||||
attribute = null; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a <code>field_info</code> structure. |
||||
* |
||||
* @param cp a constant pool table |
||||
* @param fieldName field name |
||||
* @param desc field descriptor |
||||
* |
||||
* @see Descriptor |
||||
*/ |
||||
public FieldInfo(com.fr.third.javassist.bytecode.ConstPool cp, String fieldName, String desc) { |
||||
this(cp); |
||||
name = cp.addUtf8Info(fieldName); |
||||
cachedName = fieldName; |
||||
descriptor = cp.addUtf8Info(desc); |
||||
} |
||||
|
||||
FieldInfo(com.fr.third.javassist.bytecode.ConstPool cp, DataInputStream in) throws IOException { |
||||
this(cp); |
||||
read(in); |
||||
} |
||||
|
||||
/** |
||||
* Returns a string representation of the object. |
||||
*/ |
||||
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(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
name = cp.addUtf8Info(getName()); |
||||
descriptor = cp.addUtf8Info(getDescriptor()); |
||||
attribute = AttributeInfo.copyAll(attribute, cp); |
||||
constPool = cp; |
||||
} |
||||
|
||||
void prune(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
ArrayList 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 signature |
||||
= getAttribute(SignatureAttribute.tag); |
||||
if (signature != null) { |
||||
signature = signature.copy(cp, null); |
||||
newAttributes.add(signature); |
||||
} |
||||
|
||||
int index = getConstantValue(); |
||||
if (index != 0) { |
||||
index = constPool.copy(index, cp, null); |
||||
newAttributes.add(new ConstantAttribute(cp, index)); |
||||
} |
||||
|
||||
attribute = newAttributes; |
||||
name = cp.addUtf8Info(getName()); |
||||
descriptor = cp.addUtf8Info(getDescriptor()); |
||||
constPool = cp; |
||||
} |
||||
|
||||
/** |
||||
* Returns the constant pool table used |
||||
* by this <code>field_info</code>. |
||||
*/ |
||||
public ConstPool getConstPool() { |
||||
return constPool; |
||||
} |
||||
|
||||
/** |
||||
* Returns the field name. |
||||
*/ |
||||
public String getName() { |
||||
if (cachedName == null) |
||||
cachedName = constPool.getUtf8Info(name); |
||||
|
||||
return cachedName; |
||||
} |
||||
|
||||
/** |
||||
* Sets the field name. |
||||
*/ |
||||
public void setName(String newName) { |
||||
name = constPool.addUtf8Info(newName); |
||||
cachedName = newName; |
||||
} |
||||
|
||||
/** |
||||
* Returns the access flags. |
||||
* |
||||
* @see AccessFlag |
||||
*/ |
||||
public int getAccessFlags() { |
||||
return accessFlags; |
||||
} |
||||
|
||||
/** |
||||
* Sets the access flags. |
||||
* |
||||
* @see AccessFlag |
||||
*/ |
||||
public void setAccessFlags(int acc) { |
||||
accessFlags = acc; |
||||
} |
||||
|
||||
/** |
||||
* Returns the field descriptor. |
||||
* |
||||
* @see Descriptor |
||||
*/ |
||||
public String getDescriptor() { |
||||
return constPool.getUtf8Info(descriptor); |
||||
} |
||||
|
||||
/** |
||||
* Sets the field descriptor. |
||||
* |
||||
* @see Descriptor |
||||
*/ |
||||
public void setDescriptor(String desc) { |
||||
if (!desc.equals(getDescriptor())) |
||||
descriptor = constPool.addUtf8Info(desc); |
||||
} |
||||
|
||||
/** |
||||
* Finds a ConstantValue attribute and returns the index into |
||||
* the <code>constant_pool</code> table. |
||||
* |
||||
* @return 0 if a ConstantValue attribute is not found. |
||||
*/ |
||||
public int getConstantValue() { |
||||
if ((accessFlags & AccessFlag.STATIC) == 0) |
||||
return 0; |
||||
|
||||
ConstantAttribute attr |
||||
= (ConstantAttribute)getAttribute(ConstantAttribute.tag); |
||||
if (attr == null) |
||||
return 0; |
||||
else |
||||
return attr.getConstantValue(); |
||||
} |
||||
|
||||
/** |
||||
* Returns all the attributes. The returned <code>List</code> object |
||||
* is shared with this object. If you add a new attribute to the list, |
||||
* the attribute is also added to the field represented by this |
||||
* object. If you remove an attribute from the list, it is also removed |
||||
* from the field. |
||||
* |
||||
* @return a list of <code>AttributeInfo</code> objects. |
||||
* @see AttributeInfo |
||||
*/ |
||||
public List getAttributes() { |
||||
if (attribute == null) |
||||
attribute = new ArrayList(); |
||||
|
||||
return attribute; |
||||
} |
||||
|
||||
/** |
||||
* Returns the attribute with the specified name. |
||||
* It returns null if the specified attribute is not found. |
||||
* |
||||
* @param name attribute name |
||||
* @see #getAttributes() |
||||
*/ |
||||
public AttributeInfo getAttribute(String name) { |
||||
return AttributeInfo.lookup(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); |
||||
} |
||||
|
||||
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); |
||||
} |
||||
} |
||||
} |
@ -1,242 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.util.Map; |
||||
import java.io.IOException; |
||||
|
||||
/** |
||||
* <code>InnerClasses_attribute</code>. |
||||
*/ |
||||
public class InnerClassesAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"InnerClasses"</code>. |
||||
*/ |
||||
public static final String tag = "InnerClasses"; |
||||
|
||||
InnerClassesAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
private InnerClassesAttribute(com.fr.third.javassist.bytecode.ConstPool cp, byte[] info) { |
||||
super(cp, tag, info); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an empty InnerClasses attribute. |
||||
* |
||||
* @see #append(String, String, String, int) |
||||
*/ |
||||
public InnerClassesAttribute(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
super(cp, tag, new byte[2]); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(0, get(), 0); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>number_of_classes</code>. |
||||
*/ |
||||
public int tableLength() { return com.fr.third.javassist.bytecode.ByteArray.readU16bit(get(), 0); } |
||||
|
||||
/** |
||||
* Returns <code>classes[nth].inner_class_info_index</code>. |
||||
*/ |
||||
public int innerClassIndex(int nth) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(get(), nth * 8 + 2); |
||||
} |
||||
|
||||
/** |
||||
* Returns the class name indicated |
||||
* by <code>classes[nth].inner_class_info_index</code>. |
||||
* |
||||
* @return null or the class name. |
||||
*/ |
||||
public String innerClass(int nth) { |
||||
int i = innerClassIndex(nth); |
||||
if (i == 0) |
||||
return null; |
||||
else |
||||
return constPool.getClassInfo(i); |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>classes[nth].inner_class_info_index</code> to |
||||
* the given index. |
||||
*/ |
||||
public void setInnerClassIndex(int nth, int index) { |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(index, get(), nth * 8 + 2); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>classes[nth].outer_class_info_index</code>. |
||||
*/ |
||||
public int outerClassIndex(int nth) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(get(), nth * 8 + 4); |
||||
} |
||||
|
||||
/** |
||||
* Returns the class name indicated |
||||
* by <code>classes[nth].outer_class_info_index</code>. |
||||
* |
||||
* @return null or the class name. |
||||
*/ |
||||
public String outerClass(int nth) { |
||||
int i = outerClassIndex(nth); |
||||
if (i == 0) |
||||
return null; |
||||
else |
||||
return constPool.getClassInfo(i); |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>classes[nth].outer_class_info_index</code> to |
||||
* the given index. |
||||
*/ |
||||
public void setOuterClassIndex(int nth, int index) { |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(index, get(), nth * 8 + 4); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>classes[nth].inner_name_index</code>. |
||||
*/ |
||||
public int innerNameIndex(int nth) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(get(), nth * 8 + 6); |
||||
} |
||||
|
||||
/** |
||||
* Returns the simple class name indicated |
||||
* by <code>classes[nth].inner_name_index</code>. |
||||
* |
||||
* @return null or the class name. |
||||
*/ |
||||
public String innerName(int nth) { |
||||
int i = innerNameIndex(nth); |
||||
if (i == 0) |
||||
return null; |
||||
else |
||||
return constPool.getUtf8Info(i); |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>classes[nth].inner_name_index</code> to |
||||
* the given index. |
||||
*/ |
||||
public void setInnerNameIndex(int nth, int index) { |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(index, get(), nth * 8 + 6); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>classes[nth].inner_class_access_flags</code>. |
||||
*/ |
||||
public int accessFlags(int nth) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(get(), nth * 8 + 8); |
||||
} |
||||
|
||||
/** |
||||
* Sets <code>classes[nth].inner_class_access_flags</code> to |
||||
* the given index. |
||||
*/ |
||||
public void setAccessFlags(int nth, int flags) { |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(flags, get(), nth * 8 + 8); |
||||
} |
||||
|
||||
/** |
||||
* Appends a new entry. |
||||
* |
||||
* @param inner <code>inner_class_info_index</code> |
||||
* @param outer <code>outer_class_info_index</code> |
||||
* @param name <code>inner_name_index</code> |
||||
* @param flags <code>inner_class_access_flags</code> |
||||
*/ |
||||
public void append(String inner, String outer, String name, int flags) { |
||||
int i = constPool.addClassInfo(inner); |
||||
int o = constPool.addClassInfo(outer); |
||||
int n = constPool.addUtf8Info(name); |
||||
append(i, o, n, flags); |
||||
} |
||||
|
||||
/** |
||||
* Appends a new entry. |
||||
* |
||||
* @param inner <code>inner_class_info_index</code> |
||||
* @param outer <code>outer_class_info_index</code> |
||||
* @param name <code>inner_name_index</code> |
||||
* @param flags <code>inner_class_access_flags</code> |
||||
*/ |
||||
public void append(int inner, int outer, int name, int flags) { |
||||
byte[] data = get(); |
||||
int len = data.length; |
||||
byte[] newData = new byte[len + 8]; |
||||
for (int i = 2; i < len; ++i) |
||||
newData[i] = data[i]; |
||||
|
||||
int n = com.fr.third.javassist.bytecode.ByteArray.readU16bit(data, 0); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(n + 1, newData, 0); |
||||
|
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(inner, newData, len); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(outer, newData, len + 2); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(name, newData, len + 4); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(flags, newData, len + 6); |
||||
|
||||
set(newData); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. Class names are replaced according to the |
||||
* given <code>Map</code> object. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
*/ |
||||
public AttributeInfo copy(com.fr.third.javassist.bytecode.ConstPool newCp, Map classnames) { |
||||
byte[] src = get(); |
||||
byte[] dest = new byte[src.length]; |
||||
ConstPool cp = getConstPool(); |
||||
InnerClassesAttribute attr = new InnerClassesAttribute(newCp, dest); |
||||
int n = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, 0); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(n, dest, 0); |
||||
int j = 2; |
||||
for (int i = 0; i < n; ++i) { |
||||
int innerClass = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, j); |
||||
int outerClass = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, j + 2); |
||||
int innerName = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, j + 4); |
||||
int innerAccess = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, j + 6); |
||||
|
||||
if (innerClass != 0) |
||||
innerClass = cp.copy(innerClass, newCp, classnames); |
||||
|
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(innerClass, dest, j); |
||||
|
||||
if (outerClass != 0) |
||||
outerClass = cp.copy(outerClass, newCp, classnames); |
||||
|
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(outerClass, dest, j + 2); |
||||
|
||||
if (innerName != 0) |
||||
innerName = cp.copy(innerName, newCp, classnames); |
||||
|
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(innerName, dest, j + 4); |
||||
ByteArray.write16bit(innerAccess, dest, j + 6); |
||||
j += 8; |
||||
} |
||||
|
||||
return attr; |
||||
} |
||||
} |
@ -1,295 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.PrintStream; |
||||
|
||||
import com.fr.third.javassist.CtMethod; |
||||
|
||||
/** |
||||
* Simple utility class for printing the bytecode instructions of a method. |
||||
* |
||||
* @author Jason T. Greene |
||||
*/ |
||||
public class InstructionPrinter implements Opcode { |
||||
|
||||
private final static String opcodes[] = Mnemonic.OPCODE; |
||||
private final PrintStream stream; |
||||
|
||||
/** |
||||
* Constructs a <code>InstructionPrinter</code> object. |
||||
*/ |
||||
public InstructionPrinter(PrintStream stream) { |
||||
this.stream = stream; |
||||
} |
||||
|
||||
/** |
||||
* Prints the bytecode instructions of a given method. |
||||
*/ |
||||
public static void print(CtMethod method, PrintStream stream) { |
||||
(new InstructionPrinter(stream)).print(method); |
||||
} |
||||
|
||||
/** |
||||
* Prints the bytecode instructions of a given method. |
||||
*/ |
||||
public void print(CtMethod method) { |
||||
MethodInfo info = method.getMethodInfo2(); |
||||
com.fr.third.javassist.bytecode.ConstPool pool = info.getConstPool(); |
||||
CodeAttribute code = info.getCodeAttribute(); |
||||
if (code == null) |
||||
return; |
||||
|
||||
com.fr.third.javassist.bytecode.CodeIterator iterator = code.iterator(); |
||||
while (iterator.hasNext()) { |
||||
int pos; |
||||
try { |
||||
pos = iterator.next(); |
||||
} catch (BadBytecode e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
stream.println(pos + ": " + instructionString(iterator, pos, pool)); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Gets a string representation of the bytecode instruction at the specified |
||||
* position. |
||||
*/ |
||||
public static String instructionString(com.fr.third.javassist.bytecode.CodeIterator iter, int pos, com.fr.third.javassist.bytecode.ConstPool pool) { |
||||
int opcode = iter.byteAt(pos); |
||||
|
||||
if (opcode > opcodes.length || opcode < 0) |
||||
throw new IllegalArgumentException("Invalid opcode, opcode: " + opcode + " pos: "+ pos); |
||||
|
||||
String opstring = opcodes[opcode]; |
||||
switch (opcode) { |
||||
case BIPUSH: |
||||
return opstring + " " + iter.byteAt(pos + 1); |
||||
case SIPUSH: |
||||
return opstring + " " + iter.s16bitAt(pos + 1); |
||||
case LDC: |
||||
return opstring + " " + ldc(pool, iter.byteAt(pos + 1)); |
||||
case LDC_W : |
||||
case LDC2_W : |
||||
return opstring + " " + ldc(pool, iter.u16bitAt(pos + 1)); |
||||
case ILOAD: |
||||
case LLOAD: |
||||
case FLOAD: |
||||
case DLOAD: |
||||
case ALOAD: |
||||
case ISTORE: |
||||
case LSTORE: |
||||
case FSTORE: |
||||
case DSTORE: |
||||
case ASTORE: |
||||
return opstring + " " + iter.byteAt(pos + 1); |
||||
case IFEQ: |
||||
case IFGE: |
||||
case IFGT: |
||||
case IFLE: |
||||
case IFLT: |
||||
case IFNE: |
||||
case IFNONNULL: |
||||
case IFNULL: |
||||
case IF_ACMPEQ: |
||||
case IF_ACMPNE: |
||||
case IF_ICMPEQ: |
||||
case IF_ICMPGE: |
||||
case IF_ICMPGT: |
||||
case IF_ICMPLE: |
||||
case IF_ICMPLT: |
||||
case IF_ICMPNE: |
||||
return opstring + " " + (iter.s16bitAt(pos + 1) + pos); |
||||
case IINC: |
||||
return opstring + " " + iter.byteAt(pos + 1); |
||||
case GOTO: |
||||
case JSR: |
||||
return opstring + " " + (iter.s16bitAt(pos + 1) + pos); |
||||
case RET: |
||||
return opstring + " " + iter.byteAt(pos + 1); |
||||
case TABLESWITCH: |
||||
return tableSwitch(iter, pos); |
||||
case LOOKUPSWITCH: |
||||
return lookupSwitch(iter, pos); |
||||
case GETSTATIC: |
||||
case PUTSTATIC: |
||||
case GETFIELD: |
||||
case PUTFIELD: |
||||
return opstring + " " + fieldInfo(pool, iter.u16bitAt(pos + 1)); |
||||
case INVOKEVIRTUAL: |
||||
case INVOKESPECIAL: |
||||
case INVOKESTATIC: |
||||
return opstring + " " + methodInfo(pool, iter.u16bitAt(pos + 1)); |
||||
case INVOKEINTERFACE: |
||||
return opstring + " " + interfaceMethodInfo(pool, iter.u16bitAt(pos + 1)); |
||||
case INVOKEDYNAMIC: |
||||
return opstring + " " + iter.u16bitAt(pos + 1); |
||||
case NEW: |
||||
return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1)); |
||||
case NEWARRAY: |
||||
return opstring + " " + arrayInfo(iter.byteAt(pos + 1)); |
||||
case ANEWARRAY: |
||||
case CHECKCAST: |
||||
return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1)); |
||||
case WIDE: |
||||
return wide(iter, pos); |
||||
case MULTIANEWARRAY: |
||||
return opstring + " " + classInfo(pool, iter.u16bitAt(pos + 1)); |
||||
case GOTO_W: |
||||
case JSR_W: |
||||
return opstring + " " + (iter.s32bitAt(pos + 1)+ pos); |
||||
default: |
||||
return opstring; |
||||
} |
||||
} |
||||
|
||||
|
||||
private static String wide(com.fr.third.javassist.bytecode.CodeIterator iter, int pos) { |
||||
int opcode = iter.byteAt(pos + 1); |
||||
int index = iter.u16bitAt(pos + 2); |
||||
switch (opcode) { |
||||
case ILOAD: |
||||
case LLOAD: |
||||
case FLOAD: |
||||
case DLOAD: |
||||
case ALOAD: |
||||
case ISTORE: |
||||
case LSTORE: |
||||
case FSTORE: |
||||
case DSTORE: |
||||
case ASTORE: |
||||
case IINC: |
||||
case RET: |
||||
return opcodes[opcode] + " " + index; |
||||
default: |
||||
throw new RuntimeException("Invalid WIDE operand"); |
||||
} |
||||
} |
||||
|
||||
|
||||
private static String arrayInfo(int type) { |
||||
switch (type) { |
||||
case T_BOOLEAN: |
||||
return "boolean"; |
||||
case T_CHAR: |
||||
return "char"; |
||||
case T_BYTE: |
||||
return "byte"; |
||||
case T_SHORT: |
||||
return "short"; |
||||
case T_INT: |
||||
return "int"; |
||||
case T_LONG: |
||||
return "long"; |
||||
case T_FLOAT: |
||||
return "float"; |
||||
case T_DOUBLE: |
||||
return "double"; |
||||
default: |
||||
throw new RuntimeException("Invalid array type"); |
||||
} |
||||
} |
||||
|
||||
|
||||
private static String classInfo(com.fr.third.javassist.bytecode.ConstPool pool, int index) { |
||||
return "#" + index + " = Class " + pool.getClassInfo(index); |
||||
} |
||||
|
||||
|
||||
private static String interfaceMethodInfo(com.fr.third.javassist.bytecode.ConstPool pool, int index) { |
||||
return "#" + index + " = Method " |
||||
+ pool.getInterfaceMethodrefClassName(index) + "." |
||||
+ pool.getInterfaceMethodrefName(index) + "(" |
||||
+ pool.getInterfaceMethodrefType(index) + ")"; |
||||
} |
||||
|
||||
private static String methodInfo(com.fr.third.javassist.bytecode.ConstPool pool, int index) { |
||||
return "#" + index + " = Method " |
||||
+ pool.getMethodrefClassName(index) + "." |
||||
+ pool.getMethodrefName(index) + "(" |
||||
+ pool.getMethodrefType(index) + ")"; |
||||
} |
||||
|
||||
|
||||
private static String fieldInfo(com.fr.third.javassist.bytecode.ConstPool pool, int index) { |
||||
return "#" + index + " = Field " |
||||
+ pool.getFieldrefClassName(index) + "." |
||||
+ pool.getFieldrefName(index) + "(" |
||||
+ pool.getFieldrefType(index) + ")"; |
||||
} |
||||
|
||||
|
||||
private static String lookupSwitch(com.fr.third.javassist.bytecode.CodeIterator iter, int pos) { |
||||
StringBuffer buffer = new StringBuffer("lookupswitch {\n"); |
||||
int index = (pos & ~3) + 4; |
||||
// default
|
||||
buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n"); |
||||
int npairs = iter.s32bitAt(index += 4); |
||||
int end = npairs * 8 + (index += 4); |
||||
|
||||
for (; index < end; index += 8) { |
||||
int match = iter.s32bitAt(index); |
||||
int target = iter.s32bitAt(index + 4) + pos; |
||||
buffer.append("\t\t").append(match).append(": ").append(target).append("\n"); |
||||
} |
||||
|
||||
buffer.setCharAt(buffer.length() - 1, '}'); |
||||
return buffer.toString(); |
||||
} |
||||
|
||||
|
||||
private static String tableSwitch(CodeIterator iter, int pos) { |
||||
StringBuffer buffer = new StringBuffer("tableswitch {\n"); |
||||
int index = (pos & ~3) + 4; |
||||
// default
|
||||
buffer.append("\t\tdefault: ").append(pos + iter.s32bitAt(index)).append("\n"); |
||||
int low = iter.s32bitAt(index += 4); |
||||
int high = iter.s32bitAt(index += 4); |
||||
int end = (high - low + 1) * 4 + (index += 4); |
||||
|
||||
// Offset table
|
||||
for (int key = low; index < end; index += 4, key++) { |
||||
int target = iter.s32bitAt(index) + pos; |
||||
buffer.append("\t\t").append(key).append(": ").append(target).append("\n"); |
||||
} |
||||
|
||||
buffer.setCharAt(buffer.length() - 1, '}'); |
||||
return buffer.toString(); |
||||
} |
||||
|
||||
|
||||
private static String ldc(com.fr.third.javassist.bytecode.ConstPool pool, int index) { |
||||
int tag = pool.getTag(index); |
||||
switch (tag) { |
||||
case com.fr.third.javassist.bytecode.ConstPool.CONST_String: |
||||
return "#" + index + " = \"" + pool.getStringInfo(index) + "\""; |
||||
case com.fr.third.javassist.bytecode.ConstPool.CONST_Integer: |
||||
return "#" + index + " = int " + pool.getIntegerInfo(index); |
||||
case com.fr.third.javassist.bytecode.ConstPool.CONST_Float: |
||||
return "#" + index + " = float " + pool.getFloatInfo(index); |
||||
case com.fr.third.javassist.bytecode.ConstPool.CONST_Long: |
||||
return "#" + index + " = long " + pool.getLongInfo(index); |
||||
case com.fr.third.javassist.bytecode.ConstPool.CONST_Double: |
||||
return "#" + index + " = int " + pool.getDoubleInfo(index); |
||||
case ConstPool.CONST_Class: |
||||
return classInfo(pool, index); |
||||
default: |
||||
throw new RuntimeException("bad LDC: " + tag); |
||||
} |
||||
} |
||||
} |
@ -1,182 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <code>LineNumberTable_attribute</code>. |
||||
*/ |
||||
public class LineNumberAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"LineNumberTable"</code>. |
||||
*/ |
||||
public static final String tag = "LineNumberTable"; |
||||
|
||||
LineNumberAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
private LineNumberAttribute(com.fr.third.javassist.bytecode.ConstPool cp, byte[] i) { |
||||
super(cp, tag, i); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>line_number_table_length</code>. |
||||
* This represents the number of entries in the table. |
||||
*/ |
||||
public int tableLength() { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, 0); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>line_number_table[i].start_pc</code>. |
||||
* This represents the index into the code array at which the code |
||||
* for a new line in the original source file begins. |
||||
* |
||||
* @param i the i-th entry. |
||||
*/ |
||||
public int startPc(int i) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, i * 4 + 2); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>line_number_table[i].line_number</code>. |
||||
* This represents the corresponding line number in the original |
||||
* source file. |
||||
* |
||||
* @param i the i-th entry. |
||||
*/ |
||||
public int lineNumber(int i) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, i * 4 + 4); |
||||
} |
||||
|
||||
/** |
||||
* Returns the line number corresponding to the specified bytecode. |
||||
* |
||||
* @param pc the index into the code array. |
||||
*/ |
||||
public int toLineNumber(int pc) { |
||||
int n = tableLength(); |
||||
int i = 0; |
||||
for (; i < n; ++i) |
||||
if (pc < startPc(i)) |
||||
if (i == 0) |
||||
return lineNumber(0); |
||||
else |
||||
break; |
||||
|
||||
return lineNumber(i - 1); |
||||
} |
||||
|
||||
/** |
||||
* Returns the index into the code array at which the code for |
||||
* the specified line begins. |
||||
* |
||||
* @param line the line number. |
||||
* @return -1 if the specified line is not found. |
||||
*/ |
||||
public int toStartPc(int line) { |
||||
int n = tableLength(); |
||||
for (int i = 0; i < n; ++i) |
||||
if (line == lineNumber(i)) |
||||
return startPc(i); |
||||
|
||||
return -1; |
||||
} |
||||
|
||||
/** |
||||
* Used as a return type of <code>toNearPc()</code>. |
||||
*/ |
||||
static public class Pc { |
||||
/** |
||||
* The index into the code array. |
||||
*/ |
||||
public int index; |
||||
/** |
||||
* The line number. |
||||
*/ |
||||
public int line; |
||||
} |
||||
|
||||
/** |
||||
* Returns the index into the code array at which the code for |
||||
* the specified line (or the nearest line after the specified one) |
||||
* begins. |
||||
* |
||||
* @param line the line number. |
||||
* @return a pair of the index and the line number of the |
||||
* bytecode at that index. |
||||
*/ |
||||
public Pc toNearPc(int line) { |
||||
int n = tableLength(); |
||||
int nearPc = 0; |
||||
int distance = 0; |
||||
if (n > 0) { |
||||
distance = lineNumber(0) - line; |
||||
nearPc = startPc(0); |
||||
} |
||||
|
||||
for (int i = 1; i < n; ++i) { |
||||
int d = lineNumber(i) - line; |
||||
if ((d < 0 && d > distance) |
||||
|| (d >= 0 && (d < distance || distance < 0))) { |
||||
distance = d; |
||||
nearPc = startPc(i); |
||||
} |
||||
} |
||||
|
||||
Pc res = new Pc(); |
||||
res.index = nearPc; |
||||
res.line = line + distance; |
||||
return res; |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames should be null. |
||||
*/ |
||||
public AttributeInfo copy(ConstPool newCp, Map classnames) { |
||||
byte[] src = info; |
||||
int num = src.length; |
||||
byte[] dest = new byte[num]; |
||||
for (int i = 0; i < num; ++i) |
||||
dest[i] = src[i]; |
||||
|
||||
LineNumberAttribute attr = new LineNumberAttribute(newCp, dest); |
||||
return attr; |
||||
} |
||||
|
||||
/** |
||||
* Adjusts start_pc if bytecode is inserted in a method body. |
||||
*/ |
||||
void shiftPc(int where, int gapLength, boolean exclusive) { |
||||
int n = tableLength(); |
||||
for (int i = 0; i < n; ++i) { |
||||
int pos = i * 4 + 2; |
||||
int pc = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos); |
||||
if (pc > where || (exclusive && pc == where)) |
||||
ByteArray.write16bit(pc + gapLength, info, pos); |
||||
} |
||||
} |
||||
} |
@ -1,334 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <code>LocalVariableTable_attribute</code>. |
||||
*/ |
||||
public class LocalVariableAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"LocalVariableTable"</code>. |
||||
*/ |
||||
public static final String tag = "LocalVariableTable"; |
||||
|
||||
/** |
||||
* The name of the attribute <code>"LocalVariableTypeTable"</code>. |
||||
*/ |
||||
public static final String typeTag = "LocalVariableTypeTable"; |
||||
|
||||
/** |
||||
* Constructs an empty LocalVariableTable. |
||||
*/ |
||||
public LocalVariableAttribute(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
super(cp, tag, new byte[2]); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(0, info, 0); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an empty LocalVariableTable. |
||||
* |
||||
* @param name the attribute name. |
||||
* <code>LocalVariableAttribute.tag</code> or |
||||
* <code>LocalVariableAttribute.typeTag</code>. |
||||
* @see #tag |
||||
* @see #typeTag |
||||
* @since 3.1 |
||||
* @deprecated |
||||
*/ |
||||
public LocalVariableAttribute(com.fr.third.javassist.bytecode.ConstPool cp, String name) { |
||||
super(cp, name, new byte[2]); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(0, info, 0); |
||||
} |
||||
|
||||
LocalVariableAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
LocalVariableAttribute(com.fr.third.javassist.bytecode.ConstPool cp, String name, byte[] i) { |
||||
super(cp, name, i); |
||||
} |
||||
|
||||
/** |
||||
* Appends a new entry to <code>local_variable_table</code>. |
||||
* |
||||
* @param startPc <code>start_pc</code> |
||||
* @param length <code>length</code> |
||||
* @param nameIndex <code>name_index</code> |
||||
* @param descriptorIndex <code>descriptor_index</code> |
||||
* @param index <code>index</code> |
||||
*/ |
||||
public void addEntry(int startPc, int length, int nameIndex, |
||||
int descriptorIndex, int index) { |
||||
int size = info.length; |
||||
byte[] newInfo = new byte[size + 10]; |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(tableLength() + 1, newInfo, 0); |
||||
for (int i = 2; i < size; ++i) |
||||
newInfo[i] = info[i]; |
||||
|
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(startPc, newInfo, size); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(length, newInfo, size + 2); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(nameIndex, newInfo, size + 4); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(descriptorIndex, newInfo, size + 6); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(index, newInfo, size + 8); |
||||
info = newInfo; |
||||
} |
||||
|
||||
void renameClass(String oldname, String newname) { |
||||
com.fr.third.javassist.bytecode.ConstPool cp = getConstPool(); |
||||
int n = tableLength(); |
||||
for (int i = 0; i < n; ++i) { |
||||
int pos = i * 10 + 2; |
||||
int index = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos + 6); |
||||
if (index != 0) { |
||||
String desc = cp.getUtf8Info(index); |
||||
desc = renameEntry(desc, oldname, newname); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(cp.addUtf8Info(desc), info, pos + 6); |
||||
} |
||||
} |
||||
} |
||||
|
||||
String renameEntry(String desc, String oldname, String newname) { |
||||
return com.fr.third.javassist.bytecode.Descriptor.rename(desc, oldname, newname); |
||||
} |
||||
|
||||
void renameClass(Map classnames) { |
||||
com.fr.third.javassist.bytecode.ConstPool cp = getConstPool(); |
||||
int n = tableLength(); |
||||
for (int i = 0; i < n; ++i) { |
||||
int pos = i * 10 + 2; |
||||
int index = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos + 6); |
||||
if (index != 0) { |
||||
String desc = cp.getUtf8Info(index); |
||||
desc = renameEntry(desc, classnames); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(cp.addUtf8Info(desc), info, pos + 6); |
||||
} |
||||
} |
||||
} |
||||
|
||||
String renameEntry(String desc, Map classnames) { |
||||
return com.fr.third.javassist.bytecode.Descriptor.rename(desc, classnames); |
||||
} |
||||
|
||||
/** |
||||
* For each <code>local_variable_table[i].index</code>, |
||||
* this method increases <code>index</code> by <code>delta</code>. |
||||
* |
||||
* @param lessThan the index does not change if it |
||||
* is less than this value. |
||||
*/ |
||||
public void shiftIndex(int lessThan, int delta) { |
||||
int size = info.length; |
||||
for (int i = 2; i < size; i += 10){ |
||||
int org = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, i + 8); |
||||
if (org >= lessThan) |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(org + delta, info, i + 8); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>local_variable_table_length</code>. |
||||
* This represents the number of entries in the table. |
||||
*/ |
||||
public int tableLength() { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, 0); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>local_variable_table[i].start_pc</code>. |
||||
* This represents the index into the code array from which the local |
||||
* variable is effective. |
||||
* |
||||
* @param i the i-th entry. |
||||
*/ |
||||
public int startPc(int i) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, i * 10 + 2); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>local_variable_table[i].length</code>. |
||||
* This represents the length of the code region in which the local |
||||
* variable is effective. |
||||
* |
||||
* @param i the i-th entry. |
||||
*/ |
||||
public int codeLength(int i) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, i * 10 + 4); |
||||
} |
||||
|
||||
/** |
||||
* Adjusts start_pc and length if bytecode is inserted in a method body. |
||||
*/ |
||||
void shiftPc(int where, int gapLength, boolean exclusive) { |
||||
int n = tableLength(); |
||||
for (int i = 0; i < n; ++i) { |
||||
int pos = i * 10 + 2; |
||||
int pc = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos); |
||||
int len = com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, pos + 2); |
||||
|
||||
/* if pc == 0, then the local variable is a method parameter. |
||||
*/ |
||||
if (pc > where || (exclusive && pc == where && pc != 0)) |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(pc + gapLength, info, pos); |
||||
else if (pc + len > where || (exclusive && pc + len == where)) |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(len + gapLength, info, pos + 2); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns the value of <code>local_variable_table[i].name_index</code>. |
||||
* This represents the name of the local variable. |
||||
* |
||||
* @param i the i-th entry. |
||||
*/ |
||||
public int nameIndex(int i) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, i * 10 + 6); |
||||
} |
||||
|
||||
/** |
||||
* Returns the name of the local variable |
||||
* specified by <code>local_variable_table[i].name_index</code>. |
||||
* |
||||
* @param i the i-th entry. |
||||
*/ |
||||
public String variableName(int i) { |
||||
return getConstPool().getUtf8Info(nameIndex(i)); |
||||
} |
||||
|
||||
/** |
||||
* Returns the value of |
||||
* <code>local_variable_table[i].descriptor_index</code>. |
||||
* This represents the type descriptor of the local variable. |
||||
* <p> |
||||
* If this attribute represents a LocalVariableTypeTable attribute, |
||||
* this method returns the value of |
||||
* <code>local_variable_type_table[i].signature_index</code>. |
||||
* It represents the type of the local variable. |
||||
* |
||||
* @param i the i-th entry. |
||||
*/ |
||||
public int descriptorIndex(int i) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, i * 10 + 8); |
||||
} |
||||
|
||||
/** |
||||
* This method is equivalent to <code>descriptorIndex()</code>. |
||||
* If this attribute represents a LocalVariableTypeTable attribute, |
||||
* this method should be used instead of <code>descriptorIndex()</code> |
||||
* since the method name is more appropriate. |
||||
* |
||||
* @param i the i-th entry. |
||||
* @see #descriptorIndex(int) |
||||
* @see com.fr.third.javassist.bytecode.SignatureAttribute#toFieldSignature(String) |
||||
*/ |
||||
public int signatureIndex(int i) { |
||||
return descriptorIndex(i); |
||||
} |
||||
|
||||
/** |
||||
* Returns the type descriptor of the local variable |
||||
* specified by <code>local_variable_table[i].descriptor_index</code>. |
||||
* <p> |
||||
* If this attribute represents a LocalVariableTypeTable attribute, |
||||
* this method returns the type signature of the local variable |
||||
* specified by <code>local_variable_type_table[i].signature_index</code>. |
||||
* |
||||
* @param i the i-th entry. |
||||
*/ |
||||
public String descriptor(int i) { |
||||
return getConstPool().getUtf8Info(descriptorIndex(i)); |
||||
} |
||||
|
||||
/** |
||||
* This method is equivalent to <code>descriptor()</code>. |
||||
* If this attribute represents a LocalVariableTypeTable attribute, |
||||
* this method should be used instead of <code>descriptor()</code> |
||||
* since the method name is more appropriate. |
||||
* |
||||
* <p>To parse the string, call <code>toFieldSignature(String)</code> |
||||
* in <code>SignatureAttribute</code>. |
||||
* |
||||
* @param i the i-th entry. |
||||
* @see #descriptor(int) |
||||
* @see SignatureAttribute#toFieldSignature(String) |
||||
*/ |
||||
public String signature(int i) { |
||||
return descriptor(i); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>local_variable_table[i].index</code>. |
||||
* This represents the index of the local variable. |
||||
* |
||||
* @param i the i-th entry. |
||||
*/ |
||||
public int index(int i) { |
||||
return com.fr.third.javassist.bytecode.ByteArray.readU16bit(info, i * 10 + 10); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames should be null. |
||||
*/ |
||||
public AttributeInfo copy(com.fr.third.javassist.bytecode.ConstPool newCp, Map classnames) { |
||||
byte[] src = get(); |
||||
byte[] dest = new byte[src.length]; |
||||
com.fr.third.javassist.bytecode.ConstPool cp = getConstPool(); |
||||
LocalVariableAttribute attr = makeThisAttr(newCp, dest); |
||||
int n = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, 0); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(n, dest, 0); |
||||
int j = 2; |
||||
for (int i = 0; i < n; ++i) { |
||||
int start = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, j); |
||||
int len = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, j + 2); |
||||
int name = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, j + 4); |
||||
int type = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, j + 6); |
||||
int index = com.fr.third.javassist.bytecode.ByteArray.readU16bit(src, j + 8); |
||||
|
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(start, dest, j); |
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(len, dest, j + 2); |
||||
if (name != 0) |
||||
name = cp.copy(name, newCp, null); |
||||
|
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(name, dest, j + 4); |
||||
|
||||
if (type != 0) { |
||||
String sig = cp.getUtf8Info(type); |
||||
sig = Descriptor.rename(sig, classnames); |
||||
type = newCp.addUtf8Info(sig); |
||||
} |
||||
|
||||
com.fr.third.javassist.bytecode.ByteArray.write16bit(type, dest, j + 6); |
||||
ByteArray.write16bit(index, dest, j + 8); |
||||
j += 10; |
||||
} |
||||
|
||||
return attr; |
||||
} |
||||
|
||||
// LocalVariableTypeAttribute overrides this method.
|
||||
LocalVariableAttribute makeThisAttr(ConstPool cp, byte[] dest) { |
||||
return new LocalVariableAttribute(cp, tag, dest); |
||||
} |
||||
} |
@ -1,63 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <code>LocalVariableTypeTable_attribute</code>. |
||||
* |
||||
* @since 3.11 |
||||
*/ |
||||
public class LocalVariableTypeAttribute extends com.fr.third.javassist.bytecode.LocalVariableAttribute { |
||||
/** |
||||
* The name of the attribute <code>"LocalVariableTypeTable"</code>. |
||||
*/ |
||||
public static final String tag = com.fr.third.javassist.bytecode.LocalVariableAttribute.typeTag; |
||||
|
||||
/** |
||||
* Constructs an empty LocalVariableTypeTable. |
||||
*/ |
||||
public LocalVariableTypeAttribute(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
super(cp, tag, new byte[2]); |
||||
ByteArray.write16bit(0, info, 0); |
||||
} |
||||
|
||||
LocalVariableTypeAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
private LocalVariableTypeAttribute(com.fr.third.javassist.bytecode.ConstPool cp, byte[] dest) { |
||||
super(cp, tag, dest); |
||||
} |
||||
|
||||
String renameEntry(String desc, String oldname, String newname) { |
||||
return com.fr.third.javassist.bytecode.SignatureAttribute.renameClass(desc, oldname, newname); |
||||
} |
||||
|
||||
String renameEntry(String desc, Map classnames) { |
||||
return SignatureAttribute.renameClass(desc, classnames); |
||||
} |
||||
|
||||
LocalVariableAttribute makeThisAttr(ConstPool cp, byte[] dest) { |
||||
return new LocalVariableTypeAttribute(cp, dest); |
||||
} |
||||
} |
@ -1,64 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
final class LongVector { |
||||
static final int ASIZE = 128; |
||||
static final int ABITS = 7; // ASIZE = 2^ABITS
|
||||
static final int VSIZE = 8; |
||||
private com.fr.third.javassist.bytecode.ConstInfo[][] objects; |
||||
private int elements; |
||||
|
||||
public LongVector() { |
||||
objects = new com.fr.third.javassist.bytecode.ConstInfo[VSIZE][]; |
||||
elements = 0; |
||||
} |
||||
|
||||
public LongVector(int initialSize) { |
||||
int vsize = ((initialSize >> ABITS) & ~(VSIZE - 1)) + VSIZE; |
||||
objects = new com.fr.third.javassist.bytecode.ConstInfo[vsize][]; |
||||
elements = 0; |
||||
} |
||||
|
||||
public int size() { return elements; } |
||||
|
||||
public int capacity() { return objects.length * ASIZE; } |
||||
|
||||
public com.fr.third.javassist.bytecode.ConstInfo elementAt(int i) { |
||||
if (i < 0 || elements <= i) |
||||
return null; |
||||
|
||||
return objects[i >> ABITS][i & (ASIZE - 1)]; |
||||
} |
||||
|
||||
public void addElement(com.fr.third.javassist.bytecode.ConstInfo value) { |
||||
int nth = elements >> ABITS; |
||||
int offset = elements & (ASIZE - 1); |
||||
int len = objects.length; |
||||
if (nth >= len) { |
||||
com.fr.third.javassist.bytecode.ConstInfo[][] newObj = new com.fr.third.javassist.bytecode.ConstInfo[len + VSIZE][]; |
||||
System.arraycopy(objects, 0, newObj, 0, len); |
||||
objects = newObj; |
||||
} |
||||
|
||||
if (objects[nth] == null) |
||||
objects[nth] = new com.fr.third.javassist.bytecode.ConstInfo[ASIZE]; |
||||
|
||||
objects[nth][offset] = value; |
||||
elements++; |
||||
} |
||||
} |
@ -1,551 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.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.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.CtConstructor; |
||||
import com.fr.third.javassist.CtMethod; |
||||
import com.fr.third.javassist.bytecode.stackmap.MapMaker; |
||||
|
||||
/** |
||||
* <code>method_info</code> structure. |
||||
* |
||||
* <p>The bytecode sequence of the method is represented |
||||
* by a <code>CodeAttribute</code> object. |
||||
* |
||||
* @see #getCodeAttribute() |
||||
* @see CodeAttribute |
||||
* @see CtMethod#getMethodInfo() |
||||
* @see CtConstructor#getMethodInfo() |
||||
*/ |
||||
public class MethodInfo { |
||||
com.fr.third.javassist.bytecode.ConstPool constPool; |
||||
int accessFlags; |
||||
int name; |
||||
String cachedName; |
||||
int descriptor; |
||||
ArrayList attribute; // may be null
|
||||
|
||||
/** |
||||
* If this value is true, Javassist maintains a <code>StackMap</code> attribute |
||||
* generated by the <code>preverify</code> tool of J2ME (CLDC). The initial |
||||
* value of this field is <code>false</code>. |
||||
*/ |
||||
public static boolean doPreverify = false; |
||||
|
||||
/** |
||||
* The name of constructors: <code><init></code>. |
||||
*/ |
||||
public static final String nameInit = "<init>"; |
||||
|
||||
/** |
||||
* The name of class initializer (static initializer): |
||||
* <code><clinit></code>. |
||||
*/ |
||||
public static final String nameClinit = "<clinit>"; |
||||
|
||||
private MethodInfo(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
constPool = cp; |
||||
attribute = null; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a <code>method_info</code> structure. The initial value of |
||||
* <code>access_flags</code> is zero. |
||||
* |
||||
* @param cp |
||||
* a constant pool table |
||||
* @param methodname |
||||
* method name |
||||
* @param desc |
||||
* method descriptor |
||||
* @see com.fr.third.javassist.bytecode.Descriptor |
||||
*/ |
||||
public MethodInfo(com.fr.third.javassist.bytecode.ConstPool cp, String methodname, String desc) { |
||||
this(cp); |
||||
accessFlags = 0; |
||||
name = cp.addUtf8Info(methodname); |
||||
cachedName = methodname; |
||||
descriptor = constPool.addUtf8Info(desc); |
||||
} |
||||
|
||||
MethodInfo(com.fr.third.javassist.bytecode.ConstPool cp, DataInputStream in) throws IOException { |
||||
this(cp); |
||||
read(in); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a copy of <code>method_info</code> structure. Class names |
||||
* appearing in the source <code>method_info</code> are renamed according |
||||
* to <code>classnameMap</code>. |
||||
* |
||||
* <p> |
||||
* Note: only <code>Code</code> and <code>Exceptions</code> 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 <code>method_info</code> |
||||
* @param classnameMap |
||||
* specifies pairs of replaced and substituted name. |
||||
* @see com.fr.third.javassist.bytecode.Descriptor |
||||
*/ |
||||
public MethodInfo(com.fr.third.javassist.bytecode.ConstPool cp, String methodname, MethodInfo src, |
||||
Map classnameMap) throws BadBytecode { |
||||
this(cp); |
||||
read(src, methodname, classnameMap); |
||||
} |
||||
|
||||
/** |
||||
* Returns a string representation of the object. |
||||
*/ |
||||
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(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
name = cp.addUtf8Info(getName()); |
||||
descriptor = cp.addUtf8Info(getDescriptor()); |
||||
attribute = AttributeInfo.copyAll(attribute, cp); |
||||
constPool = cp; |
||||
} |
||||
|
||||
void prune(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
ArrayList 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 com.fr.third.javassist.bytecode.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 com.fr.third.javassist.bytecode.AccessFlag |
||||
*/ |
||||
public int getAccessFlags() { |
||||
return accessFlags; |
||||
} |
||||
|
||||
/** |
||||
* Sets access flags. |
||||
* |
||||
* @see AccessFlag |
||||
*/ |
||||
public void setAccessFlags(int acc) { |
||||
accessFlags = acc; |
||||
} |
||||
|
||||
/** |
||||
* Returns a method descriptor. |
||||
* |
||||
* @see com.fr.third.javassist.bytecode.Descriptor |
||||
*/ |
||||
public String getDescriptor() { |
||||
return constPool.getUtf8Info(descriptor); |
||||
} |
||||
|
||||
/** |
||||
* Sets a method descriptor. |
||||
* |
||||
* @see com.fr.third.javassist.bytecode.Descriptor |
||||
*/ |
||||
public void setDescriptor(String desc) { |
||||
if (!desc.equals(getDescriptor())) |
||||
descriptor = constPool.addUtf8Info(desc); |
||||
} |
||||
|
||||
/** |
||||
* Returns all the attributes. The returned <code>List</code> 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 <code>AttributeInfo</code> 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. |
||||
* |
||||
* @param name attribute name |
||||
* @return an <code>AttributeInfo</code> object or null. |
||||
* @see #getAttributes() |
||||
*/ |
||||
public AttributeInfo getAttribute(String name) { |
||||
return AttributeInfo.lookup(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. |
||||
* |
||||
* <p> |
||||
* The added attribute must share the same constant pool table as this |
||||
* <code>method_info</code> 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. |
||||
* |
||||
* <p> |
||||
* The added attribute must share the same constant pool table as this |
||||
* <code>method_info</code> 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 <code>doPreverify</code> 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, com.fr.third.javassist.bytecode.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 <code>MethodInfo</code> 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 <code>MethodInfo</code> does not |
||||
* include a code attribute, nothing happens. |
||||
* |
||||
* @param pool used for making type hierarchy. |
||||
* @see com.fr.third.javassist.bytecode.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. |
||||
* |
||||
* <p> |
||||
* This method modifies a call to <code>super()</code>, 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. |
||||
* |
||||
* <p> |
||||
* This method should be called when the super class of the class declaring |
||||
* this method is changed. |
||||
* |
||||
* <p> |
||||
* This method does not perform anything unless this <code>MethodInfo</code> |
||||
* 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()
|
||||
com.fr.third.javassist.bytecode.ConstPool cp = constPool; |
||||
int mref = com.fr.third.javassist.bytecode.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) |
||||
throws BadBytecode { |
||||
com.fr.third.javassist.bytecode.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); |
||||
} |
||||
} |
||||
} |
@ -1,239 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
/** |
||||
* JVM Instruction Names. |
||||
* |
||||
* <p>This interface has been separated from javassist.bytecode.Opcode |
||||
* because typical bytecode translators do not use mnemonics. If this |
||||
* interface were merged with Opcode, extra memory would be unnecessary |
||||
* consumed. |
||||
* |
||||
* @see Opcode |
||||
*/ |
||||
public interface Mnemonic { |
||||
|
||||
/** |
||||
* The instruction names (mnemonics) sorted by the opcode. |
||||
* The length of this array is 202 (jsr_w=201). |
||||
*/ |
||||
String[] OPCODE = { |
||||
"nop", /* 0*/ |
||||
"aconst_null", /* 1*/ |
||||
"iconst_m1", /* 2*/ |
||||
"iconst_0", /* 3*/ |
||||
"iconst_1", /* 4*/ |
||||
"iconst_2", /* 5*/ |
||||
"iconst_3", /* 6*/ |
||||
"iconst_4", /* 7*/ |
||||
"iconst_5", /* 8*/ |
||||
"lconst_0", /* 9*/ |
||||
"lconst_1", /* 10*/ |
||||
"fconst_0", /* 11*/ |
||||
"fconst_1", /* 12*/ |
||||
"fconst_2", /* 13*/ |
||||
"dconst_0", /* 14*/ |
||||
"dconst_1", /* 15*/ |
||||
"bipush", /* 16*/ |
||||
"sipush", /* 17*/ |
||||
"ldc", /* 18*/ |
||||
"ldc_w", /* 19*/ |
||||
"ldc2_w", /* 20*/ |
||||
"iload", /* 21*/ |
||||
"lload", /* 22*/ |
||||
"fload", /* 23*/ |
||||
"dload", /* 24*/ |
||||
"aload", /* 25*/ |
||||
"iload_0", /* 26*/ |
||||
"iload_1", /* 27*/ |
||||
"iload_2", /* 28*/ |
||||
"iload_3", /* 29*/ |
||||
"lload_0", /* 30*/ |
||||
"lload_1", /* 31*/ |
||||
"lload_2", /* 32*/ |
||||
"lload_3", /* 33*/ |
||||
"fload_0", /* 34*/ |
||||
"fload_1", /* 35*/ |
||||
"fload_2", /* 36*/ |
||||
"fload_3", /* 37*/ |
||||
"dload_0", /* 38*/ |
||||
"dload_1", /* 39*/ |
||||
"dload_2", /* 40*/ |
||||
"dload_3", /* 41*/ |
||||
"aload_0", /* 42*/ |
||||
"aload_1", /* 43*/ |
||||
"aload_2", /* 44*/ |
||||
"aload_3", /* 45*/ |
||||
"iaload", /* 46*/ |
||||
"laload", /* 47*/ |
||||
"faload", /* 48*/ |
||||
"daload", /* 49*/ |
||||
"aaload", /* 50*/ |
||||
"baload", /* 51*/ |
||||
"caload", /* 52*/ |
||||
"saload", /* 53*/ |
||||
"istore", /* 54*/ |
||||
"lstore", /* 55*/ |
||||
"fstore", /* 56*/ |
||||
"dstore", /* 57*/ |
||||
"astore", /* 58*/ |
||||
"istore_0", /* 59*/ |
||||
"istore_1", /* 60*/ |
||||
"istore_2", /* 61*/ |
||||
"istore_3", /* 62*/ |
||||
"lstore_0", /* 63*/ |
||||
"lstore_1", /* 64*/ |
||||
"lstore_2", /* 65*/ |
||||
"lstore_3", /* 66*/ |
||||
"fstore_0", /* 67*/ |
||||
"fstore_1", /* 68*/ |
||||
"fstore_2", /* 69*/ |
||||
"fstore_3", /* 70*/ |
||||
"dstore_0", /* 71*/ |
||||
"dstore_1", /* 72*/ |
||||
"dstore_2", /* 73*/ |
||||
"dstore_3", /* 74*/ |
||||
"astore_0", /* 75*/ |
||||
"astore_1", /* 76*/ |
||||
"astore_2", /* 77*/ |
||||
"astore_3", /* 78*/ |
||||
"iastore", /* 79*/ |
||||
"lastore", /* 80*/ |
||||
"fastore", /* 81*/ |
||||
"dastore", /* 82*/ |
||||
"aastore", /* 83*/ |
||||
"bastore", /* 84*/ |
||||
"castore", /* 85*/ |
||||
"sastore", /* 86*/ |
||||
"pop", /* 87*/ |
||||
"pop2", /* 88*/ |
||||
"dup", /* 89*/ |
||||
"dup_x1", /* 90*/ |
||||
"dup_x2", /* 91*/ |
||||
"dup2", /* 92*/ |
||||
"dup2_x1", /* 93*/ |
||||
"dup2_x2", /* 94*/ |
||||
"swap", /* 95*/ |
||||
"iadd", /* 96*/ |
||||
"ladd", /* 97*/ |
||||
"fadd", /* 98*/ |
||||
"dadd", /* 99*/ |
||||
"isub", /* 100*/ |
||||
"lsub", /* 101*/ |
||||
"fsub", /* 102*/ |
||||
"dsub", /* 103*/ |
||||
"imul", /* 104*/ |
||||
"lmul", /* 105*/ |
||||
"fmul", /* 106*/ |
||||
"dmul", /* 107*/ |
||||
"idiv", /* 108*/ |
||||
"ldiv", /* 109*/ |
||||
"fdiv", /* 110*/ |
||||
"ddiv", /* 111*/ |
||||
"irem", /* 112*/ |
||||
"lrem", /* 113*/ |
||||
"frem", /* 114*/ |
||||
"drem", /* 115*/ |
||||
"ineg", /* 116*/ |
||||
"lneg", /* 117*/ |
||||
"fneg", /* 118*/ |
||||
"dneg", /* 119*/ |
||||
"ishl", /* 120*/ |
||||
"lshl", /* 121*/ |
||||
"ishr", /* 122*/ |
||||
"lshr", /* 123*/ |
||||
"iushr", /* 124*/ |
||||
"lushr", /* 125*/ |
||||
"iand", /* 126*/ |
||||
"land", /* 127*/ |
||||
"ior", /* 128*/ |
||||
"lor", /* 129*/ |
||||
"ixor", /* 130*/ |
||||
"lxor", /* 131*/ |
||||
"iinc", /* 132*/ |
||||
"i2l", /* 133*/ |
||||
"i2f", /* 134*/ |
||||
"i2d", /* 135*/ |
||||
"l2i", /* 136*/ |
||||
"l2f", /* 137*/ |
||||
"l2d", /* 138*/ |
||||
"f2i", /* 139*/ |
||||
"f2l", /* 140*/ |
||||
"f2d", /* 141*/ |
||||
"d2i", /* 142*/ |
||||
"d2l", /* 143*/ |
||||
"d2f", /* 144*/ |
||||
"i2b", /* 145*/ |
||||
"i2c", /* 146*/ |
||||
"i2s", /* 147*/ |
||||
"lcmp", /* 148*/ |
||||
"fcmpl", /* 149*/ |
||||
"fcmpg", /* 150*/ |
||||
"dcmpl", /* 151*/ |
||||
"dcmpg", /* 152*/ |
||||
"ifeq", /* 153*/ |
||||
"ifne", /* 154*/ |
||||
"iflt", /* 155*/ |
||||
"ifge", /* 156*/ |
||||
"ifgt", /* 157*/ |
||||
"ifle", /* 158*/ |
||||
"if_icmpeq", /* 159*/ |
||||
"if_icmpne", /* 160*/ |
||||
"if_icmplt", /* 161*/ |
||||
"if_icmpge", /* 162*/ |
||||
"if_icmpgt", /* 163*/ |
||||
"if_icmple", /* 164*/ |
||||
"if_acmpeq", /* 165*/ |
||||
"if_acmpne", /* 166*/ |
||||
"goto", /* 167*/ |
||||
"jsr", /* 168*/ |
||||
"ret", /* 169*/ |
||||
"tableswitch", /* 170*/ |
||||
"lookupswitch", /* 171*/ |
||||
"ireturn", /* 172*/ |
||||
"lreturn", /* 173*/ |
||||
"freturn", /* 174*/ |
||||
"dreturn", /* 175*/ |
||||
"areturn", /* 176*/ |
||||
"return", /* 177*/ |
||||
"getstatic", /* 178*/ |
||||
"putstatic", /* 179*/ |
||||
"getfield", /* 180*/ |
||||
"putfield", /* 181*/ |
||||
"invokevirtual", /* 182*/ |
||||
"invokespecial", /* 183*/ |
||||
"invokestatic", /* 184*/ |
||||
"invokeinterface", /* 185*/ |
||||
"invokedynamic", /* 186 */ |
||||
"new", /* 187*/ |
||||
"newarray", /* 188*/ |
||||
"anewarray", /* 189*/ |
||||
"arraylength", /* 190*/ |
||||
"athrow", /* 191*/ |
||||
"checkcast", /* 192*/ |
||||
"instanceof", /* 193*/ |
||||
"monitorenter", /* 194*/ |
||||
"monitorexit", /* 195*/ |
||||
"wide", /* 196*/ |
||||
"multianewarray", /* 197*/ |
||||
"ifnull", /* 198*/ |
||||
"ifnonnull", /* 199*/ |
||||
"goto_w", /* 200*/ |
||||
"jsr_w" /* 201*/ |
||||
}; |
||||
} |
@ -1,449 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
/** |
||||
* JVM Instruction Set. |
||||
* |
||||
* <p>This interface defines opcodes and |
||||
* array types for the NEWARRAY instruction. |
||||
* |
||||
* @see Mnemonic |
||||
*/ |
||||
public interface Opcode { |
||||
/* Opcodes */ |
||||
|
||||
int AALOAD = 50; |
||||
int AASTORE = 83; |
||||
int ACONST_NULL = 1; |
||||
int ALOAD = 25; |
||||
int ALOAD_0 = 42; |
||||
int ALOAD_1 = 43; |
||||
int ALOAD_2 = 44; |
||||
int ALOAD_3 = 45; |
||||
int ANEWARRAY = 189; |
||||
int ARETURN = 176; |
||||
int ARRAYLENGTH = 190; |
||||
int ASTORE = 58; |
||||
int ASTORE_0 = 75; |
||||
int ASTORE_1 = 76; |
||||
int ASTORE_2 = 77; |
||||
int ASTORE_3 = 78; |
||||
int ATHROW = 191; |
||||
int BALOAD = 51; |
||||
int BASTORE = 84; |
||||
int BIPUSH = 16; |
||||
int CALOAD = 52; |
||||
int CASTORE = 85; |
||||
int CHECKCAST = 192; |
||||
int D2F = 144; |
||||
int D2I = 142; |
||||
int D2L = 143; |
||||
int DADD = 99; |
||||
int DALOAD = 49; |
||||
int DASTORE = 82; |
||||
int DCMPG = 152; |
||||
int DCMPL = 151; |
||||
int DCONST_0 = 14; |
||||
int DCONST_1 = 15; |
||||
int DDIV = 111; |
||||
int DLOAD = 24; |
||||
int DLOAD_0 = 38; |
||||
int DLOAD_1 = 39; |
||||
int DLOAD_2 = 40; |
||||
int DLOAD_3 = 41; |
||||
int DMUL = 107; |
||||
int DNEG = 119; |
||||
int DREM = 115; |
||||
int DRETURN = 175; |
||||
int DSTORE = 57; |
||||
int DSTORE_0 = 71; |
||||
int DSTORE_1 = 72; |
||||
int DSTORE_2 = 73; |
||||
int DSTORE_3 = 74; |
||||
int DSUB = 103; |
||||
int DUP = 89; |
||||
int DUP2 = 92; |
||||
int DUP2_X1 = 93; |
||||
int DUP2_X2 = 94; |
||||
int DUP_X1 = 90; |
||||
int DUP_X2 = 91; |
||||
int F2D = 141; |
||||
int F2I = 139; |
||||
int F2L = 140; |
||||
int FADD = 98; |
||||
int FALOAD = 48; |
||||
int FASTORE = 81; |
||||
int FCMPG = 150; |
||||
int FCMPL = 149; |
||||
int FCONST_0 = 11; |
||||
int FCONST_1 = 12; |
||||
int FCONST_2 = 13; |
||||
int FDIV = 110; |
||||
int FLOAD = 23; |
||||
int FLOAD_0 = 34; |
||||
int FLOAD_1 = 35; |
||||
int FLOAD_2 = 36; |
||||
int FLOAD_3 = 37; |
||||
int FMUL = 106; |
||||
int FNEG = 118; |
||||
int FREM = 114; |
||||
int FRETURN = 174; |
||||
int FSTORE = 56; |
||||
int FSTORE_0 = 67; |
||||
int FSTORE_1 = 68; |
||||
int FSTORE_2 = 69; |
||||
int FSTORE_3 = 70; |
||||
int FSUB = 102; |
||||
int GETFIELD = 180; |
||||
int GETSTATIC = 178; |
||||
int GOTO = 167; |
||||
int GOTO_W = 200; |
||||
int I2B = 145; |
||||
int I2C = 146; |
||||
int I2D = 135; |
||||
int I2F = 134; |
||||
int I2L = 133; |
||||
int I2S = 147; |
||||
int IADD = 96; |
||||
int IALOAD = 46; |
||||
int IAND = 126; |
||||
int IASTORE = 79; |
||||
int ICONST_0 = 3; |
||||
int ICONST_1 = 4; |
||||
int ICONST_2 = 5; |
||||
int ICONST_3 = 6; |
||||
int ICONST_4 = 7; |
||||
int ICONST_5 = 8; |
||||
int ICONST_M1 = 2; |
||||
int IDIV = 108; |
||||
int IFEQ = 153; |
||||
int IFGE = 156; |
||||
int IFGT = 157; |
||||
int IFLE = 158; |
||||
int IFLT = 155; |
||||
int IFNE = 154; |
||||
int IFNONNULL = 199; |
||||
int IFNULL = 198; |
||||
int IF_ACMPEQ = 165; |
||||
int IF_ACMPNE = 166; |
||||
int IF_ICMPEQ = 159; |
||||
int IF_ICMPGE = 162; |
||||
int IF_ICMPGT = 163; |
||||
int IF_ICMPLE = 164; |
||||
int IF_ICMPLT = 161; |
||||
int IF_ICMPNE = 160; |
||||
int IINC = 132; |
||||
int ILOAD = 21; |
||||
int ILOAD_0 = 26; |
||||
int ILOAD_1 = 27; |
||||
int ILOAD_2 = 28; |
||||
int ILOAD_3 = 29; |
||||
int IMUL = 104; |
||||
int INEG = 116; |
||||
int INSTANCEOF = 193; |
||||
int INVOKEDYNAMIC = 186; |
||||
int INVOKEINTERFACE = 185; |
||||
int INVOKESPECIAL = 183; |
||||
int INVOKESTATIC = 184; |
||||
int INVOKEVIRTUAL = 182; |
||||
int IOR = 128; |
||||
int IREM = 112; |
||||
int IRETURN = 172; |
||||
int ISHL = 120; |
||||
int ISHR = 122; |
||||
int ISTORE = 54; |
||||
int ISTORE_0 = 59; |
||||
int ISTORE_1 = 60; |
||||
int ISTORE_2 = 61; |
||||
int ISTORE_3 = 62; |
||||
int ISUB = 100; |
||||
int IUSHR = 124; |
||||
int IXOR = 130; |
||||
int JSR = 168; |
||||
int JSR_W = 201; |
||||
int L2D = 138; |
||||
int L2F = 137; |
||||
int L2I = 136; |
||||
int LADD = 97; |
||||
int LALOAD = 47; |
||||
int LAND = 127; |
||||
int LASTORE = 80; |
||||
int LCMP = 148; |
||||
int LCONST_0 = 9; |
||||
int LCONST_1 = 10; |
||||
int LDC = 18; |
||||
int LDC2_W = 20; |
||||
int LDC_W = 19; |
||||
int LDIV = 109; |
||||
int LLOAD = 22; |
||||
int LLOAD_0 = 30; |
||||
int LLOAD_1 = 31; |
||||
int LLOAD_2 = 32; |
||||
int LLOAD_3 = 33; |
||||
int LMUL = 105; |
||||
int LNEG = 117; |
||||
int LOOKUPSWITCH = 171; |
||||
int LOR = 129; |
||||
int LREM = 113; |
||||
int LRETURN = 173; |
||||
int LSHL = 121; |
||||
int LSHR = 123; |
||||
int LSTORE = 55; |
||||
int LSTORE_0 = 63; |
||||
int LSTORE_1 = 64; |
||||
int LSTORE_2 = 65; |
||||
int LSTORE_3 = 66; |
||||
int LSUB = 101; |
||||
int LUSHR = 125; |
||||
int LXOR = 131; |
||||
int MONITORENTER = 194; |
||||
int MONITOREXIT = 195; |
||||
int MULTIANEWARRAY = 197; |
||||
int NEW = 187; |
||||
int NEWARRAY = 188; |
||||
int NOP = 0; |
||||
int POP = 87; |
||||
int POP2 = 88; |
||||
int PUTFIELD = 181; |
||||
int PUTSTATIC = 179; |
||||
int RET = 169; |
||||
int RETURN = 177; |
||||
int SALOAD = 53; |
||||
int SASTORE = 86; |
||||
int SIPUSH = 17; |
||||
int SWAP = 95; |
||||
int TABLESWITCH = 170; |
||||
int WIDE = 196; |
||||
|
||||
/* array-type code for the newarray instruction */ |
||||
|
||||
int T_BOOLEAN = 4; |
||||
int T_CHAR = 5; |
||||
int T_FLOAT = 6; |
||||
int T_DOUBLE = 7; |
||||
int T_BYTE = 8; |
||||
int T_SHORT = 9; |
||||
int T_INT = 10; |
||||
int T_LONG = 11; |
||||
|
||||
/* how many values are pushed on the operand stack. */ |
||||
int[] STACK_GROW = { |
||||
0, // nop, 0
|
||||
1, // aconst_null, 1
|
||||
1, // iconst_m1, 2
|
||||
1, // iconst_0, 3
|
||||
1, // iconst_1, 4
|
||||
1, // iconst_2, 5
|
||||
1, // iconst_3, 6
|
||||
1, // iconst_4, 7
|
||||
1, // iconst_5, 8
|
||||
2, // lconst_0, 9
|
||||
2, // lconst_1, 10
|
||||
1, // fconst_0, 11
|
||||
1, // fconst_1, 12
|
||||
1, // fconst_2, 13
|
||||
2, // dconst_0, 14
|
||||
2, // dconst_1, 15
|
||||
1, // bipush, 16
|
||||
1, // sipush, 17
|
||||
1, // ldc, 18
|
||||
1, // ldc_w, 19
|
||||
2, // ldc2_w, 20
|
||||
1, // iload, 21
|
||||
2, // lload, 22
|
||||
1, // fload, 23
|
||||
2, // dload, 24
|
||||
1, // aload, 25
|
||||
1, // iload_0, 26
|
||||
1, // iload_1, 27
|
||||
1, // iload_2, 28
|
||||
1, // iload_3, 29
|
||||
2, // lload_0, 30
|
||||
2, // lload_1, 31
|
||||
2, // lload_2, 32
|
||||
2, // lload_3, 33
|
||||
1, // fload_0, 34
|
||||
1, // fload_1, 35
|
||||
1, // fload_2, 36
|
||||
1, // fload_3, 37
|
||||
2, // dload_0, 38
|
||||
2, // dload_1, 39
|
||||
2, // dload_2, 40
|
||||
2, // dload_3, 41
|
||||
1, // aload_0, 42
|
||||
1, // aload_1, 43
|
||||
1, // aload_2, 44
|
||||
1, // aload_3, 45
|
||||
-1, // iaload, 46
|
||||
0, // laload, 47
|
||||
-1, // faload, 48
|
||||
0, // daload, 49
|
||||
-1, // aaload, 50
|
||||
-1, // baload, 51
|
||||
-1, // caload, 52
|
||||
-1, // saload, 53
|
||||
-1, // istore, 54
|
||||
-2, // lstore, 55
|
||||
-1, // fstore, 56
|
||||
-2, // dstore, 57
|
||||
-1, // astore, 58
|
||||
-1, // istore_0, 59
|
||||
-1, // istore_1, 60
|
||||
-1, // istore_2, 61
|
||||
-1, // istore_3, 62
|
||||
-2, // lstore_0, 63
|
||||
-2, // lstore_1, 64
|
||||
-2, // lstore_2, 65
|
||||
-2, // lstore_3, 66
|
||||
-1, // fstore_0, 67
|
||||
-1, // fstore_1, 68
|
||||
-1, // fstore_2, 69
|
||||
-1, // fstore_3, 70
|
||||
-2, // dstore_0, 71
|
||||
-2, // dstore_1, 72
|
||||
-2, // dstore_2, 73
|
||||
-2, // dstore_3, 74
|
||||
-1, // astore_0, 75
|
||||
-1, // astore_1, 76
|
||||
-1, // astore_2, 77
|
||||
-1, // astore_3, 78
|
||||
-3, // iastore, 79
|
||||
-4, // lastore, 80
|
||||
-3, // fastore, 81
|
||||
-4, // dastore, 82
|
||||
-3, // aastore, 83
|
||||
-3, // bastore, 84
|
||||
-3, // castore, 85
|
||||
-3, // sastore, 86
|
||||
-1, // pop, 87
|
||||
-2, // pop2, 88
|
||||
1, // dup, 89
|
||||
1, // dup_x1, 90
|
||||
1, // dup_x2, 91
|
||||
2, // dup2, 92
|
||||
2, // dup2_x1, 93
|
||||
2, // dup2_x2, 94
|
||||
0, // swap, 95
|
||||
-1, // iadd, 96
|
||||
-2, // ladd, 97
|
||||
-1, // fadd, 98
|
||||
-2, // dadd, 99
|
||||
-1, // isub, 100
|
||||
-2, // lsub, 101
|
||||
-1, // fsub, 102
|
||||
-2, // dsub, 103
|
||||
-1, // imul, 104
|
||||
-2, // lmul, 105
|
||||
-1, // fmul, 106
|
||||
-2, // dmul, 107
|
||||
-1, // idiv, 108
|
||||
-2, // ldiv, 109
|
||||
-1, // fdiv, 110
|
||||
-2, // ddiv, 111
|
||||
-1, // irem, 112
|
||||
-2, // lrem, 113
|
||||
-1, // frem, 114
|
||||
-2, // drem, 115
|
||||
0, // ineg, 116
|
||||
0, // lneg, 117
|
||||
0, // fneg, 118
|
||||
0, // dneg, 119
|
||||
-1, // ishl, 120
|
||||
-1, // lshl, 121
|
||||
-1, // ishr, 122
|
||||
-1, // lshr, 123
|
||||
-1, // iushr, 124
|
||||
-1, // lushr, 125
|
||||
-1, // iand, 126
|
||||
-2, // land, 127
|
||||
-1, // ior, 128
|
||||
-2, // lor, 129
|
||||
-1, // ixor, 130
|
||||
-2, // lxor, 131
|
||||
0, // iinc, 132
|
||||
1, // i2l, 133
|
||||
0, // i2f, 134
|
||||
1, // i2d, 135
|
||||
-1, // l2i, 136
|
||||
-1, // l2f, 137
|
||||
0, // l2d, 138
|
||||
0, // f2i, 139
|
||||
1, // f2l, 140
|
||||
1, // f2d, 141
|
||||
-1, // d2i, 142
|
||||
0, // d2l, 143
|
||||
-1, // d2f, 144
|
||||
0, // i2b, 145
|
||||
0, // i2c, 146
|
||||
0, // i2s, 147
|
||||
-3, // lcmp, 148
|
||||
-1, // fcmpl, 149
|
||||
-1, // fcmpg, 150
|
||||
-3, // dcmpl, 151
|
||||
-3, // dcmpg, 152
|
||||
-1, // ifeq, 153
|
||||
-1, // ifne, 154
|
||||
-1, // iflt, 155
|
||||
-1, // ifge, 156
|
||||
-1, // ifgt, 157
|
||||
-1, // ifle, 158
|
||||
-2, // if_icmpeq, 159
|
||||
-2, // if_icmpne, 160
|
||||
-2, // if_icmplt, 161
|
||||
-2, // if_icmpge, 162
|
||||
-2, // if_icmpgt, 163
|
||||
-2, // if_icmple, 164
|
||||
-2, // if_acmpeq, 165
|
||||
-2, // if_acmpne, 166
|
||||
0, // goto, 167
|
||||
1, // jsr, 168
|
||||
0, // ret, 169
|
||||
-1, // tableswitch, 170
|
||||
-1, // lookupswitch, 171
|
||||
-1, // ireturn, 172
|
||||
-2, // lreturn, 173
|
||||
-1, // freturn, 174
|
||||
-2, // dreturn, 175
|
||||
-1, // areturn, 176
|
||||
0, // return, 177
|
||||
0, // getstatic, 178 depends on the type
|
||||
0, // putstatic, 179 depends on the type
|
||||
0, // getfield, 180 depends on the type
|
||||
0, // putfield, 181 depends on the type
|
||||
0, // invokevirtual, 182 depends on the type
|
||||
0, // invokespecial, 183 depends on the type
|
||||
0, // invokestatic, 184 depends on the type
|
||||
0, // invokeinterface, 185 depends on the type
|
||||
0, // invokedynaimc, 186 depends on the type
|
||||
1, // new, 187
|
||||
0, // newarray, 188
|
||||
0, // anewarray, 189
|
||||
0, // arraylength, 190
|
||||
-1, // athrow, 191 stack is cleared
|
||||
0, // checkcast, 192
|
||||
0, // instanceof, 193
|
||||
-1, // monitorenter, 194
|
||||
-1, // monitorexit, 195
|
||||
0, // wide, 196 depends on the following opcode
|
||||
0, // multianewarray, 197 depends on the dimensions
|
||||
-1, // ifnull, 198
|
||||
-1, // ifnonnull, 199
|
||||
0, // goto_w, 200
|
||||
1 // jsr_w, 201
|
||||
}; |
||||
} |
@ -1,215 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
import java.io.IOException; |
||||
import java.io.DataInputStream; |
||||
import java.io.ByteArrayOutputStream; |
||||
|
||||
import com.fr.third.javassist.bytecode.annotation.Annotation; |
||||
import com.fr.third.javassist.bytecode.AnnotationsAttribute.Copier; |
||||
import com.fr.third.javassist.bytecode.AnnotationsAttribute.Parser; |
||||
import com.fr.third.javassist.bytecode.AnnotationsAttribute.Renamer; |
||||
|
||||
/** |
||||
* A class representing <code>RuntimeVisibleAnnotations_attribute</code> and |
||||
* <code>RuntimeInvisibleAnnotations_attribute</code>. |
||||
* |
||||
* <p>To obtain an ParameterAnnotationAttribute object, invoke |
||||
* <code>getAttribute(ParameterAnnotationsAttribute.invisibleTag)</code> |
||||
* in <code>MethodInfo</code>. |
||||
* The obtained attribute is a |
||||
* runtime invisible annotations attribute. |
||||
* If the parameter is |
||||
* <code>ParameterAnnotationAttribute.visibleTag</code>, then the obtained |
||||
* attribute is a runtime visible one. |
||||
*/ |
||||
public class ParameterAnnotationsAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of the <code>RuntimeVisibleParameterAnnotations</code> |
||||
* attribute. |
||||
*/ |
||||
public static final String visibleTag |
||||
= "RuntimeVisibleParameterAnnotations"; |
||||
|
||||
/** |
||||
* The name of the <code>RuntimeInvisibleParameterAnnotations</code> |
||||
* attribute. |
||||
*/ |
||||
public static final String invisibleTag |
||||
= "RuntimeInvisibleParameterAnnotations"; |
||||
/** |
||||
* Constructs |
||||
* a <code>Runtime(In)VisibleParameterAnnotations_attribute</code>. |
||||
* |
||||
* @param cp constant pool |
||||
* @param attrname attribute name (<code>visibleTag</code> or |
||||
* <code>invisibleTag</code>). |
||||
* @param info the contents of this attribute. It does not |
||||
* include <code>attribute_name_index</code> or |
||||
* <code>attribute_length</code>. |
||||
*/ |
||||
public ParameterAnnotationsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, String attrname, |
||||
byte[] info) { |
||||
super(cp, attrname, info); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an empty |
||||
* <code>Runtime(In)VisibleParameterAnnotations_attribute</code>. |
||||
* A new annotation can be later added to the created attribute |
||||
* by <code>setAnnotations()</code>. |
||||
* |
||||
* @param cp constant pool |
||||
* @param attrname attribute name (<code>visibleTag</code> or |
||||
* <code>invisibleTag</code>). |
||||
* @see #setAnnotations(com.fr.third.javassist.bytecode.annotation.Annotation[][]) |
||||
*/ |
||||
public ParameterAnnotationsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, String attrname) { |
||||
this(cp, attrname, new byte[] { 0 }); |
||||
} |
||||
|
||||
/** |
||||
* @param n the attribute name. |
||||
*/ |
||||
ParameterAnnotationsAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>num_parameters</code>. |
||||
*/ |
||||
public int numParameters() { |
||||
return info[0] & 0xff; |
||||
} |
||||
|
||||
/** |
||||
* Copies this attribute and returns a new copy. |
||||
*/ |
||||
public AttributeInfo copy(ConstPool newCp, Map classnames) { |
||||
Copier copier = new Copier(info, constPool, newCp, classnames); |
||||
try { |
||||
copier.parameters(); |
||||
return new ParameterAnnotationsAttribute(newCp, getName(), |
||||
copier.close()); |
||||
} |
||||
catch (Exception e) { |
||||
throw new RuntimeException(e.toString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Parses the annotations and returns a data structure representing |
||||
* that parsed annotations. Note that changes of the node values of the |
||||
* returned tree are not reflected on the annotations represented by |
||||
* this object unless the tree is copied back to this object by |
||||
* <code>setAnnotations()</code>. |
||||
* |
||||
* @return Each element of the returned array represents an array of |
||||
* annotations that are associated with each method parameter. |
||||
* |
||||
* @see #setAnnotations(com.fr.third.javassist.bytecode.annotation.Annotation[][]) |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.annotation.Annotation[][] getAnnotations() { |
||||
try { |
||||
return new Parser(info, constPool).parseParameters(); |
||||
} |
||||
catch (Exception e) { |
||||
throw new RuntimeException(e.toString()); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Changes the annotations represented by this object according to |
||||
* the given array of <code>Annotation</code> objects. |
||||
* |
||||
* @param params the data structure representing the |
||||
* new annotations. Every element of this array |
||||
* is an array of <code>Annotation</code> and |
||||
* it represens annotations of each method parameter. |
||||
*/ |
||||
public void setAnnotations(com.fr.third.javassist.bytecode.annotation.Annotation[][] params) { |
||||
ByteArrayOutputStream output = new ByteArrayOutputStream(); |
||||
com.fr.third.javassist.bytecode.annotation.AnnotationsWriter writer = new com.fr.third.javassist.bytecode.annotation.AnnotationsWriter(output, constPool); |
||||
try { |
||||
int n = params.length; |
||||
writer.numParameters(n); |
||||
for (int i = 0; i < n; ++i) { |
||||
com.fr.third.javassist.bytecode.annotation.Annotation[] anno = params[i]; |
||||
writer.numAnnotations(anno.length); |
||||
for (int j = 0; j < anno.length; ++j) |
||||
anno[j].write(writer); |
||||
} |
||||
|
||||
writer.close(); |
||||
} |
||||
catch (IOException e) { |
||||
throw new RuntimeException(e); // should never reach here.
|
||||
} |
||||
|
||||
set(output.toByteArray()); |
||||
} |
||||
|
||||
/** |
||||
* @param oldname a JVM class name. |
||||
* @param newname a JVM class name. |
||||
*/ |
||||
void renameClass(String oldname, String newname) { |
||||
HashMap map = new HashMap(); |
||||
map.put(oldname, newname); |
||||
renameClass(map); |
||||
} |
||||
|
||||
void renameClass(Map classnames) { |
||||
Renamer renamer = new Renamer(info, getConstPool(), classnames); |
||||
try { |
||||
renamer.parameters(); |
||||
} catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
void getRefClasses(Map classnames) { renameClass(classnames); } |
||||
|
||||
/** |
||||
* Returns a string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
com.fr.third.javassist.bytecode.annotation.Annotation[][] aa = getAnnotations(); |
||||
StringBuilder sbuf = new StringBuilder(); |
||||
int k = 0; |
||||
while (k < aa.length) { |
||||
Annotation[] a = aa[k++]; |
||||
int i = 0; |
||||
while (i < a.length) { |
||||
sbuf.append(a[i++].toString()); |
||||
if (i != a.length) |
||||
sbuf.append(" "); |
||||
} |
||||
|
||||
if (k != aa.length) |
||||
sbuf.append(", "); |
||||
} |
||||
|
||||
return sbuf.toString(); |
||||
|
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,71 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <code>SourceFile_attribute</code>. |
||||
*/ |
||||
public class SourceFileAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"SourceFile"</code>. |
||||
*/ |
||||
public static final String tag = "SourceFile"; |
||||
|
||||
SourceFileAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a SourceFile attribute. |
||||
* |
||||
* @param cp a constant pool table. |
||||
* @param filename the name of the source file. |
||||
*/ |
||||
public SourceFileAttribute(com.fr.third.javassist.bytecode.ConstPool cp, String filename) { |
||||
super(cp, tag); |
||||
int index = cp.addUtf8Info(filename); |
||||
byte[] bvalue = new byte[2]; |
||||
bvalue[0] = (byte)(index >>> 8); |
||||
bvalue[1] = (byte)index; |
||||
set(bvalue); |
||||
} |
||||
|
||||
/** |
||||
* Returns the file name indicated by <code>sourcefile_index</code>. |
||||
*/ |
||||
public String getFileName() { |
||||
return getConstPool().getUtf8Info(ByteArray.readU16bit(get(), 0)); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. Class names are replaced according to the |
||||
* given <code>Map</code> object. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames pairs of replaced and substituted |
||||
* class names. |
||||
*/ |
||||
public AttributeInfo copy(ConstPool newCp, Map classnames) { |
||||
return new SourceFileAttribute(newCp, getFileName()); |
||||
} |
||||
} |
@ -1,575 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.ByteArrayOutputStream; |
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
import com.fr.third.javassist.CannotCompileException; |
||||
import com.fr.third.javassist.CtBehavior; |
||||
import com.fr.third.javassist.CtClass; |
||||
|
||||
/** |
||||
* Another <code>stack_map</code> attribute defined in CLDC 1.1 for J2ME. |
||||
* |
||||
* <p>This is an entry in the attributes table of a Code attribute. |
||||
* It was introduced by J2ME CLDC 1.1 (JSR 139) for pre-verification. |
||||
* |
||||
* <p>According to the CLDC specification, the sizes of some fields are not 16bit |
||||
* but 32bit if the code size is more than 64K or the number of the local variables |
||||
* is more than 64K. However, for the J2ME CLDC technology, they are always 16bit. |
||||
* The implementation of the StackMap class assumes they are 16bit. |
||||
* |
||||
* @see MethodInfo#doPreverify |
||||
* @see StackMapTable |
||||
* @since 3.12 |
||||
*/ |
||||
public class StackMap extends AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"StackMap"</code>. |
||||
*/ |
||||
public static final String tag = "StackMap"; |
||||
|
||||
|
||||
/** |
||||
* Constructs a <code>stack_map</code> attribute. |
||||
*/ |
||||
StackMap(ConstPool cp, byte[] newInfo) { |
||||
super(cp, tag, newInfo); |
||||
} |
||||
|
||||
StackMap(ConstPool cp, int name_id, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, name_id, in); |
||||
} |
||||
|
||||
/** |
||||
* Returns <code>number_of_entries</code>. |
||||
*/ |
||||
public int numOfEntries() { |
||||
return ByteArray.readU16bit(info, 0); |
||||
} |
||||
|
||||
/** |
||||
* <code>Top_variable_info.tag</code>. |
||||
*/ |
||||
public static final int TOP = 0; |
||||
|
||||
/** |
||||
* <code>Integer_variable_info.tag</code>. |
||||
*/ |
||||
public static final int INTEGER = 1; |
||||
|
||||
/** |
||||
* <code>Float_variable_info.tag</code>. |
||||
*/ |
||||
public static final int FLOAT = 2; |
||||
|
||||
/** |
||||
* <code>Double_variable_info.tag</code>. |
||||
*/ |
||||
public static final int DOUBLE = 3; |
||||
|
||||
/** |
||||
* <code>Long_variable_info.tag</code>. |
||||
*/ |
||||
public static final int LONG = 4; |
||||
|
||||
/** |
||||
* <code>Null_variable_info.tag</code>. |
||||
*/ |
||||
public static final int NULL = 5; |
||||
|
||||
/** |
||||
* <code>UninitializedThis_variable_info.tag</code>. |
||||
*/ |
||||
public static final int THIS = 6; |
||||
|
||||
/** |
||||
* <code>Object_variable_info.tag</code>. |
||||
*/ |
||||
public static final int OBJECT = 7; |
||||
|
||||
/** |
||||
* <code>Uninitialized_variable_info.tag</code>. |
||||
*/ |
||||
public static final int UNINIT = 8; |
||||
|
||||
/** |
||||
* Makes a copy. |
||||
*/ |
||||
public AttributeInfo copy(ConstPool newCp, Map classnames) { |
||||
Copier copier = new Copier(this, newCp, classnames); |
||||
copier.visit(); |
||||
return copier.getStackMap(); |
||||
} |
||||
|
||||
/** |
||||
* A code walker for a StackMap attribute. |
||||
*/ |
||||
public static class Walker { |
||||
byte[] info; |
||||
|
||||
/** |
||||
* Constructs a walker. |
||||
*/ |
||||
public Walker(StackMap sm) { |
||||
info = sm.get(); |
||||
} |
||||
|
||||
/** |
||||
* Visits each entry of the stack map frames. |
||||
*/ |
||||
public void visit() { |
||||
int num = ByteArray.readU16bit(info, 0); |
||||
int pos = 2; |
||||
for (int i = 0; i < num; i++) { |
||||
int offset = ByteArray.readU16bit(info, pos); |
||||
int numLoc = ByteArray.readU16bit(info, pos + 2); |
||||
pos = locals(pos + 4, offset, numLoc); |
||||
int numStack = ByteArray.readU16bit(info, pos); |
||||
pos = stack(pos + 2, offset, numStack); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Invoked when <code>locals</code> of <code>stack_map_frame</code> |
||||
* is visited. |
||||
*/ |
||||
public int locals(int pos, int offset, int num) { |
||||
return typeInfoArray(pos, offset, num, true); |
||||
} |
||||
|
||||
/** |
||||
* Invoked when <code>stack</code> of <code>stack_map_frame</code> |
||||
* is visited. |
||||
*/ |
||||
public int stack(int pos, int offset, int num) { |
||||
return typeInfoArray(pos, offset, num, false); |
||||
} |
||||
|
||||
/** |
||||
* Invoked when an array of <code>verification_type_info</code> is |
||||
* visited. |
||||
* |
||||
* @param num the number of elements. |
||||
* @param isLocals true if this array is for <code>locals</code>. |
||||
* false if it is for <code>stack</code>. |
||||
*/ |
||||
public int typeInfoArray(int pos, int offset, int num, boolean isLocals) { |
||||
for (int k = 0; k < num; k++) |
||||
pos = typeInfoArray2(k, pos); |
||||
|
||||
return pos; |
||||
} |
||||
|
||||
int typeInfoArray2(int k, int pos) { |
||||
byte tag = info[pos]; |
||||
if (tag == OBJECT) { |
||||
int clazz = ByteArray.readU16bit(info, pos + 1); |
||||
objectVariable(pos, clazz); |
||||
pos += 3; |
||||
} |
||||
else if (tag == UNINIT) { |
||||
int offsetOfNew = ByteArray.readU16bit(info, pos + 1); |
||||
uninitialized(pos, offsetOfNew); |
||||
pos += 3; |
||||
} |
||||
else { |
||||
typeInfo(pos, tag); |
||||
pos++; |
||||
} |
||||
|
||||
return pos; |
||||
} |
||||
|
||||
/** |
||||
* Invoked when an element of <code>verification_type_info</code> |
||||
* (except <code>Object_variable_info</code> and |
||||
* <code>Uninitialized_variable_info</code>) is visited. |
||||
*/ |
||||
public void typeInfo(int pos, byte tag) {} |
||||
|
||||
/** |
||||
* Invoked when an element of type <code>Object_variable_info</code> |
||||
* is visited. |
||||
*/ |
||||
public void objectVariable(int pos, int clazz) {} |
||||
|
||||
/** |
||||
* Invoked when an element of type <code>Uninitialized_variable_info</code> |
||||
* is visited. |
||||
*/ |
||||
public void uninitialized(int pos, int offset) {} |
||||
} |
||||
|
||||
static class Copier extends Walker { |
||||
byte[] dest; |
||||
ConstPool srcCp, destCp; |
||||
Map classnames; |
||||
|
||||
Copier(StackMap map, ConstPool newCp, Map classnames) { |
||||
super(map); |
||||
srcCp = map.getConstPool(); |
||||
dest = new byte[info.length]; |
||||
destCp = newCp; |
||||
this.classnames = classnames; |
||||
} |
||||
|
||||
public void visit() { |
||||
int num = ByteArray.readU16bit(info, 0); |
||||
ByteArray.write16bit(num, dest, 0); |
||||
super.visit(); |
||||
} |
||||
|
||||
public int locals(int pos, int offset, int num) { |
||||
ByteArray.write16bit(offset, dest, pos - 4); |
||||
return super.locals(pos, offset, num); |
||||
} |
||||
|
||||
public int typeInfoArray(int pos, int offset, int num, boolean isLocals) { |
||||
ByteArray.write16bit(num, dest, pos - 2); |
||||
return super.typeInfoArray(pos, offset, num, isLocals); |
||||
} |
||||
|
||||
public void typeInfo(int pos, byte tag) { |
||||
dest[pos] = tag; |
||||
} |
||||
|
||||
public void objectVariable(int pos, int clazz) { |
||||
dest[pos] = OBJECT; |
||||
int newClazz = srcCp.copy(clazz, destCp, classnames); |
||||
ByteArray.write16bit(newClazz, dest, pos + 1); |
||||
} |
||||
|
||||
public void uninitialized(int pos, int offset) { |
||||
dest[pos] = UNINIT; |
||||
ByteArray.write16bit(offset, dest, pos + 1); |
||||
} |
||||
|
||||
public StackMap getStackMap() { |
||||
return new StackMap(destCp, dest); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Updates this stack map table when a new local variable is inserted |
||||
* for a new parameter. |
||||
* |
||||
* @param index the index of the added local variable. |
||||
* @param tag the type tag of that local variable. |
||||
* It is available by <code>StackMapTable.typeTagOf(char)</code>. |
||||
* @param classInfo the index of the <code>CONSTANT_Class_info</code> structure |
||||
* in a constant pool table. This should be zero unless the tag |
||||
* is <code>ITEM_Object</code>. |
||||
* |
||||
* @see CtBehavior#addParameter(CtClass) |
||||
* @see StackMapTable#typeTagOf(char) |
||||
* @see ConstPool |
||||
*/ |
||||
public void insertLocal(int index, int tag, int classInfo) |
||||
throws BadBytecode |
||||
{ |
||||
byte[] data = new InsertLocal(this, index, tag, classInfo).doit(); |
||||
this.set(data); |
||||
} |
||||
|
||||
static class SimpleCopy extends Walker { |
||||
Writer writer; |
||||
|
||||
SimpleCopy(StackMap map) { |
||||
super(map); |
||||
writer = new Writer(); |
||||
} |
||||
|
||||
byte[] doit() { |
||||
visit(); |
||||
return writer.toByteArray(); |
||||
} |
||||
|
||||
public void visit() { |
||||
int num = ByteArray.readU16bit(info, 0); |
||||
writer.write16bit(num); |
||||
super.visit(); |
||||
} |
||||
|
||||
public int locals(int pos, int offset, int num) { |
||||
writer.write16bit(offset); |
||||
return super.locals(pos, offset, num); |
||||
} |
||||
|
||||
public int typeInfoArray(int pos, int offset, int num, boolean isLocals) { |
||||
writer.write16bit(num); |
||||
return super.typeInfoArray(pos, offset, num, isLocals); |
||||
} |
||||
|
||||
public void typeInfo(int pos, byte tag) { |
||||
writer.writeVerifyTypeInfo(tag, 0); |
||||
} |
||||
|
||||
public void objectVariable(int pos, int clazz) { |
||||
writer.writeVerifyTypeInfo(OBJECT, clazz); |
||||
} |
||||
|
||||
public void uninitialized(int pos, int offset) { |
||||
writer.writeVerifyTypeInfo(UNINIT, offset); |
||||
} |
||||
} |
||||
|
||||
static class InsertLocal extends SimpleCopy { |
||||
private int varIndex; |
||||
private int varTag, varData; |
||||
|
||||
InsertLocal(StackMap map, int varIndex, int varTag, int varData) { |
||||
super(map); |
||||
this.varIndex = varIndex; |
||||
this.varTag = varTag; |
||||
this.varData = varData; |
||||
} |
||||
|
||||
public int typeInfoArray(int pos, int offset, int num, boolean isLocals) { |
||||
if (!isLocals || num < varIndex) |
||||
return super.typeInfoArray(pos, offset, num, isLocals); |
||||
|
||||
writer.write16bit(num + 1); |
||||
for (int k = 0; k < num; k++) { |
||||
if (k == varIndex) |
||||
writeVarTypeInfo(); |
||||
|
||||
pos = typeInfoArray2(k, pos); |
||||
} |
||||
|
||||
if (num == varIndex) |
||||
writeVarTypeInfo(); |
||||
|
||||
return pos; |
||||
} |
||||
|
||||
private void writeVarTypeInfo() { |
||||
if (varTag == OBJECT) |
||||
writer.writeVerifyTypeInfo(OBJECT, varData); |
||||
else if (varTag == UNINIT) |
||||
writer.writeVerifyTypeInfo(UNINIT, varData); |
||||
else |
||||
writer.writeVerifyTypeInfo(varTag, 0); |
||||
} |
||||
} |
||||
|
||||
void shiftPc(int where, int gapSize, boolean exclusive) |
||||
throws BadBytecode |
||||
{ |
||||
new Shifter(this, where, gapSize, exclusive).visit(); |
||||
} |
||||
|
||||
static class Shifter extends Walker { |
||||
private int where, gap; |
||||
private boolean exclusive; |
||||
|
||||
public Shifter(StackMap smt, int where, int gap, boolean exclusive) { |
||||
super(smt); |
||||
this.where = where; |
||||
this.gap = gap; |
||||
this.exclusive = exclusive; |
||||
} |
||||
|
||||
public int locals(int pos, int offset, int num) { |
||||
if (exclusive ? where <= offset : where < offset) |
||||
ByteArray.write16bit(offset + gap, info, pos - 4); |
||||
|
||||
return super.locals(pos, offset, num); |
||||
} |
||||
|
||||
public void uninitialized(int pos, int offset) { |
||||
if (where <= offset) |
||||
ByteArray.write16bit(offset + gap, info, pos + 1); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* @see CodeIterator.Switcher#adjustOffsets(int, int) |
||||
*/ |
||||
void shiftForSwitch(int where, int gapSize) throws BadBytecode { |
||||
new SwitchShifter(this, where, gapSize).visit(); |
||||
} |
||||
|
||||
static class SwitchShifter extends Walker { |
||||
private int where, gap; |
||||
|
||||
public SwitchShifter(StackMap smt, int where, int gap) { |
||||
super(smt); |
||||
this.where = where; |
||||
this.gap = gap; |
||||
} |
||||
|
||||
public int locals(int pos, int offset, int num) { |
||||
if (where == pos + offset) |
||||
ByteArray.write16bit(offset - gap, info, pos - 4); |
||||
else if (where == pos) |
||||
ByteArray.write16bit(offset + gap, info, pos - 4); |
||||
|
||||
return super.locals(pos, offset, num); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Undocumented method. Do not use; internal-use only. |
||||
* |
||||
* <p>This method is for javassist.convert.TransformNew. |
||||
* It is called to update the stack map when |
||||
* the NEW opcode (and the following DUP) is removed. |
||||
* |
||||
* @param where the position of the removed NEW opcode. |
||||
*/ |
||||
public void removeNew(int where) throws CannotCompileException { |
||||
byte[] data = new NewRemover(this, where).doit(); |
||||
this.set(data); |
||||
} |
||||
|
||||
static class NewRemover extends SimpleCopy { |
||||
int posOfNew; |
||||
|
||||
NewRemover(StackMap map, int where) { |
||||
super(map); |
||||
posOfNew = where; |
||||
} |
||||
|
||||
public int stack(int pos, int offset, int num) { |
||||
return stackTypeInfoArray(pos, offset, num); |
||||
} |
||||
|
||||
private int stackTypeInfoArray(int pos, int offset, int num) { |
||||
int p = pos; |
||||
int count = 0; |
||||
for (int k = 0; k < num; k++) { |
||||
byte tag = info[p]; |
||||
if (tag == OBJECT) |
||||
p += 3; |
||||
else if (tag == UNINIT) { |
||||
int offsetOfNew = ByteArray.readU16bit(info, p + 1); |
||||
if (offsetOfNew == posOfNew) |
||||
count++; |
||||
|
||||
p += 3; |
||||
} |
||||
else |
||||
p++; |
||||
} |
||||
|
||||
writer.write16bit(num - count); |
||||
for (int k = 0; k < num; k++) { |
||||
byte tag = info[pos]; |
||||
if (tag == OBJECT) { |
||||
int clazz = ByteArray.readU16bit(info, pos + 1); |
||||
objectVariable(pos, clazz); |
||||
pos += 3; |
||||
} |
||||
else if (tag == UNINIT) { |
||||
int offsetOfNew = ByteArray.readU16bit(info, pos + 1); |
||||
if (offsetOfNew != posOfNew) |
||||
uninitialized(pos, offsetOfNew); |
||||
|
||||
pos += 3; |
||||
} |
||||
else { |
||||
typeInfo(pos, tag); |
||||
pos++; |
||||
} |
||||
} |
||||
|
||||
return pos; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Prints this stack map. |
||||
*/ |
||||
public void print(java.io.PrintWriter out) { |
||||
new Printer(this, out).print(); |
||||
} |
||||
|
||||
static class Printer extends Walker { |
||||
private java.io.PrintWriter writer; |
||||
|
||||
public Printer(StackMap map, java.io.PrintWriter out) { |
||||
super(map); |
||||
writer = out; |
||||
} |
||||
|
||||
public void print() { |
||||
int num = ByteArray.readU16bit(info, 0); |
||||
writer.println(num + " entries"); |
||||
visit(); |
||||
} |
||||
|
||||
public int locals(int pos, int offset, int num) { |
||||
writer.println(" * offset " + offset); |
||||
return super.locals(pos, offset, num); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Internal use only. |
||||
*/ |
||||
public static class Writer { |
||||
// see javassist.bytecode.stackmap.MapMaker
|
||||
|
||||
private ByteArrayOutputStream output; |
||||
|
||||
/** |
||||
* Constructs a writer. |
||||
*/ |
||||
public Writer() { |
||||
output = new ByteArrayOutputStream(); |
||||
} |
||||
|
||||
/** |
||||
* Converts the written data into a byte array. |
||||
*/ |
||||
public byte[] toByteArray() { |
||||
return output.toByteArray(); |
||||
} |
||||
|
||||
/** |
||||
* Converts to a <code>StackMap</code> attribute. |
||||
*/ |
||||
public StackMap toStackMap(ConstPool cp) { |
||||
return new StackMap(cp, output.toByteArray()); |
||||
} |
||||
|
||||
/** |
||||
* Writes a <code>union verification_type_info</code> value. |
||||
* |
||||
* @param data <code>cpool_index</code> or <code>offset</code>. |
||||
*/ |
||||
public void writeVerifyTypeInfo(int tag, int data) { |
||||
output.write(tag); |
||||
if (tag == StackMap.OBJECT || tag == StackMap.UNINIT) |
||||
write16bit(data); |
||||
} |
||||
|
||||
/** |
||||
* Writes a 16bit value. |
||||
*/ |
||||
public void write16bit(int value) { |
||||
output.write((value >>> 8) & 0xff); |
||||
output.write(value & 0xff); |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,56 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode; |
||||
|
||||
import java.io.DataInputStream; |
||||
import java.io.IOException; |
||||
import java.util.Map; |
||||
|
||||
/** |
||||
* <code>Synthetic_attribute</code>. |
||||
*/ |
||||
public class SyntheticAttribute extends com.fr.third.javassist.bytecode.AttributeInfo { |
||||
/** |
||||
* The name of this attribute <code>"Synthetic"</code>. |
||||
*/ |
||||
public static final String tag = "Synthetic"; |
||||
|
||||
SyntheticAttribute(com.fr.third.javassist.bytecode.ConstPool cp, int n, DataInputStream in) |
||||
throws IOException |
||||
{ |
||||
super(cp, n, in); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a Synthetic attribute. |
||||
* |
||||
* @param cp a constant pool table. |
||||
*/ |
||||
public SyntheticAttribute(com.fr.third.javassist.bytecode.ConstPool cp) { |
||||
super(cp, tag, new byte[0]); |
||||
} |
||||
|
||||
/** |
||||
* Makes a copy. |
||||
* |
||||
* @param newCp the constant pool table used by the new copy. |
||||
* @param classnames should be null. |
||||
*/ |
||||
public AttributeInfo copy(ConstPool newCp, Map classnames) { |
||||
return new SyntheticAttribute(newCp); |
||||
} |
||||
} |
@ -1,423 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import java.util.Iterator; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.CtClass; |
||||
import com.fr.third.javassist.CtMethod; |
||||
import com.fr.third.javassist.NotFoundException; |
||||
import com.fr.third.javassist.bytecode.AccessFlag; |
||||
import com.fr.third.javassist.bytecode.BadBytecode; |
||||
import com.fr.third.javassist.bytecode.CodeAttribute; |
||||
import com.fr.third.javassist.bytecode.CodeIterator; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
import com.fr.third.javassist.bytecode.Descriptor; |
||||
import com.fr.third.javassist.bytecode.ExceptionTable; |
||||
import com.fr.third.javassist.bytecode.MethodInfo; |
||||
import com.fr.third.javassist.bytecode.Opcode; |
||||
|
||||
/** |
||||
* A data-flow analyzer that determines the type state of the stack and local |
||||
* variable table at every reachable instruction in a method. During analysis, |
||||
* bytecode verification is performed in a similar manner to that described |
||||
* in the JVM specification. |
||||
* |
||||
* <p>Example:</p> |
||||
* |
||||
* <pre> |
||||
* // Method to analyze
|
||||
* public Object doSomething(int x) { |
||||
* Number n; |
||||
* if (x < 5) { |
||||
* n = new Double(0); |
||||
* } else { |
||||
* n = new Long(0); |
||||
* } |
||||
* |
||||
* return n; |
||||
* } |
||||
* |
||||
* // Which compiles to:
|
||||
* // 0: iload_1
|
||||
* // 1: iconst_5
|
||||
* // 2: if_icmpge 17
|
||||
* // 5: new #18; //class java/lang/Double
|
||||
* // 8: dup
|
||||
* // 9: dconst_0
|
||||
* // 10: invokespecial #44; //Method java/lang/Double."<init>":(D)V
|
||||
* // 13: astore_2
|
||||
* // 14: goto 26
|
||||
* // 17: new #16; //class java/lang/Long
|
||||
* // 20: dup
|
||||
* // 21: lconst_1
|
||||
* // 22: invokespecial #47; //Method java/lang/Long."<init>":(J)V
|
||||
* // 25: astore_2
|
||||
* // 26: aload_2
|
||||
* // 27: areturn
|
||||
* |
||||
* public void analyzeIt(CtClass clazz, MethodInfo method) { |
||||
* Analyzer analyzer = new Analyzer(); |
||||
* Frame[] frames = analyzer.analyze(clazz, method); |
||||
* frames[0].getLocal(0).getCtClass(); // returns clazz;
|
||||
* frames[0].getLocal(1).getCtClass(); // returns java.lang.String
|
||||
* frames[1].peek(); // returns Type.INTEGER
|
||||
* frames[27].peek().getCtClass(); // returns java.lang.Number
|
||||
* } |
||||
* </pre> |
||||
* |
||||
* @see FramePrinter |
||||
* @author Jason T. Greene |
||||
*/ |
||||
public class Analyzer implements Opcode { |
||||
private final SubroutineScanner scanner = new SubroutineScanner(); |
||||
private CtClass clazz; |
||||
private ExceptionInfo[] exceptions; |
||||
private com.fr.third.javassist.bytecode.analysis.Frame[] frames; |
||||
private Subroutine[] subroutines; |
||||
|
||||
private static class ExceptionInfo { |
||||
private int end; |
||||
private int handler; |
||||
private int start; |
||||
private com.fr.third.javassist.bytecode.analysis.Type type; |
||||
|
||||
private ExceptionInfo(int start, int end, int handler, com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
this.start = start; |
||||
this.end = end; |
||||
this.handler = handler; |
||||
this.type = type; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Performs data-flow analysis on a method and returns an array, indexed by |
||||
* instruction position, containing the starting frame state of all reachable |
||||
* instructions. Non-reachable code, and illegal code offsets are represented |
||||
* as a null in the frame state array. This can be used to detect dead code. |
||||
* |
||||
* If the method does not contain code (it is either native or abstract), null |
||||
* is returned. |
||||
* |
||||
* @param clazz the declaring class of the method |
||||
* @param method the method to analyze |
||||
* @return an array, indexed by instruction position, of the starting frame state, |
||||
* or null if this method doesn't have code |
||||
* @throws BadBytecode if the bytecode does not comply with the JVM specification |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.analysis.Frame[] analyze(CtClass clazz, MethodInfo method) throws BadBytecode { |
||||
this.clazz = clazz; |
||||
CodeAttribute codeAttribute = method.getCodeAttribute(); |
||||
// Native or Abstract
|
||||
if (codeAttribute == null) |
||||
return null; |
||||
|
||||
int maxLocals = codeAttribute.getMaxLocals(); |
||||
int maxStack = codeAttribute.getMaxStack(); |
||||
int codeLength = codeAttribute.getCodeLength(); |
||||
|
||||
CodeIterator iter = codeAttribute.iterator(); |
||||
IntQueue queue = new IntQueue(); |
||||
|
||||
exceptions = buildExceptionInfo(method); |
||||
subroutines = scanner.scan(method); |
||||
|
||||
Executor executor = new Executor(clazz.getClassPool(), method.getConstPool()); |
||||
frames = new com.fr.third.javassist.bytecode.analysis.Frame[codeLength]; |
||||
frames[iter.lookAhead()] = firstFrame(method, maxLocals, maxStack); |
||||
queue.add(iter.next()); |
||||
while (!queue.isEmpty()) { |
||||
analyzeNextEntry(method, iter, queue, executor); |
||||
} |
||||
|
||||
return frames; |
||||
} |
||||
|
||||
/** |
||||
* Performs data-flow analysis on a method and returns an array, indexed by |
||||
* instruction position, containing the starting frame state of all reachable |
||||
* instructions. Non-reachable code, and illegal code offsets are represented |
||||
* as a null in the frame state array. This can be used to detect dead code. |
||||
* |
||||
* If the method does not contain code (it is either native or abstract), null |
||||
* is returned. |
||||
* |
||||
* @param method the method to analyze |
||||
* @return an array, indexed by instruction position, of the starting frame state, |
||||
* or null if this method doesn't have code |
||||
* @throws BadBytecode if the bytecode does not comply with the JVM specification |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.analysis.Frame[] analyze(CtMethod method) throws BadBytecode { |
||||
return analyze(method.getDeclaringClass(), method.getMethodInfo2()); |
||||
} |
||||
|
||||
private void analyzeNextEntry(MethodInfo method, CodeIterator iter, |
||||
IntQueue queue, Executor executor) throws BadBytecode { |
||||
int pos = queue.take(); |
||||
iter.move(pos); |
||||
iter.next(); |
||||
|
||||
com.fr.third.javassist.bytecode.analysis.Frame frame = frames[pos].copy(); |
||||
Subroutine subroutine = subroutines[pos]; |
||||
|
||||
try { |
||||
executor.execute(method, pos, iter, frame, subroutine); |
||||
} catch (RuntimeException e) { |
||||
throw new BadBytecode(e.getMessage() + "[pos = " + pos + "]", e); |
||||
} |
||||
|
||||
int opcode = iter.byteAt(pos); |
||||
|
||||
if (opcode == TABLESWITCH) { |
||||
mergeTableSwitch(queue, pos, iter, frame); |
||||
} else if (opcode == LOOKUPSWITCH) { |
||||
mergeLookupSwitch(queue, pos, iter, frame); |
||||
} else if (opcode == RET) { |
||||
mergeRet(queue, iter, pos, frame, subroutine); |
||||
} else if (com.fr.third.javassist.bytecode.analysis.Util.isJumpInstruction(opcode)) { |
||||
int target = com.fr.third.javassist.bytecode.analysis.Util.getJumpTarget(pos, iter); |
||||
|
||||
if (com.fr.third.javassist.bytecode.analysis.Util.isJsr(opcode)) { |
||||
// Merge the state before the jsr into the next instruction
|
||||
mergeJsr(queue, frames[pos], subroutines[target], pos, lookAhead(iter, pos)); |
||||
} else if (! com.fr.third.javassist.bytecode.analysis.Util.isGoto(opcode)) { |
||||
merge(queue, frame, lookAhead(iter, pos)); |
||||
} |
||||
|
||||
merge(queue, frame, target); |
||||
} else if (opcode != ATHROW && ! Util.isReturn(opcode)) { |
||||
// Can advance to next instruction
|
||||
merge(queue, frame, lookAhead(iter, pos)); |
||||
} |
||||
|
||||
// Merge all exceptions that are reachable from this instruction.
|
||||
// The redundancy is intentional, since the state must be based
|
||||
// on the current instruction frame.
|
||||
mergeExceptionHandlers(queue, method, pos, frame); |
||||
} |
||||
|
||||
private ExceptionInfo[] buildExceptionInfo(MethodInfo method) { |
||||
ConstPool constPool = method.getConstPool(); |
||||
ClassPool classes = clazz.getClassPool(); |
||||
|
||||
ExceptionTable table = method.getCodeAttribute().getExceptionTable(); |
||||
ExceptionInfo[] exceptions = new ExceptionInfo[table.size()]; |
||||
for (int i = 0; i < table.size(); i++) { |
||||
int index = table.catchType(i); |
||||
com.fr.third.javassist.bytecode.analysis.Type type; |
||||
try { |
||||
type = index == 0 ? com.fr.third.javassist.bytecode.analysis.Type.THROWABLE : com.fr.third.javassist.bytecode.analysis.Type.get(classes.get(constPool.getClassInfo(index))); |
||||
} catch (NotFoundException e) { |
||||
throw new IllegalStateException(e.getMessage()); |
||||
} |
||||
|
||||
exceptions[i] = new ExceptionInfo(table.startPc(i), table.endPc(i), table.handlerPc(i), type); |
||||
} |
||||
|
||||
return exceptions; |
||||
} |
||||
|
||||
private com.fr.third.javassist.bytecode.analysis.Frame firstFrame(MethodInfo method, int maxLocals, int maxStack) { |
||||
int pos = 0; |
||||
|
||||
com.fr.third.javassist.bytecode.analysis.Frame first = new com.fr.third.javassist.bytecode.analysis.Frame(maxLocals, maxStack); |
||||
if ((method.getAccessFlags() & AccessFlag.STATIC) == 0) { |
||||
first.setLocal(pos++, com.fr.third.javassist.bytecode.analysis.Type.get(clazz)); |
||||
} |
||||
|
||||
CtClass[] parameters; |
||||
try { |
||||
parameters = Descriptor.getParameterTypes(method.getDescriptor(), clazz.getClassPool()); |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
for (int i = 0; i < parameters.length; i++) { |
||||
com.fr.third.javassist.bytecode.analysis.Type type = zeroExtend(com.fr.third.javassist.bytecode.analysis.Type.get(parameters[i])); |
||||
first.setLocal(pos++, type); |
||||
if (type.getSize() == 2) |
||||
first.setLocal(pos++, com.fr.third.javassist.bytecode.analysis.Type.TOP); |
||||
} |
||||
|
||||
return first; |
||||
} |
||||
|
||||
private int getNext(CodeIterator iter, int of, int restore) throws BadBytecode { |
||||
iter.move(of); |
||||
iter.next(); |
||||
int next = iter.lookAhead(); |
||||
iter.move(restore); |
||||
iter.next(); |
||||
|
||||
return next; |
||||
} |
||||
|
||||
private int lookAhead(CodeIterator iter, int pos) throws BadBytecode { |
||||
if (! iter.hasNext()) |
||||
throw new BadBytecode("Execution falls off end! [pos = " + pos + "]"); |
||||
|
||||
return iter.lookAhead(); |
||||
} |
||||
|
||||
|
||||
private void merge(IntQueue queue, com.fr.third.javassist.bytecode.analysis.Frame frame, int target) { |
||||
com.fr.third.javassist.bytecode.analysis.Frame old = frames[target]; |
||||
boolean changed; |
||||
|
||||
if (old == null) { |
||||
frames[target] = frame.copy(); |
||||
changed = true; |
||||
} else { |
||||
changed = old.merge(frame); |
||||
} |
||||
|
||||
if (changed) { |
||||
queue.add(target); |
||||
} |
||||
} |
||||
|
||||
private void mergeExceptionHandlers(IntQueue queue, MethodInfo method, int pos, com.fr.third.javassist.bytecode.analysis.Frame frame) { |
||||
for (int i = 0; i < exceptions.length; i++) { |
||||
ExceptionInfo exception = exceptions[i]; |
||||
|
||||
// Start is inclusive, while end is exclusive!
|
||||
if (pos >= exception.start && pos < exception.end) { |
||||
com.fr.third.javassist.bytecode.analysis.Frame newFrame = frame.copy(); |
||||
newFrame.clearStack(); |
||||
newFrame.push(exception.type); |
||||
merge(queue, newFrame, exception.handler); |
||||
} |
||||
} |
||||
} |
||||
|
||||
private void mergeJsr(IntQueue queue, com.fr.third.javassist.bytecode.analysis.Frame frame, Subroutine sub, int pos, int next) throws BadBytecode { |
||||
if (sub == null) |
||||
throw new BadBytecode("No subroutine at jsr target! [pos = " + pos + "]"); |
||||
|
||||
com.fr.third.javassist.bytecode.analysis.Frame old = frames[next]; |
||||
boolean changed = false; |
||||
|
||||
if (old == null) { |
||||
old = frames[next] = frame.copy(); |
||||
changed = true; |
||||
} else { |
||||
for (int i = 0; i < frame.localsLength(); i++) { |
||||
// Skip everything accessed by a subroutine, mergeRet must handle this
|
||||
if (!sub.isAccessed(i)) { |
||||
com.fr.third.javassist.bytecode.analysis.Type oldType = old.getLocal(i); |
||||
com.fr.third.javassist.bytecode.analysis.Type newType = frame.getLocal(i); |
||||
if (oldType == null) { |
||||
old.setLocal(i, newType); |
||||
changed = true; |
||||
continue; |
||||
} |
||||
|
||||
newType = oldType.merge(newType); |
||||
// Always set the type, in case a multi-type switched to a standard type.
|
||||
old.setLocal(i, newType); |
||||
if (!newType.equals(oldType) || newType.popChanged()) |
||||
changed = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
if (! old.isJsrMerged()) { |
||||
old.setJsrMerged(true); |
||||
changed = true; |
||||
} |
||||
|
||||
if (changed && old.isRetMerged()) |
||||
queue.add(next); |
||||
|
||||
} |
||||
|
||||
private void mergeLookupSwitch(IntQueue queue, int pos, CodeIterator iter, com.fr.third.javassist.bytecode.analysis.Frame frame) throws BadBytecode { |
||||
int index = (pos & ~3) + 4; |
||||
// default
|
||||
merge(queue, frame, pos + iter.s32bitAt(index)); |
||||
int npairs = iter.s32bitAt(index += 4); |
||||
int end = npairs * 8 + (index += 4); |
||||
|
||||
// skip "match"
|
||||
for (index += 4; index < end; index += 8) { |
||||
int target = iter.s32bitAt(index) + pos; |
||||
merge(queue, frame, target); |
||||
} |
||||
} |
||||
|
||||
private void mergeRet(IntQueue queue, CodeIterator iter, int pos, com.fr.third.javassist.bytecode.analysis.Frame frame, Subroutine subroutine) throws BadBytecode { |
||||
if (subroutine == null) |
||||
throw new BadBytecode("Ret on no subroutine! [pos = " + pos + "]"); |
||||
|
||||
Iterator callerIter = subroutine.callers().iterator(); |
||||
while (callerIter.hasNext()) { |
||||
int caller = ((Integer) callerIter.next()).intValue(); |
||||
int returnLoc = getNext(iter, caller, pos); |
||||
boolean changed = false; |
||||
|
||||
com.fr.third.javassist.bytecode.analysis.Frame old = frames[returnLoc]; |
||||
if (old == null) { |
||||
old = frames[returnLoc] = frame.copyStack(); |
||||
changed = true; |
||||
} else { |
||||
changed = old.mergeStack(frame); |
||||
} |
||||
|
||||
for (Iterator i = subroutine.accessed().iterator(); i.hasNext(); ) { |
||||
int index = ((Integer)i.next()).intValue(); |
||||
com.fr.third.javassist.bytecode.analysis.Type oldType = old.getLocal(index); |
||||
com.fr.third.javassist.bytecode.analysis.Type newType = frame.getLocal(index); |
||||
if (oldType != newType) { |
||||
old.setLocal(index, newType); |
||||
changed = true; |
||||
} |
||||
} |
||||
|
||||
if (! old.isRetMerged()) { |
||||
old.setRetMerged(true); |
||||
changed = true; |
||||
} |
||||
|
||||
if (changed && old.isJsrMerged()) |
||||
queue.add(returnLoc); |
||||
} |
||||
} |
||||
|
||||
|
||||
private void mergeTableSwitch(IntQueue queue, int pos, CodeIterator iter, Frame frame) throws BadBytecode { |
||||
// Skip 4 byte alignment padding
|
||||
int index = (pos & ~3) + 4; |
||||
// default
|
||||
merge(queue, frame, pos + iter.s32bitAt(index)); |
||||
int low = iter.s32bitAt(index += 4); |
||||
int high = iter.s32bitAt(index += 4); |
||||
int end = (high - low + 1) * 4 + (index += 4); |
||||
|
||||
// Offset table
|
||||
for (; index < end; index += 4) { |
||||
int target = iter.s32bitAt(index) + pos; |
||||
merge(queue, frame, target); |
||||
} |
||||
} |
||||
|
||||
private com.fr.third.javassist.bytecode.analysis.Type zeroExtend(com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
if (type == com.fr.third.javassist.bytecode.analysis.Type.SHORT || type == com.fr.third.javassist.bytecode.analysis.Type.BYTE || type == com.fr.third.javassist.bytecode.analysis.Type.CHAR || type == com.fr.third.javassist.bytecode.analysis.Type.BOOLEAN) |
||||
return Type.INTEGER; |
||||
|
||||
return type; |
||||
} |
||||
} |
@ -1,504 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import java.util.ArrayList; |
||||
import com.fr.third.javassist.CtClass; |
||||
import com.fr.third.javassist.CtMethod; |
||||
import com.fr.third.javassist.bytecode.BadBytecode; |
||||
import com.fr.third.javassist.bytecode.MethodInfo; |
||||
import com.fr.third.javassist.bytecode.stackmap.BasicBlock; |
||||
|
||||
/** |
||||
* Represents the control flow graph of a given method. |
||||
* |
||||
* <p>To obtain the control flow graph, do the following:</p> |
||||
* |
||||
* <pre>CtMethod m = ... |
||||
* ControlFlow cf = new ControlFlow(m); |
||||
* Block[] blocks = cf.basicBlocks(); |
||||
* </pre> |
||||
* |
||||
* <p><code>blocks</code> is an array of basic blocks in |
||||
* that method body.</p> |
||||
* |
||||
* @see CtMethod |
||||
* @see Block |
||||
* @see com.fr.third.javassist.bytecode.analysis.Frame |
||||
* @see com.fr.third.javassist.bytecode.analysis.Analyzer |
||||
* @author Shigeru Chiba |
||||
* @since 3.16 |
||||
*/ |
||||
public class ControlFlow { |
||||
private CtClass clazz; |
||||
private MethodInfo methodInfo; |
||||
private Block[] basicBlocks; |
||||
private com.fr.third.javassist.bytecode.analysis.Frame[] frames; |
||||
|
||||
/** |
||||
* Constructs a control-flow analyzer for the given method. |
||||
*/ |
||||
public ControlFlow(CtMethod method) throws BadBytecode { |
||||
this(method.getDeclaringClass(), method.getMethodInfo2()); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a control-flow analyzer. |
||||
*/ |
||||
public ControlFlow(CtClass ctclazz, MethodInfo minfo) throws BadBytecode { |
||||
clazz = ctclazz; |
||||
methodInfo = minfo; |
||||
frames = null; |
||||
basicBlocks = (Block[])new BasicBlock.Maker() { |
||||
protected BasicBlock makeBlock(int pos) { |
||||
return new Block(pos, methodInfo); |
||||
} |
||||
protected BasicBlock[] makeArray(int size) { |
||||
return new Block[size]; |
||||
} |
||||
}.make(minfo); |
||||
int size = basicBlocks.length; |
||||
int[] counters = new int[size]; |
||||
for (int i = 0; i < size; i++) { |
||||
Block b = basicBlocks[i]; |
||||
b.index = i; |
||||
b.entrances = new Block[b.incomings()]; |
||||
counters[i] = 0; |
||||
} |
||||
|
||||
for (int i = 0; i < size; i++) { |
||||
Block b = basicBlocks[i]; |
||||
for (int k = 0; k < b.exits(); k++) { |
||||
Block e = b.exit(k); |
||||
e.entrances[counters[e.index]++] = b; |
||||
} |
||||
|
||||
ControlFlow.Catcher[] catchers = b.catchers(); |
||||
for (int k = 0; k < catchers.length; k++) { |
||||
Block catchBlock = catchers[k].node; |
||||
catchBlock.entrances[counters[catchBlock.index]++] = b; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns all the basic blocks in the method body. |
||||
*/ |
||||
public Block[] basicBlocks() { |
||||
return basicBlocks; |
||||
} |
||||
|
||||
/** |
||||
* Returns the types of the local variables and stack frame entries |
||||
* available at the given position. If the byte at the position is |
||||
* not the first byte of an instruction, then this method returns |
||||
* null. |
||||
* |
||||
* @param pos the position. |
||||
*/ |
||||
public Frame frameAt(int pos) throws BadBytecode { |
||||
if (frames == null) |
||||
frames = new Analyzer().analyze(clazz, methodInfo); |
||||
|
||||
return frames[pos]; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a dominator tree. This method returns an array of |
||||
* the tree nodes. The first element of the array is the root |
||||
* of the tree. |
||||
* |
||||
* <p> The order of the elements is the same as that |
||||
* of the elements in the <code>Block</code> array returned |
||||
* by the <code>basicBlocks</code> |
||||
* method. If a <code>Block</code> object is at the i-th position |
||||
* in the <code>Block</code> array, then |
||||
* the <code>Node</code> object referring to that |
||||
* <code>Block</code> object is at the i-th position in the |
||||
* array returned by this method. |
||||
* For every array element <code>node</code>, its index in the |
||||
* array is equivalent to <code>node.block().index()</code>. |
||||
* |
||||
* @return an array of the tree nodes, or null if the method is abstract. |
||||
* @see Node#block() |
||||
* @see Block#index() |
||||
*/ |
||||
public Node[] dominatorTree() { |
||||
int size = basicBlocks.length; |
||||
if (size == 0) |
||||
return null; |
||||
|
||||
Node[] nodes = new Node[size]; |
||||
boolean[] visited = new boolean[size]; |
||||
int[] distance = new int[size]; |
||||
for (int i = 0; i < size; i++) { |
||||
nodes[i] = new Node(basicBlocks[i]); |
||||
visited[i] = false; |
||||
} |
||||
|
||||
Access access = new Access(nodes) { |
||||
BasicBlock[] exits(Node n) { return n.block.getExit(); } |
||||
BasicBlock[] entrances(Node n) { return n.block.entrances; } |
||||
}; |
||||
nodes[0].makeDepth1stTree(null, visited, 0, distance, access); |
||||
do { |
||||
for (int i = 0; i < size; i++) |
||||
visited[i] = false; |
||||
} while (nodes[0].makeDominatorTree(visited, distance, access)); |
||||
Node.setChildren(nodes); |
||||
return nodes; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a post dominator tree. This method returns an array of |
||||
* the tree nodes. Note that the tree has multiple roots. |
||||
* The parent of the root nodes is null. |
||||
* |
||||
* <p> The order of the elements is the same as that |
||||
* of the elements in the <code>Block</code> array returned |
||||
* by the <code>basicBlocks</code> |
||||
* method. If a <code>Block</code> object is at the i-th position |
||||
* in the <code>Block</code> array, then |
||||
* the <code>Node</code> object referring to that |
||||
* <code>Block</code> object is at the i-th position in the |
||||
* array returned by this method. |
||||
* For every array element <code>node</code>, its index in the |
||||
* array is equivalent to <code>node.block().index()</code>. |
||||
* |
||||
* @return an array of the tree nodes, or null if the method is abstract. |
||||
* @see Node#block() |
||||
* @see Block#index() |
||||
*/ |
||||
public Node[] postDominatorTree() { |
||||
int size = basicBlocks.length; |
||||
if (size == 0) |
||||
return null; |
||||
|
||||
Node[] nodes = new Node[size]; |
||||
boolean[] visited = new boolean[size]; |
||||
int[] distance = new int[size]; |
||||
for (int i = 0; i < size; i++) { |
||||
nodes[i] = new Node(basicBlocks[i]); |
||||
visited[i] = false; |
||||
} |
||||
|
||||
Access access = new Access(nodes) { |
||||
BasicBlock[] exits(Node n) { return n.block.entrances; } |
||||
BasicBlock[] entrances(Node n) { return n.block.getExit(); } |
||||
}; |
||||
|
||||
int counter = 0; |
||||
for (int i = 0; i < size; i++) |
||||
if (nodes[i].block.exits() == 0) |
||||
counter = nodes[i].makeDepth1stTree(null, visited, counter, distance, access); |
||||
|
||||
boolean changed; |
||||
do { |
||||
for (int i = 0; i < size; i++) |
||||
visited[i] = false; |
||||
|
||||
changed = false; |
||||
for (int i = 0; i < size; i++) |
||||
if (nodes[i].block.exits() == 0) |
||||
if (nodes[i].makeDominatorTree(visited, distance, access)) |
||||
changed = true; |
||||
} while (changed); |
||||
|
||||
Node.setChildren(nodes); |
||||
return nodes; |
||||
} |
||||
|
||||
/** |
||||
* Basic block. |
||||
* It is a sequence of contiguous instructions that do not contain |
||||
* jump/branch instructions except the last one. |
||||
* Since Java6 or later does not allow <code>JSR</code>, |
||||
* we deal with <code>JSR</code> as a non-branch instruction. |
||||
*/ |
||||
public static class Block extends BasicBlock { |
||||
/** |
||||
* A field that can be freely used for storing extra data. |
||||
* A client program of this control-flow analyzer can append |
||||
* an additional attribute to a <code>Block</code> object. |
||||
* The Javassist library never accesses this field. |
||||
*/ |
||||
public Object clientData = null; |
||||
|
||||
int index; |
||||
MethodInfo method; |
||||
Block[] entrances; |
||||
|
||||
Block(int pos, MethodInfo minfo) { |
||||
super(pos); |
||||
method = minfo; |
||||
} |
||||
|
||||
protected void toString2(StringBuffer sbuf) { |
||||
super.toString2(sbuf); |
||||
sbuf.append(", incoming{"); |
||||
for (int i = 0; i < entrances.length; i++) |
||||
sbuf.append(entrances[i].position).append(", "); |
||||
|
||||
sbuf.append("}"); |
||||
} |
||||
|
||||
BasicBlock[] getExit() { return exit; } |
||||
|
||||
/** |
||||
* Returns the position of this block in the array of |
||||
* basic blocks that the <code>basicBlocks</code> method |
||||
* returns. |
||||
* |
||||
* @see #basicBlocks() |
||||
*/ |
||||
public int index() { return index; } |
||||
|
||||
/** |
||||
* Returns the position of the first instruction |
||||
* in this block. |
||||
*/ |
||||
public int position() { return position; } |
||||
|
||||
/** |
||||
* Returns the length of this block. |
||||
*/ |
||||
public int length() { return length; } |
||||
|
||||
/** |
||||
* Returns the number of the control paths entering this block. |
||||
*/ |
||||
public int incomings() { return incoming; } |
||||
|
||||
/** |
||||
* Returns the block that the control may jump into this block from. |
||||
*/ |
||||
public Block incoming(int n) { |
||||
return entrances[n]; |
||||
} |
||||
|
||||
/** |
||||
* Return the number of the blocks that may be executed |
||||
* after this block. |
||||
*/ |
||||
public int exits() { return exit == null ? 0 : exit.length; } |
||||
|
||||
/** |
||||
* Returns the n-th block that may be executed after this |
||||
* block. |
||||
* |
||||
* @param n an index in the array of exit blocks. |
||||
*/ |
||||
public Block exit(int n) { return (Block)exit[n]; } |
||||
|
||||
/** |
||||
* Returns catch clauses that will catch an exception thrown |
||||
* in this block. |
||||
*/ |
||||
public Catcher[] catchers() { |
||||
ArrayList catchers = new ArrayList(); |
||||
BasicBlock.Catch c = toCatch; |
||||
while (c != null) { |
||||
catchers.add(new Catcher(c)); |
||||
c = c.next; |
||||
} |
||||
|
||||
return (Catcher[])catchers.toArray(new Catcher[catchers.size()]); |
||||
} |
||||
} |
||||
|
||||
static abstract class Access { |
||||
Node[] all; |
||||
Access(Node[] nodes) { all = nodes; } |
||||
Node node(BasicBlock b) { return all[((Block)b).index]; } |
||||
abstract BasicBlock[] exits(Node n); |
||||
abstract BasicBlock[] entrances(Node n); |
||||
} |
||||
|
||||
/** |
||||
* A node of (post) dominator trees. |
||||
*/ |
||||
public static class Node { |
||||
private Block block; |
||||
private Node parent; |
||||
private Node[] children; |
||||
|
||||
Node(Block b) { |
||||
block = b; |
||||
parent = null; |
||||
} |
||||
|
||||
/** |
||||
* Returns a <code>String</code> representation. |
||||
*/ |
||||
public String toString() { |
||||
StringBuffer sbuf = new StringBuffer(); |
||||
sbuf.append("Node[pos=").append(block().position()); |
||||
sbuf.append(", parent="); |
||||
sbuf.append(parent == null ? "*" : Integer.toString(parent.block().position())); |
||||
sbuf.append(", children{"); |
||||
for (int i = 0; i < children.length; i++) |
||||
sbuf.append(children[i].block().position()).append(", "); |
||||
|
||||
sbuf.append("}]"); |
||||
return sbuf.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the basic block indicated by this node. |
||||
*/ |
||||
public Block block() { return block; } |
||||
|
||||
/** |
||||
* Returns the parent of this node. |
||||
*/ |
||||
public Node parent() { return parent; } |
||||
|
||||
/** |
||||
* Returns the number of the children of this node. |
||||
*/ |
||||
public int children() { return children.length; } |
||||
|
||||
/** |
||||
* Returns the n-th child of this node. |
||||
* |
||||
* @param n an index in the array of children. |
||||
*/ |
||||
public Node child(int n) { return children[n]; } |
||||
|
||||
/* |
||||
* After executing this method, distance[] represents the post order of the tree nodes. |
||||
* It also represents distances from the root; a bigger number represents a shorter |
||||
* distance. parent is set to its parent in the depth first spanning tree. |
||||
*/ |
||||
int makeDepth1stTree(Node caller, boolean[] visited, int counter, int[] distance, Access access) { |
||||
int index = block.index; |
||||
if (visited[index]) |
||||
return counter; |
||||
|
||||
visited[index] = true; |
||||
parent = caller; |
||||
BasicBlock[] exits = access.exits(this); |
||||
if (exits != null) |
||||
for (int i = 0; i < exits.length; i++) { |
||||
Node n = access.node(exits[i]); |
||||
counter = n.makeDepth1stTree(this, visited, counter, distance, access); |
||||
} |
||||
|
||||
distance[index] = counter++; |
||||
return counter; |
||||
} |
||||
|
||||
boolean makeDominatorTree(boolean[] visited, int[] distance, Access access) { |
||||
int index = block.index; |
||||
if (visited[index]) |
||||
return false; |
||||
|
||||
visited[index] = true; |
||||
boolean changed = false; |
||||
BasicBlock[] exits = access.exits(this); |
||||
if (exits != null) |
||||
for (int i = 0; i < exits.length; i++) { |
||||
Node n = access.node(exits[i]); |
||||
if (n.makeDominatorTree(visited, distance, access)) |
||||
changed = true; |
||||
} |
||||
|
||||
BasicBlock[] entrances = access.entrances(this); |
||||
if (entrances != null) |
||||
for (int i = 0; i < entrances.length; i++) { |
||||
if (parent != null) { |
||||
Node n = getAncestor(parent, access.node(entrances[i]), distance); |
||||
if (n != parent) { |
||||
parent = n; |
||||
changed = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return changed; |
||||
} |
||||
|
||||
private static Node getAncestor(Node n1, Node n2, int[] distance) { |
||||
while (n1 != n2) { |
||||
if (distance[n1.block.index] < distance[n2.block.index]) |
||||
n1 = n1.parent; |
||||
else |
||||
n2 = n2.parent; |
||||
|
||||
if (n1 == null || n2 == null) |
||||
return null; |
||||
} |
||||
|
||||
return n1; |
||||
} |
||||
|
||||
private static void setChildren(Node[] all) { |
||||
int size = all.length; |
||||
int[] nchildren = new int[size]; |
||||
for (int i = 0; i < size; i++) |
||||
nchildren[i] = 0; |
||||
|
||||
for (int i = 0; i < size; i++) { |
||||
Node p = all[i].parent; |
||||
if (p != null) |
||||
nchildren[p.block.index]++; |
||||
} |
||||
|
||||
for (int i = 0; i < size; i++) |
||||
all[i].children = new Node[nchildren[i]]; |
||||
|
||||
for (int i = 0; i < size; i++) |
||||
nchildren[i] = 0; |
||||
|
||||
for (int i = 0; i < size; i++) { |
||||
Node n = all[i]; |
||||
Node p = n.parent; |
||||
if (p != null) |
||||
p.children[nchildren[p.block.index]++] = n; |
||||
} |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Represents a catch clause. |
||||
*/ |
||||
public static class Catcher { |
||||
private Block node; |
||||
private int typeIndex; |
||||
|
||||
Catcher(BasicBlock.Catch c) { |
||||
node = (Block)c.body; |
||||
typeIndex = c.typeIndex; |
||||
} |
||||
|
||||
/** |
||||
* Returns the first block of the catch clause. |
||||
*/ |
||||
public Block block() { return node; } |
||||
|
||||
/** |
||||
* Returns the name of the exception type that |
||||
* this catch clause catches. |
||||
*/ |
||||
public String type() { |
||||
if (typeIndex == 0) |
||||
return "java.lang.Throwable"; |
||||
else |
||||
return node.method.getConstPool().getClassInfo(typeIndex); |
||||
} |
||||
} |
||||
} |
File diff suppressed because it is too large
Load Diff
@ -1,289 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
|
||||
/** |
||||
* Represents the stack frame and local variable table at a particular point in time. |
||||
* |
||||
* @author Jason T. Greene |
||||
*/ |
||||
public class Frame { |
||||
private com.fr.third.javassist.bytecode.analysis.Type[] locals; |
||||
private com.fr.third.javassist.bytecode.analysis.Type[] stack; |
||||
private int top; |
||||
private boolean jsrMerged; |
||||
private boolean retMerged; |
||||
|
||||
/** |
||||
* Create a new frame with the specified local variable table size, and max stack size |
||||
* |
||||
* @param locals the number of local variable table entries |
||||
* @param stack the maximum stack size |
||||
*/ |
||||
public Frame(int locals, int stack) { |
||||
this.locals = new com.fr.third.javassist.bytecode.analysis.Type[locals]; |
||||
this.stack = new com.fr.third.javassist.bytecode.analysis.Type[stack]; |
||||
} |
||||
|
||||
/** |
||||
* Returns the local varaible table entry at index. |
||||
* |
||||
* @param index the position in the table |
||||
* @return the type if one exists, or null if the position is empty |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.analysis.Type getLocal(int index) { |
||||
return locals[index]; |
||||
} |
||||
|
||||
/** |
||||
* Sets the local variable table entry at index to a type. |
||||
* |
||||
* @param index the position in the table |
||||
* @param type the type to set at the position |
||||
*/ |
||||
public void setLocal(int index, com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
locals[index] = type; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Returns the type on the stack at the specified index. |
||||
* |
||||
* @param index the position on the stack |
||||
* @return the type of the stack position |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.analysis.Type getStack(int index) { |
||||
return stack[index]; |
||||
} |
||||
|
||||
/** |
||||
* Sets the type of the stack position |
||||
* |
||||
* @param index the position on the stack |
||||
* @param type the type to set |
||||
*/ |
||||
public void setStack(int index, com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
stack[index] = type; |
||||
} |
||||
|
||||
/** |
||||
* Empties the stack |
||||
*/ |
||||
public void clearStack() { |
||||
top = 0; |
||||
} |
||||
|
||||
/** |
||||
* Gets the index of the type sitting at the top of the stack. |
||||
* This is not to be confused with a length operation which |
||||
* would return the number of elements, not the position of |
||||
* the last element. |
||||
* |
||||
* @return the position of the element at the top of the stack |
||||
*/ |
||||
public int getTopIndex() { |
||||
return top - 1; |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of local variable table entries, specified |
||||
* at construction. |
||||
* |
||||
* @return the number of local variable table entries |
||||
*/ |
||||
public int localsLength() { |
||||
return locals.length; |
||||
} |
||||
|
||||
/** |
||||
* Gets the top of the stack without altering it |
||||
* |
||||
* @return the top of the stack |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.analysis.Type peek() { |
||||
if (top < 1) |
||||
throw new IndexOutOfBoundsException("Stack is empty"); |
||||
|
||||
return stack[top - 1]; |
||||
} |
||||
|
||||
/** |
||||
* Alters the stack to contain one less element and return it. |
||||
* |
||||
* @return the element popped from the stack |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.analysis.Type pop() { |
||||
if (top < 1) |
||||
throw new IndexOutOfBoundsException("Stack is empty"); |
||||
return stack[--top]; |
||||
} |
||||
|
||||
/** |
||||
* Alters the stack by placing the passed type on the top |
||||
* |
||||
* @param type the type to add to the top |
||||
*/ |
||||
public void push(com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
stack[top++] = type; |
||||
} |
||||
|
||||
|
||||
/** |
||||
* Makes a shallow copy of this frame, i.e. the type instances will |
||||
* remain the same. |
||||
* |
||||
* @return the shallow copy |
||||
*/ |
||||
public Frame copy() { |
||||
Frame frame = new Frame(locals.length, stack.length); |
||||
System.arraycopy(locals, 0, frame.locals, 0, locals.length); |
||||
System.arraycopy(stack, 0, frame.stack, 0, stack.length); |
||||
frame.top = top; |
||||
return frame; |
||||
} |
||||
|
||||
/** |
||||
* Makes a shallow copy of the stack portion of this frame. The local |
||||
* variable table size will be copied, but its contents will be empty. |
||||
* |
||||
* @return the shallow copy of the stack |
||||
*/ |
||||
public Frame copyStack() { |
||||
Frame frame = new Frame(locals.length, stack.length); |
||||
System.arraycopy(stack, 0, frame.stack, 0, stack.length); |
||||
frame.top = top; |
||||
return frame; |
||||
} |
||||
|
||||
/** |
||||
* Merges all types on the stack of this frame instance with that of the specified frame. |
||||
* The local variable table is left untouched. |
||||
* |
||||
* @param frame the frame to merge the stack from |
||||
* @return true if any changes where made |
||||
*/ |
||||
public boolean mergeStack(Frame frame) { |
||||
boolean changed = false; |
||||
if (top != frame.top) |
||||
throw new RuntimeException("Operand stacks could not be merged, they are different sizes!"); |
||||
|
||||
for (int i = 0; i < top; i++) { |
||||
if (stack[i] != null) { |
||||
com.fr.third.javassist.bytecode.analysis.Type prev = stack[i]; |
||||
com.fr.third.javassist.bytecode.analysis.Type merged = prev.merge(frame.stack[i]); |
||||
if (merged == com.fr.third.javassist.bytecode.analysis.Type.BOGUS) |
||||
throw new RuntimeException("Operand stacks could not be merged due to differing primitive types: pos = " + i); |
||||
|
||||
stack[i] = merged; |
||||
// always replace the instance in case a multi-interface type changes to a normal Type
|
||||
if ((! merged.equals(prev)) || merged.popChanged()) { |
||||
changed = true; |
||||
} |
||||
} |
||||
} |
||||
|
||||
return changed; |
||||
} |
||||
|
||||
/** |
||||
* Merges all types on the stack and local variable table of this frame with that of the specified |
||||
* type. |
||||
* |
||||
* @param frame the frame to merge with |
||||
* @return true if any changes to this frame where made by this merge |
||||
*/ |
||||
public boolean merge(Frame frame) { |
||||
boolean changed = false; |
||||
|
||||
// Local variable table
|
||||
for (int i = 0; i < locals.length; i++) { |
||||
if (locals[i] != null) { |
||||
com.fr.third.javassist.bytecode.analysis.Type prev = locals[i]; |
||||
Type merged = prev.merge(frame.locals[i]); |
||||
// always replace the instance in case a multi-interface type changes to a normal Type
|
||||
locals[i] = merged; |
||||
if (! merged.equals(prev) || merged.popChanged()) { |
||||
changed = true; |
||||
} |
||||
} else if (frame.locals[i] != null) { |
||||
locals[i] = frame.locals[i]; |
||||
changed = true; |
||||
} |
||||
} |
||||
|
||||
changed |= mergeStack(frame); |
||||
return changed; |
||||
} |
||||
|
||||
public String toString() { |
||||
StringBuffer buffer = new StringBuffer(); |
||||
|
||||
buffer.append("locals = ["); |
||||
for (int i = 0; i < locals.length; i++) { |
||||
buffer.append(locals[i] == null ? "empty" : locals[i].toString()); |
||||
if (i < locals.length - 1) |
||||
buffer.append(", "); |
||||
} |
||||
buffer.append("] stack = ["); |
||||
for (int i = 0; i < top; i++) { |
||||
buffer.append(stack[i]); |
||||
if (i < top - 1) |
||||
buffer.append(", "); |
||||
} |
||||
buffer.append("]"); |
||||
|
||||
return buffer.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Whether or not state from the source JSR instruction has been merged |
||||
* |
||||
* @return true if JSR state has been merged |
||||
*/ |
||||
boolean isJsrMerged() { |
||||
return jsrMerged; |
||||
} |
||||
|
||||
/** |
||||
* Sets whether of not the state from the source JSR instruction has been merged |
||||
* |
||||
* @param jsrMerged true if merged, otherwise false |
||||
*/ |
||||
void setJsrMerged(boolean jsrMerged) { |
||||
this.jsrMerged = jsrMerged; |
||||
} |
||||
|
||||
/** |
||||
* Whether or not state from the RET instruction, of the subroutine that was jumped |
||||
* to has been merged. |
||||
* |
||||
* @return true if RET state has been merged |
||||
*/ |
||||
boolean isRetMerged() { |
||||
return retMerged; |
||||
} |
||||
|
||||
/** |
||||
* Sets whether or not state from the RET instruction, of the subroutine that was jumped |
||||
* to has been merged. |
||||
* |
||||
* @param retMerged true if RET state has been merged |
||||
*/ |
||||
void setRetMerged(boolean retMerged) { |
||||
this.retMerged = retMerged; |
||||
} |
||||
} |
@ -1,148 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import java.io.PrintStream; |
||||
|
||||
import com.fr.third.javassist.CtClass; |
||||
import com.fr.third.javassist.CtMethod; |
||||
import com.fr.third.javassist.Modifier; |
||||
import com.fr.third.javassist.NotFoundException; |
||||
import com.fr.third.javassist.bytecode.BadBytecode; |
||||
import com.fr.third.javassist.bytecode.CodeAttribute; |
||||
import com.fr.third.javassist.bytecode.CodeIterator; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
import com.fr.third.javassist.bytecode.Descriptor; |
||||
import com.fr.third.javassist.bytecode.InstructionPrinter; |
||||
import com.fr.third.javassist.bytecode.MethodInfo; |
||||
|
||||
/** |
||||
* A utility class for printing a merged view of the frame state and the |
||||
* instructions of a method. |
||||
* |
||||
* @author Jason T. Greene |
||||
*/ |
||||
public final class FramePrinter { |
||||
private final PrintStream stream; |
||||
|
||||
/** |
||||
* Constructs a bytecode printer. |
||||
*/ |
||||
public FramePrinter(PrintStream stream) { |
||||
this.stream = stream; |
||||
} |
||||
|
||||
/** |
||||
* Prints all the methods declared in the given class. |
||||
*/ |
||||
public static void print(CtClass clazz, PrintStream stream) { |
||||
(new FramePrinter(stream)).print(clazz); |
||||
} |
||||
|
||||
/** |
||||
* Prints all the methods declared in the given class. |
||||
*/ |
||||
public void print(CtClass clazz) { |
||||
CtMethod[] methods = clazz.getDeclaredMethods(); |
||||
for (int i = 0; i < methods.length; i++) { |
||||
print(methods[i]); |
||||
} |
||||
} |
||||
|
||||
private String getMethodString(CtMethod method) { |
||||
try { |
||||
return Modifier.toString(method.getModifiers()) + " " |
||||
+ method.getReturnType().getName() + " " + method.getName() |
||||
+ Descriptor.toString(method.getSignature()) + ";"; |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Prints the instructions and the frame states of the given method. |
||||
*/ |
||||
public void print(CtMethod method) { |
||||
stream.println("\n" + getMethodString(method)); |
||||
MethodInfo info = method.getMethodInfo2(); |
||||
ConstPool pool = info.getConstPool(); |
||||
CodeAttribute code = info.getCodeAttribute(); |
||||
if (code == null) |
||||
return; |
||||
|
||||
com.fr.third.javassist.bytecode.analysis.Frame[] frames; |
||||
try { |
||||
frames = (new Analyzer()).analyze(method.getDeclaringClass(), info); |
||||
} catch (BadBytecode e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
int spacing = String.valueOf(code.getCodeLength()).length(); |
||||
|
||||
CodeIterator iterator = code.iterator(); |
||||
while (iterator.hasNext()) { |
||||
int pos; |
||||
try { |
||||
pos = iterator.next(); |
||||
} catch (BadBytecode e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
stream.println(pos + ": " + InstructionPrinter.instructionString(iterator, pos, pool)); |
||||
|
||||
addSpacing(spacing + 3); |
||||
com.fr.third.javassist.bytecode.analysis.Frame frame = frames[pos]; |
||||
if (frame == null) { |
||||
stream.println("--DEAD CODE--"); |
||||
continue; |
||||
} |
||||
printStack(frame); |
||||
|
||||
addSpacing(spacing + 3); |
||||
printLocals(frame); |
||||
} |
||||
|
||||
} |
||||
|
||||
private void printStack(com.fr.third.javassist.bytecode.analysis.Frame frame) { |
||||
stream.print("stack ["); |
||||
int top = frame.getTopIndex(); |
||||
for (int i = 0; i <= top; i++) { |
||||
if (i > 0) |
||||
stream.print(", "); |
||||
com.fr.third.javassist.bytecode.analysis.Type type = frame.getStack(i); |
||||
stream.print(type); |
||||
} |
||||
stream.println("]"); |
||||
} |
||||
|
||||
private void printLocals(Frame frame) { |
||||
stream.print("locals ["); |
||||
int length = frame.localsLength(); |
||||
for (int i = 0; i < length; i++) { |
||||
if (i > 0) |
||||
stream.print(", "); |
||||
Type type = frame.getLocal(i); |
||||
stream.print(type == null ? "empty" : type.toString()); |
||||
} |
||||
stream.println("]"); |
||||
} |
||||
|
||||
private void addSpacing(int count) { |
||||
while (count-- > 0) |
||||
stream.print(' '); |
||||
} |
||||
} |
@ -1,57 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import java.util.NoSuchElementException; |
||||
|
||||
class IntQueue { |
||||
private static class Entry { |
||||
private IntQueue.Entry next; |
||||
private int value; |
||||
private Entry(int value) { |
||||
this.value = value; |
||||
} |
||||
} |
||||
private IntQueue.Entry head; |
||||
|
||||
private IntQueue.Entry tail; |
||||
|
||||
void add(int value) { |
||||
IntQueue.Entry entry = new Entry(value); |
||||
if (tail != null) |
||||
tail.next = entry; |
||||
tail = entry; |
||||
|
||||
if (head == null) |
||||
head = entry; |
||||
} |
||||
|
||||
boolean isEmpty() { |
||||
return head == null; |
||||
} |
||||
|
||||
int take() { |
||||
if (head == null) |
||||
throw new NoSuchElementException(); |
||||
|
||||
int value = head.value; |
||||
head = head.next; |
||||
if (head == null) |
||||
tail = null; |
||||
|
||||
return value; |
||||
} |
||||
} |
@ -1,130 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.CtClass; |
||||
import com.fr.third.javassist.NotFoundException; |
||||
|
||||
/** |
||||
* Represents an array of {@link com.fr.third.javassist.bytecode.analysis.MultiType} instances. |
||||
* |
||||
* @author Jason T. Greene |
||||
*/ |
||||
public class MultiArrayType extends com.fr.third.javassist.bytecode.analysis.Type { |
||||
private com.fr.third.javassist.bytecode.analysis.MultiType component; |
||||
private int dims; |
||||
|
||||
public MultiArrayType(MultiType component, int dims) { |
||||
super(null); |
||||
this.component = component; |
||||
this.dims = dims; |
||||
} |
||||
|
||||
public CtClass getCtClass() { |
||||
CtClass clazz = component.getCtClass(); |
||||
if (clazz == null) |
||||
return null; |
||||
|
||||
ClassPool pool = clazz.getClassPool(); |
||||
if (pool == null) |
||||
pool = ClassPool.getDefault(); |
||||
|
||||
String name = arrayName(clazz.getName(), dims); |
||||
|
||||
try { |
||||
return pool.get(name); |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
boolean popChanged() { |
||||
return component.popChanged(); |
||||
} |
||||
|
||||
public int getDimensions() { |
||||
return dims; |
||||
} |
||||
|
||||
public com.fr.third.javassist.bytecode.analysis.Type getComponent() { |
||||
return dims == 1 ? (com.fr.third.javassist.bytecode.analysis.Type)component : new MultiArrayType(component, dims - 1); |
||||
} |
||||
|
||||
public int getSize() { |
||||
return 1; |
||||
} |
||||
|
||||
public boolean isArray() { |
||||
return true; |
||||
} |
||||
|
||||
public boolean isAssignableFrom(com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
throw new UnsupportedOperationException("Not implemented"); |
||||
} |
||||
|
||||
public boolean isReference() { |
||||
return true; |
||||
} |
||||
|
||||
public boolean isAssignableTo(com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
if (eq(type.getCtClass(), com.fr.third.javassist.bytecode.analysis.Type.OBJECT.getCtClass())) |
||||
return true; |
||||
|
||||
if (eq(type.getCtClass(), com.fr.third.javassist.bytecode.analysis.Type.CLONEABLE.getCtClass())) |
||||
return true; |
||||
|
||||
if (eq(type.getCtClass(), com.fr.third.javassist.bytecode.analysis.Type.SERIALIZABLE.getCtClass())) |
||||
return true; |
||||
|
||||
if (! type.isArray()) |
||||
return false; |
||||
|
||||
com.fr.third.javassist.bytecode.analysis.Type typeRoot = getRootComponent(type); |
||||
int typeDims = type.getDimensions(); |
||||
|
||||
if (typeDims > dims) |
||||
return false; |
||||
|
||||
if (typeDims < dims) { |
||||
if (eq(typeRoot.getCtClass(), com.fr.third.javassist.bytecode.analysis.Type.OBJECT.getCtClass())) |
||||
return true; |
||||
|
||||
if (eq(typeRoot.getCtClass(), com.fr.third.javassist.bytecode.analysis.Type.CLONEABLE.getCtClass())) |
||||
return true; |
||||
|
||||
if (eq(typeRoot.getCtClass(), Type.SERIALIZABLE.getCtClass())) |
||||
return true; |
||||
|
||||
return false; |
||||
} |
||||
|
||||
return component.isAssignableTo(typeRoot); |
||||
} |
||||
|
||||
public boolean equals(Object o) { |
||||
if (! (o instanceof MultiArrayType)) |
||||
return false; |
||||
MultiArrayType multi = (MultiArrayType)o; |
||||
|
||||
return component.equals(multi.component) && dims == multi.dims; |
||||
} |
||||
|
||||
public String toString() { |
||||
// follows the same detailed formating scheme as component
|
||||
return arrayName(component.toString(), dims); |
||||
} |
||||
} |
@ -1,314 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.Iterator; |
||||
import java.util.Map; |
||||
|
||||
import com.fr.third.javassist.CtClass; |
||||
|
||||
/** |
||||
* MultiType represents an unresolved type. Whenever two <literal>Type</literal> |
||||
* instances are merged, if they share more than one super type (either an |
||||
* interface or a superclass), then a <literal>MultiType</literal> is used to |
||||
* represent the possible super types. The goal of a <literal>MultiType</literal> |
||||
* is to reduce the set of possible types down to a single resolved type. This |
||||
* is done by eliminating non-assignable types from the typeset when the |
||||
* <literal>MultiType</literal> is passed as an argument to |
||||
* {@link com.fr.third.javassist.bytecode.analysis.Type#isAssignableFrom(com.fr.third.javassist.bytecode.analysis.Type)}, as well as removing non-intersecting |
||||
* types during a merge. |
||||
* |
||||
* Note: Currently the <litera>MultiType</literal> instance is reused as much |
||||
* as possible so that updates are visible from all frames. In addition, all |
||||
* <literal>MultiType</literal> merge paths are also updated. This is somewhat |
||||
* hackish, but it appears to handle most scenarios. |
||||
* |
||||
* @author Jason T. Greene |
||||
*/ |
||||
|
||||
/* TODO - A better, but more involved, approach would be to track the instruction |
||||
* offset that resulted in the creation of this type, and |
||||
* whenever the typeset changes, to force a merge on that position. This |
||||
* would require creating a new MultiType instance every time the typeset |
||||
* changes, and somehow communicating assignment changes to the Analyzer |
||||
*/ |
||||
public class MultiType extends com.fr.third.javassist.bytecode.analysis.Type { |
||||
private Map interfaces; |
||||
private com.fr.third.javassist.bytecode.analysis.Type resolved; |
||||
private com.fr.third.javassist.bytecode.analysis.Type potentialClass; |
||||
private MultiType mergeSource; |
||||
private boolean changed = false; |
||||
|
||||
public MultiType(Map interfaces) { |
||||
this(interfaces, null); |
||||
} |
||||
|
||||
public MultiType(Map interfaces, com.fr.third.javassist.bytecode.analysis.Type potentialClass) { |
||||
super(null); |
||||
this.interfaces = interfaces; |
||||
this.potentialClass = potentialClass; |
||||
} |
||||
|
||||
/** |
||||
* Gets the class that corresponds with this type. If this information |
||||
* is not yet known, java.lang.Object will be returned. |
||||
*/ |
||||
public CtClass getCtClass() { |
||||
if (resolved != null) |
||||
return resolved.getCtClass(); |
||||
|
||||
return com.fr.third.javassist.bytecode.analysis.Type.OBJECT.getCtClass(); |
||||
} |
||||
|
||||
/** |
||||
* Always returns null since this type is never used for an array. |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.analysis.Type getComponent() { |
||||
return null; |
||||
} |
||||
|
||||
/** |
||||
* Always returns 1, since this type is a reference. |
||||
*/ |
||||
public int getSize() { |
||||
return 1; |
||||
} |
||||
|
||||
/** |
||||
* Always reutnrs false since this type is never used for an array |
||||
*/ |
||||
public boolean isArray() { |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the internal state has changed. |
||||
*/ |
||||
boolean popChanged() { |
||||
boolean changed = this.changed; |
||||
this.changed = false; |
||||
return changed; |
||||
} |
||||
|
||||
public boolean isAssignableFrom(com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
throw new UnsupportedOperationException("Not implemented"); |
||||
} |
||||
|
||||
public boolean isAssignableTo(com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
if (resolved != null) |
||||
return type.isAssignableFrom(resolved); |
||||
|
||||
if (com.fr.third.javassist.bytecode.analysis.Type.OBJECT.equals(type)) |
||||
return true; |
||||
|
||||
if (potentialClass != null && !type.isAssignableFrom(potentialClass)) |
||||
potentialClass = null; |
||||
|
||||
Map map = mergeMultiAndSingle(this, type); |
||||
|
||||
if (map.size() == 1 && potentialClass == null) { |
||||
// Update previous merge paths to the same resolved type
|
||||
resolved = com.fr.third.javassist.bytecode.analysis.Type.get((CtClass)map.values().iterator().next()); |
||||
propogateResolved(); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
// Keep all previous merge paths up to date
|
||||
if (map.size() >= 1) { |
||||
interfaces = map; |
||||
propogateState(); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
if (potentialClass != null) { |
||||
resolved = potentialClass; |
||||
propogateResolved(); |
||||
|
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
private void propogateState() { |
||||
MultiType source = mergeSource; |
||||
while (source != null) { |
||||
source.interfaces = interfaces; |
||||
source.potentialClass = potentialClass; |
||||
source = source.mergeSource; |
||||
} |
||||
} |
||||
|
||||
private void propogateResolved() { |
||||
MultiType source = mergeSource; |
||||
while (source != null) { |
||||
source.resolved = resolved; |
||||
source = source.mergeSource; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Always returns true, since this type is always a reference. |
||||
* |
||||
* @return true |
||||
*/ |
||||
public boolean isReference() { |
||||
return true; |
||||
} |
||||
|
||||
private Map getAllMultiInterfaces(MultiType type) { |
||||
Map map = new HashMap(); |
||||
|
||||
Iterator iter = type.interfaces.values().iterator(); |
||||
while (iter.hasNext()) { |
||||
CtClass intf = (CtClass)iter.next(); |
||||
map.put(intf.getName(), intf); |
||||
getAllInterfaces(intf, map); |
||||
} |
||||
|
||||
return map; |
||||
} |
||||
|
||||
|
||||
private Map mergeMultiInterfaces(MultiType type1, MultiType type2) { |
||||
Map map1 = getAllMultiInterfaces(type1); |
||||
Map map2 = getAllMultiInterfaces(type2); |
||||
|
||||
return findCommonInterfaces(map1, map2); |
||||
} |
||||
|
||||
private Map mergeMultiAndSingle(MultiType multi, com.fr.third.javassist.bytecode.analysis.Type single) { |
||||
Map map1 = getAllMultiInterfaces(multi); |
||||
Map map2 = getAllInterfaces(single.getCtClass(), null); |
||||
|
||||
return findCommonInterfaces(map1, map2); |
||||
} |
||||
|
||||
private boolean inMergeSource(MultiType source) { |
||||
while (source != null) { |
||||
if (source == this) |
||||
return true; |
||||
|
||||
source = source.mergeSource; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
public com.fr.third.javassist.bytecode.analysis.Type merge(com.fr.third.javassist.bytecode.analysis.Type type) { |
||||
if (this == type) |
||||
return this; |
||||
|
||||
if (type == UNINIT) |
||||
return this; |
||||
|
||||
if (type == BOGUS) |
||||
return BOGUS; |
||||
|
||||
if (type == null) |
||||
return this; |
||||
|
||||
if (resolved != null) |
||||
return resolved.merge(type); |
||||
|
||||
if (potentialClass != null) { |
||||
com.fr.third.javassist.bytecode.analysis.Type mergePotential = potentialClass.merge(type); |
||||
if (! mergePotential.equals(potentialClass) || mergePotential.popChanged()) { |
||||
potentialClass = com.fr.third.javassist.bytecode.analysis.Type.OBJECT.equals(mergePotential) ? null : mergePotential; |
||||
changed = true; |
||||
} |
||||
} |
||||
|
||||
Map merged; |
||||
|
||||
if (type instanceof MultiType) { |
||||
MultiType multi = (MultiType)type; |
||||
|
||||
if (multi.resolved != null) { |
||||
merged = mergeMultiAndSingle(this, multi.resolved); |
||||
} else { |
||||
merged = mergeMultiInterfaces(multi, this); |
||||
if (! inMergeSource(multi)) |
||||
mergeSource = multi; |
||||
} |
||||
} else { |
||||
merged = mergeMultiAndSingle(this, type); |
||||
} |
||||
|
||||
// Keep all previous merge paths up to date
|
||||
if (merged.size() > 1 || (merged.size() == 1 && potentialClass != null)) { |
||||
// Check for changes
|
||||
if (merged.size() != interfaces.size()) { |
||||
changed = true; |
||||
} else if (changed == false){ |
||||
Iterator iter = merged.keySet().iterator(); |
||||
while (iter.hasNext()) |
||||
if (! interfaces.containsKey(iter.next())) |
||||
changed = true; |
||||
} |
||||
|
||||
interfaces = merged; |
||||
propogateState(); |
||||
|
||||
return this; |
||||
} |
||||
|
||||
if (merged.size() == 1) { |
||||
resolved = Type.get((CtClass) merged.values().iterator().next()); |
||||
} else if (potentialClass != null){ |
||||
resolved = potentialClass; |
||||
} else { |
||||
resolved = OBJECT; |
||||
} |
||||
|
||||
propogateResolved(); |
||||
|
||||
return resolved; |
||||
} |
||||
|
||||
public boolean equals(Object o) { |
||||
if (! (o instanceof MultiType)) |
||||
return false; |
||||
|
||||
MultiType multi = (MultiType) o; |
||||
if (resolved != null) |
||||
return resolved.equals(multi.resolved); |
||||
else if (multi.resolved != null) |
||||
return false; |
||||
|
||||
return interfaces.keySet().equals(multi.interfaces.keySet()); |
||||
} |
||||
|
||||
public String toString() { |
||||
if (resolved != null) |
||||
return resolved.toString(); |
||||
|
||||
StringBuffer buffer = new StringBuffer("{"); |
||||
Iterator iter = interfaces.keySet().iterator(); |
||||
while (iter.hasNext()) { |
||||
buffer.append(iter.next()); |
||||
buffer.append(", "); |
||||
} |
||||
buffer.setLength(buffer.length() - 2); |
||||
if (potentialClass != null) |
||||
buffer.append(", *").append(potentialClass.toString()); |
||||
buffer.append("}"); |
||||
return buffer.toString(); |
||||
} |
||||
} |
@ -1,67 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.HashSet; |
||||
import java.util.List; |
||||
import java.util.Set; |
||||
|
||||
/** |
||||
* Represents a nested method subroutine (marked by JSR and RET). |
||||
* |
||||
* @author Jason T. Greene |
||||
*/ |
||||
public class Subroutine { |
||||
//private Set callers = new HashSet();
|
||||
private List callers = new ArrayList(); |
||||
private Set access = new HashSet(); |
||||
private int start; |
||||
|
||||
public Subroutine(int start, int caller) { |
||||
this.start = start; |
||||
callers.add(new Integer(caller)); |
||||
} |
||||
|
||||
public void addCaller(int caller) { |
||||
callers.add(new Integer(caller)); |
||||
} |
||||
|
||||
public int start() { |
||||
return start; |
||||
} |
||||
|
||||
public void access(int index) { |
||||
access.add(new Integer(index)); |
||||
} |
||||
|
||||
public boolean isAccessed(int index) { |
||||
return access.contains(new Integer(index)); |
||||
} |
||||
|
||||
public Collection accessed() { |
||||
return access; |
||||
} |
||||
|
||||
public Collection callers() { |
||||
return callers; |
||||
} |
||||
|
||||
public String toString() { |
||||
return "start = " + start + " callers = " + callers.toString(); |
||||
} |
||||
} |
@ -1,157 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import java.util.HashMap; |
||||
import java.util.HashSet; |
||||
import java.util.Map; |
||||
import java.util.Set; |
||||
|
||||
import com.fr.third.javassist.bytecode.BadBytecode; |
||||
import com.fr.third.javassist.bytecode.CodeAttribute; |
||||
import com.fr.third.javassist.bytecode.CodeIterator; |
||||
import com.fr.third.javassist.bytecode.ExceptionTable; |
||||
import com.fr.third.javassist.bytecode.MethodInfo; |
||||
import com.fr.third.javassist.bytecode.Opcode; |
||||
|
||||
/** |
||||
* Discovers the subroutines in a method, and tracks all callers. |
||||
* |
||||
* @author Jason T. Greene |
||||
*/ |
||||
public class SubroutineScanner implements Opcode { |
||||
|
||||
private com.fr.third.javassist.bytecode.analysis.Subroutine[] subroutines; |
||||
Map subTable = new HashMap(); |
||||
Set done = new HashSet(); |
||||
|
||||
|
||||
public com.fr.third.javassist.bytecode.analysis.Subroutine[] scan(MethodInfo method) throws BadBytecode { |
||||
CodeAttribute code = method.getCodeAttribute(); |
||||
CodeIterator iter = code.iterator(); |
||||
|
||||
subroutines = new com.fr.third.javassist.bytecode.analysis.Subroutine[code.getCodeLength()]; |
||||
subTable.clear(); |
||||
done.clear(); |
||||
|
||||
scan(0, iter, null); |
||||
|
||||
ExceptionTable exceptions = code.getExceptionTable(); |
||||
for (int i = 0; i < exceptions.size(); i++) { |
||||
int handler = exceptions.handlerPc(i); |
||||
// If an exception is thrown in subroutine, the handler
|
||||
// is part of the same subroutine.
|
||||
scan(handler, iter, subroutines[exceptions.startPc(i)]); |
||||
} |
||||
|
||||
return subroutines; |
||||
} |
||||
|
||||
private void scan(int pos, CodeIterator iter, com.fr.third.javassist.bytecode.analysis.Subroutine sub) throws BadBytecode { |
||||
// Skip already processed blocks
|
||||
if (done.contains(new Integer(pos))) |
||||
return; |
||||
|
||||
done.add(new Integer(pos)); |
||||
|
||||
int old = iter.lookAhead(); |
||||
iter.move(pos); |
||||
|
||||
boolean next; |
||||
do { |
||||
pos = iter.next(); |
||||
next = scanOp(pos, iter, sub) && iter.hasNext(); |
||||
} while (next); |
||||
|
||||
iter.move(old); |
||||
} |
||||
|
||||
private boolean scanOp(int pos, CodeIterator iter, com.fr.third.javassist.bytecode.analysis.Subroutine sub) throws BadBytecode { |
||||
subroutines[pos] = sub; |
||||
|
||||
int opcode = iter.byteAt(pos); |
||||
|
||||
if (opcode == TABLESWITCH) { |
||||
scanTableSwitch(pos, iter, sub); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
if (opcode == LOOKUPSWITCH) { |
||||
scanLookupSwitch(pos, iter, sub); |
||||
|
||||
return false; |
||||
} |
||||
|
||||
// All forms of return and throw end current code flow
|
||||
if (com.fr.third.javassist.bytecode.analysis.Util.isReturn(opcode) || opcode == RET || opcode == ATHROW) |
||||
return false; |
||||
|
||||
if (com.fr.third.javassist.bytecode.analysis.Util.isJumpInstruction(opcode)) { |
||||
int target = com.fr.third.javassist.bytecode.analysis.Util.getJumpTarget(pos, iter); |
||||
if (opcode == JSR || opcode == JSR_W) { |
||||
com.fr.third.javassist.bytecode.analysis.Subroutine s = (com.fr.third.javassist.bytecode.analysis.Subroutine) subTable.get(new Integer(target)); |
||||
if (s == null) { |
||||
s = new com.fr.third.javassist.bytecode.analysis.Subroutine(target, pos); |
||||
subTable.put(new Integer(target), s); |
||||
scan(target, iter, s); |
||||
} else { |
||||
s.addCaller(pos); |
||||
} |
||||
} else { |
||||
scan(target, iter, sub); |
||||
|
||||
// GOTO ends current code flow
|
||||
if (Util.isGoto(opcode)) |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
private void scanLookupSwitch(int pos, CodeIterator iter, com.fr.third.javassist.bytecode.analysis.Subroutine sub) throws BadBytecode { |
||||
int index = (pos & ~3) + 4; |
||||
// default
|
||||
scan(pos + iter.s32bitAt(index), iter, sub); |
||||
int npairs = iter.s32bitAt(index += 4); |
||||
int end = npairs * 8 + (index += 4); |
||||
|
||||
// skip "match"
|
||||
for (index += 4; index < end; index += 8) { |
||||
int target = iter.s32bitAt(index) + pos; |
||||
scan(target, iter, sub); |
||||
} |
||||
} |
||||
|
||||
private void scanTableSwitch(int pos, CodeIterator iter, Subroutine sub) throws BadBytecode { |
||||
// Skip 4 byte alignment padding
|
||||
int index = (pos & ~3) + 4; |
||||
// default
|
||||
scan(pos + iter.s32bitAt(index), iter, sub); |
||||
int low = iter.s32bitAt(index += 4); |
||||
int high = iter.s32bitAt(index += 4); |
||||
int end = (high - low + 1) * 4 + (index += 4); |
||||
|
||||
// Offset table
|
||||
for (; index < end; index += 4) { |
||||
int target = iter.s32bitAt(index) + pos; |
||||
scan(target, iter, sub); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -1,593 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.HashMap; |
||||
import java.util.IdentityHashMap; |
||||
import java.util.Iterator; |
||||
import java.util.Map; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.CtClass; |
||||
import com.fr.third.javassist.NotFoundException; |
||||
|
||||
/** |
||||
* Represents a JVM type in data-flow analysis. This abstraction is necessary since |
||||
* a JVM type not only includes all normal Java types, but also a few special types |
||||
* that are used by the JVM internally. See the static field types on this class for |
||||
* more info on these special types. |
||||
* |
||||
* All primitive and special types reuse the same instance, so identity comparison can |
||||
* be used when examining them. Normal java types must use {@link #equals(Object)} to |
||||
* compare type instances. |
||||
* |
||||
* In most cases, applications which consume this API, only need to call {@link #getCtClass()} |
||||
* to obtain the needed type information. |
||||
* |
||||
* @author Jason T. Greene |
||||
*/ |
||||
public class Type { |
||||
private final CtClass clazz; |
||||
private final boolean special; |
||||
|
||||
private static final Map prims = new IdentityHashMap(); |
||||
/** Represents the double primitive type */ |
||||
public static final Type DOUBLE = new Type(CtClass.doubleType); |
||||
/** Represents the boolean primitive type */ |
||||
public static final Type BOOLEAN = new Type(CtClass.booleanType); |
||||
/** Represents the long primitive type */ |
||||
public static final Type LONG = new Type(CtClass.longType); |
||||
/** Represents the char primitive type */ |
||||
public static final Type CHAR = new Type(CtClass.charType); |
||||
/** Represents the byte primitive type */ |
||||
public static final Type BYTE = new Type(CtClass.byteType); |
||||
/** Represents the short primitive type */ |
||||
public static final Type SHORT = new Type(CtClass.shortType); |
||||
/** Represents the integer primitive type */ |
||||
public static final Type INTEGER = new Type(CtClass.intType); |
||||
/** Represents the float primitive type */ |
||||
public static final Type FLOAT = new Type(CtClass.floatType); |
||||
/** Represents the void primitive type */ |
||||
public static final Type VOID = new Type(CtClass.voidType); |
||||
|
||||
/** |
||||
* Represents an unknown, or null type. This occurs when aconst_null is used. |
||||
* It is important not to treat this type as java.lang.Object, since a null can |
||||
* be assigned to any reference type. The analyzer will replace these with |
||||
* an actual known type if it can be determined by a merged path with known type |
||||
* information. If this type is encountered on a frame then it is guaranteed to |
||||
* be null, and the type information is simply not available. Any attempts to |
||||
* infer the type, without further information from the compiler would be a guess. |
||||
*/ |
||||
public static final Type UNINIT = new Type(null); |
||||
|
||||
/** |
||||
* Represents an internal JVM return address, which is used by the RET |
||||
* instruction to return to a JSR that invoked the subroutine. |
||||
*/ |
||||
public static final Type RETURN_ADDRESS = new Type(null, true); |
||||
|
||||
/** A placeholder used by the analyzer for the second word position of a double-word type */ |
||||
public static final Type TOP = new Type(null, true); |
||||
|
||||
/** |
||||
* Represents a non-accessible value. Code cannot access the value this type |
||||
* represents. It occurs when bytecode reuses a local variable table |
||||
* position with non-mergable types. An example would be compiled code which |
||||
* uses the same position for a primitive type in one branch, and a reference type |
||||
* in another branch. |
||||
*/ |
||||
public static final Type BOGUS = new Type(null, true); |
||||
|
||||
/** Represents the java.lang.Object reference type */ |
||||
public static final Type OBJECT = lookupType("java.lang.Object"); |
||||
/** Represents the java.io.Serializable reference type */ |
||||
public static final Type SERIALIZABLE = lookupType("java.io.Serializable"); |
||||
/** Represents the java.lang.Coneable reference type */ |
||||
public static final Type CLONEABLE = lookupType("java.lang.Cloneable"); |
||||
/** Represents the java.lang.Throwable reference type */ |
||||
public static final Type THROWABLE = lookupType("java.lang.Throwable"); |
||||
|
||||
static { |
||||
prims.put(CtClass.doubleType, DOUBLE); |
||||
prims.put(CtClass.longType, LONG); |
||||
prims.put(CtClass.charType, CHAR); |
||||
prims.put(CtClass.shortType, SHORT); |
||||
prims.put(CtClass.intType, INTEGER); |
||||
prims.put(CtClass.floatType, FLOAT); |
||||
prims.put(CtClass.byteType, BYTE); |
||||
prims.put(CtClass.booleanType, BOOLEAN); |
||||
prims.put(CtClass.voidType, VOID); |
||||
|
||||
} |
||||
|
||||
/** |
||||
* Obtain the Type for a given class. If the class is a primitive, |
||||
* the the unique type instance for the primitive will be returned. |
||||
* Otherwise a new Type instance representing the class is returned. |
||||
* |
||||
* @param clazz The java class
|
||||
* @return a type instance for this class
|
||||
*/ |
||||
public static Type get(CtClass clazz) { |
||||
Type type = (Type)prims.get(clazz); |
||||
return type != null ? type : new Type(clazz); |
||||
} |
||||
|
||||
private static Type lookupType(String name) { |
||||
try { |
||||
return new Type(ClassPool.getDefault().get(name)); |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
Type(CtClass clazz) { |
||||
this(clazz, false); |
||||
} |
||||
|
||||
private Type(CtClass clazz, boolean special) { |
||||
this.clazz = clazz; |
||||
this.special = special; |
||||
} |
||||
|
||||
// Used to indicate a merge internally triggered a change
|
||||
boolean popChanged() { |
||||
return false; |
||||
} |
||||
|
||||
/** |
||||
* Gets the word size of this type. Double-word types, such as long and double |
||||
* will occupy two positions on the local variable table or stack. |
||||
* |
||||
* @return the number of words needed to hold this type |
||||
*/ |
||||
public int getSize() { |
||||
return clazz == CtClass.doubleType || clazz == CtClass.longType || this == TOP ? 2 : 1; |
||||
} |
||||
|
||||
/** |
||||
* Returns the class this type represents. If the type is special, null will be returned. |
||||
* |
||||
* @return the class for this type, or null if special |
||||
*/ |
||||
public CtClass getCtClass() { |
||||
return clazz; |
||||
} |
||||
|
||||
/** |
||||
* Returns whether or not this type is a normal java reference, i.e. it is or extends java.lang.Object. |
||||
* |
||||
* @return true if a java reference, false if a primitive or special |
||||
*/ |
||||
public boolean isReference() { |
||||
return !special && (clazz == null || !clazz.isPrimitive()); |
||||
} |
||||
|
||||
/** |
||||
* Returns whether or not the type is special. A special type is one that is either used |
||||
* for internal tracking, or is only used internally by the JVM. |
||||
* |
||||
* @return true if special, false if not |
||||
*/ |
||||
public boolean isSpecial() { |
||||
return special; |
||||
} |
||||
|
||||
/** |
||||
* Returns whether or not this type is an array. |
||||
* |
||||
* @return true if an array, false if not |
||||
*/ |
||||
public boolean isArray() { |
||||
return clazz != null && clazz.isArray(); |
||||
} |
||||
|
||||
/** |
||||
* Returns the number of dimensions of this array. If the type is not an |
||||
* array zero is returned. |
||||
* |
||||
* @return zero if not an array, otherwise the number of array dimensions. |
||||
*/ |
||||
public int getDimensions() { |
||||
if (!isArray()) return 0; |
||||
|
||||
String name = clazz.getName(); |
||||
int pos = name.length() - 1; |
||||
int count = 0; |
||||
while (name.charAt(pos) == ']' ) { |
||||
pos -= 2; |
||||
count++; |
||||
} |
||||
|
||||
return count; |
||||
} |
||||
|
||||
/** |
||||
* Returns the array component if this type is an array. If the type |
||||
* is not an array null is returned. |
||||
* |
||||
* @return the array component if an array, otherwise null |
||||
*/ |
||||
public Type getComponent() { |
||||
if (this.clazz == null || !this.clazz.isArray()) |
||||
return null; |
||||
|
||||
CtClass component; |
||||
try { |
||||
component = this.clazz.getComponentType(); |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
Type type = (Type)prims.get(component); |
||||
return (type != null) ? type : new Type(component); |
||||
} |
||||
|
||||
/** |
||||
* Determines whether this type is assignable, to the passed type. |
||||
* A type is assignable to another if it is either the same type, or |
||||
* a sub-type. |
||||
* |
||||
* @param type the type to test assignability to |
||||
* @return true if this is assignable to type, otherwise false |
||||
*/ |
||||
public boolean isAssignableFrom(Type type) { |
||||
if (this == type) |
||||
return true; |
||||
|
||||
if ((type == UNINIT && isReference()) || this == UNINIT && type.isReference()) |
||||
return true; |
||||
|
||||
if (type instanceof MultiType) |
||||
return ((MultiType)type).isAssignableTo(this); |
||||
|
||||
if (type instanceof MultiArrayType) |
||||
return ((MultiArrayType)type).isAssignableTo(this); |
||||
|
||||
|
||||
// Primitives and Special types must be identical
|
||||
if (clazz == null || clazz.isPrimitive()) |
||||
return false; |
||||
|
||||
try { |
||||
return type.clazz.subtypeOf(clazz); |
||||
} catch (Exception e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Finds the common base type, or interface which both this and the specified |
||||
* type can be assigned. If there is more than one possible answer, then a {@link MultiType}, |
||||
* or a {@link MultiArrayType} is returned. Multi-types have special rules, |
||||
* and successive merges and assignment tests on them will alter their internal state, |
||||
* as well as other multi-types they have been merged with. This method is used by |
||||
* the data-flow analyzer to merge the type state from multiple branches. |
||||
* |
||||
* @param type the type to merge with |
||||
* @return the merged type |
||||
*/ |
||||
public Type merge(Type type) { |
||||
if (type == this) |
||||
return this; |
||||
if (type == null) |
||||
return this; |
||||
if (type == Type.UNINIT) |
||||
return this; |
||||
if (this == Type.UNINIT) |
||||
return type; |
||||
|
||||
// Unequal primitives and special types can not be merged
|
||||
if (! type.isReference() || ! this.isReference()) |
||||
return BOGUS; |
||||
|
||||
// Centralize merging of multi-interface types
|
||||
if (type instanceof MultiType) |
||||
return type.merge(this); |
||||
|
||||
if (type.isArray() && this.isArray()) |
||||
return mergeArray(type); |
||||
|
||||
try { |
||||
return mergeClasses(type); |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
Type getRootComponent(Type type) { |
||||
while (type.isArray()) |
||||
type = type.getComponent(); |
||||
|
||||
return type; |
||||
} |
||||
|
||||
private Type createArray(Type rootComponent, int dims) { |
||||
if (rootComponent instanceof MultiType) |
||||
return new MultiArrayType((MultiType) rootComponent, dims); |
||||
|
||||
String name = arrayName(rootComponent.clazz.getName(), dims); |
||||
|
||||
Type type; |
||||
try { |
||||
type = Type.get(getClassPool(rootComponent).get(name)); |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
return type; |
||||
} |
||||
|
||||
String arrayName(String component, int dims) { |
||||
// Using char[] since we have no StringBuilder in JDK4, and StringBuffer is slow.
|
||||
// Although, this is more efficient even if we did have one.
|
||||
int i = component.length(); |
||||
int size = i + dims * 2; |
||||
char[] string = new char[size]; |
||||
component.getChars(0, i, string, 0); |
||||
while (i < size) { |
||||
string[i++] = '['; |
||||
string[i++] = ']'; |
||||
} |
||||
component = new String(string); |
||||
return component; |
||||
} |
||||
|
||||
private ClassPool getClassPool(Type rootComponent) { |
||||
ClassPool pool = rootComponent.clazz.getClassPool(); |
||||
return pool != null ? pool : ClassPool.getDefault(); |
||||
} |
||||
|
||||
private Type mergeArray(Type type) { |
||||
Type typeRoot = getRootComponent(type); |
||||
Type thisRoot = getRootComponent(this); |
||||
int typeDims = type.getDimensions(); |
||||
int thisDims = this.getDimensions(); |
||||
|
||||
// Array commponents can be merged when the dimensions are equal
|
||||
if (typeDims == thisDims) { |
||||
Type mergedComponent = thisRoot.merge(typeRoot); |
||||
|
||||
// If the components can not be merged (a primitive component mixed with a different type)
|
||||
// then Object is the common type.
|
||||
if (mergedComponent == Type.BOGUS) |
||||
return Type.OBJECT; |
||||
|
||||
return createArray(mergedComponent, thisDims); |
||||
} |
||||
|
||||
Type targetRoot; |
||||
int targetDims; |
||||
|
||||
if (typeDims < thisDims) { |
||||
targetRoot = typeRoot; |
||||
targetDims = typeDims; |
||||
} else { |
||||
targetRoot = thisRoot; |
||||
targetDims = thisDims; |
||||
} |
||||
|
||||
// Special case, arrays are cloneable and serializable, so prefer them when dimensions differ
|
||||
if (eq(CLONEABLE.clazz, targetRoot.clazz) || eq(SERIALIZABLE.clazz, targetRoot.clazz)) |
||||
return createArray(targetRoot, targetDims); |
||||
|
||||
return createArray(OBJECT, targetDims); |
||||
} |
||||
|
||||
private static CtClass findCommonSuperClass(CtClass one, CtClass two) throws NotFoundException { |
||||
CtClass deep = one; |
||||
CtClass shallow = two; |
||||
CtClass backupShallow = shallow; |
||||
CtClass backupDeep = deep; |
||||
|
||||
// Phase 1 - Find the deepest hierarchy, set deep and shallow correctly
|
||||
for (;;) { |
||||
// In case we get lucky, and find a match early
|
||||
if (eq(deep, shallow) && deep.getSuperclass() != null) |
||||
return deep; |
||||
|
||||
CtClass deepSuper = deep.getSuperclass(); |
||||
CtClass shallowSuper = shallow.getSuperclass(); |
||||
|
||||
if (shallowSuper == null) { |
||||
// right, now reset shallow
|
||||
shallow = backupShallow; |
||||
break; |
||||
} |
||||
|
||||
if (deepSuper == null) { |
||||
// wrong, swap them, since deep is now useless, its our tmp before we swap it
|
||||
deep = backupDeep; |
||||
backupDeep = backupShallow; |
||||
backupShallow = deep; |
||||
|
||||
deep = shallow; |
||||
shallow = backupShallow; |
||||
break; |
||||
} |
||||
|
||||
deep = deepSuper; |
||||
shallow = shallowSuper; |
||||
} |
||||
|
||||
// Phase 2 - Move deepBackup up by (deep end - deep)
|
||||
for (;;) { |
||||
deep = deep.getSuperclass(); |
||||
if (deep == null) |
||||
break; |
||||
|
||||
backupDeep = backupDeep.getSuperclass(); |
||||
} |
||||
|
||||
deep = backupDeep; |
||||
|
||||
// Phase 3 - The hierarchy positions are now aligned
|
||||
// The common super class is easy to find now
|
||||
while (!eq(deep, shallow)) { |
||||
deep = deep.getSuperclass(); |
||||
shallow = shallow.getSuperclass(); |
||||
} |
||||
|
||||
return deep; |
||||
} |
||||
|
||||
private Type mergeClasses(Type type) throws NotFoundException { |
||||
CtClass superClass = findCommonSuperClass(this.clazz, type.clazz); |
||||
|
||||
// If its Object, then try and find a common interface(s)
|
||||
if (superClass.getSuperclass() == null) { |
||||
Map interfaces = findCommonInterfaces(type); |
||||
if (interfaces.size() == 1) |
||||
return new Type((CtClass) interfaces.values().iterator().next()); |
||||
if (interfaces.size() > 1) |
||||
return new MultiType(interfaces); |
||||
|
||||
// Only Object is in common
|
||||
return new Type(superClass); |
||||
} |
||||
|
||||
// Check for a common interface that is not on the found supertype
|
||||
Map commonDeclared = findExclusiveDeclaredInterfaces(type, superClass); |
||||
if (commonDeclared.size() > 0) { |
||||
return new MultiType(commonDeclared, new Type(superClass)); |
||||
} |
||||
|
||||
return new Type(superClass); |
||||
} |
||||
|
||||
private Map findCommonInterfaces(Type type) { |
||||
Map typeMap = getAllInterfaces(type.clazz, null); |
||||
Map thisMap = getAllInterfaces(this.clazz, null); |
||||
|
||||
return findCommonInterfaces(typeMap, thisMap); |
||||
} |
||||
|
||||
private Map findExclusiveDeclaredInterfaces(Type type, CtClass exclude) { |
||||
Map typeMap = getDeclaredInterfaces(type.clazz, null); |
||||
Map thisMap = getDeclaredInterfaces(this.clazz, null); |
||||
Map excludeMap = getAllInterfaces(exclude, null); |
||||
|
||||
Iterator i = excludeMap.keySet().iterator(); |
||||
while (i.hasNext()) { |
||||
Object intf = i.next(); |
||||
typeMap.remove(intf); |
||||
thisMap.remove(intf); |
||||
} |
||||
|
||||
return findCommonInterfaces(typeMap, thisMap); |
||||
} |
||||
|
||||
|
||||
Map findCommonInterfaces(Map typeMap, Map alterMap) { |
||||
Iterator i = alterMap.keySet().iterator(); |
||||
while (i.hasNext()) { |
||||
if (! typeMap.containsKey(i.next())) |
||||
i.remove(); |
||||
} |
||||
|
||||
// Reduce to subinterfaces
|
||||
// This does not need to be recursive since we make a copy,
|
||||
// and that copy contains all super types for the whole hierarchy
|
||||
i = new ArrayList(alterMap.values()).iterator(); |
||||
while (i.hasNext()) { |
||||
CtClass intf = (CtClass) i.next(); |
||||
CtClass[] interfaces; |
||||
try { |
||||
interfaces = intf.getInterfaces(); |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
for (int c = 0; c < interfaces.length; c++) |
||||
alterMap.remove(interfaces[c].getName()); |
||||
} |
||||
|
||||
return alterMap; |
||||
} |
||||
|
||||
Map getAllInterfaces(CtClass clazz, Map map) { |
||||
if (map == null) |
||||
map = new HashMap(); |
||||
|
||||
if (clazz.isInterface()) |
||||
map.put(clazz.getName(), clazz); |
||||
do { |
||||
try { |
||||
CtClass[] interfaces = clazz.getInterfaces(); |
||||
for (int i = 0; i < interfaces.length; i++) { |
||||
CtClass intf = interfaces[i]; |
||||
map.put(intf.getName(), intf); |
||||
getAllInterfaces(intf, map); |
||||
} |
||||
|
||||
clazz = clazz.getSuperclass(); |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} while (clazz != null); |
||||
|
||||
return map; |
||||
} |
||||
|
||||
Map getDeclaredInterfaces(CtClass clazz, Map map) { |
||||
if (map == null) |
||||
map = new HashMap(); |
||||
|
||||
if (clazz.isInterface()) |
||||
map.put(clazz.getName(), clazz); |
||||
|
||||
CtClass[] interfaces; |
||||
try { |
||||
interfaces = clazz.getInterfaces(); |
||||
} catch (NotFoundException e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
|
||||
for (int i = 0; i < interfaces.length; i++) { |
||||
CtClass intf = interfaces[i]; |
||||
map.put(intf.getName(), intf); |
||||
getDeclaredInterfaces(intf, map); |
||||
} |
||||
|
||||
return map; |
||||
} |
||||
|
||||
public boolean equals(Object o) { |
||||
if (! (o instanceof Type)) |
||||
return false; |
||||
|
||||
return o.getClass() == getClass() && eq(clazz, ((Type)o).clazz); |
||||
} |
||||
|
||||
static boolean eq(CtClass one, CtClass two) { |
||||
return one == two || (one != null && two != null && one.getName().equals(two.getName())); |
||||
} |
||||
|
||||
public String toString() { |
||||
if (this == BOGUS) |
||||
return "BOGUS"; |
||||
if (this == UNINIT) |
||||
return "UNINIT"; |
||||
if (this == RETURN_ADDRESS) |
||||
return "RETURN ADDRESS"; |
||||
if (this == TOP) |
||||
return "TOP"; |
||||
|
||||
return clazz == null ? "null" : clazz.getName(); |
||||
} |
||||
} |
@ -1,48 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.analysis; |
||||
|
||||
import com.fr.third.javassist.bytecode.CodeIterator; |
||||
import com.fr.third.javassist.bytecode.Opcode; |
||||
|
||||
/** |
||||
* A set of common utility methods. |
||||
* |
||||
* @author Jason T. Greene |
||||
*/ |
||||
public class Util implements Opcode { |
||||
public static int getJumpTarget(int pos, CodeIterator iter) { |
||||
int opcode = iter.byteAt(pos); |
||||
pos += (opcode == JSR_W || opcode == GOTO_W) ? iter.s32bitAt(pos + 1) : iter.s16bitAt(pos + 1); |
||||
return pos; |
||||
} |
||||
|
||||
public static boolean isJumpInstruction(int opcode) { |
||||
return (opcode >= IFEQ && opcode <= JSR) || opcode == IFNULL || opcode == IFNONNULL || opcode == JSR_W || opcode == GOTO_W; |
||||
} |
||||
|
||||
public static boolean isGoto(int opcode) { |
||||
return opcode == GOTO || opcode == GOTO_W; |
||||
} |
||||
|
||||
public static boolean isJsr(int opcode) { |
||||
return opcode == JSR || opcode == JSR_W; |
||||
} |
||||
|
||||
public static boolean isReturn(int opcode) { |
||||
return (opcode >= IRETURN && opcode <= RETURN); |
||||
} |
||||
} |
@ -1,20 +0,0 @@
|
||||
<html> |
||||
<body> |
||||
Bytecode Analysis API. |
||||
|
||||
<p>This package provides an API for performing data-flow analysis on a method's bytecode. |
||||
This allows the user to determine the type state of the stack and local variable table |
||||
at the start of every instruction. In addition this API can be used to validate |
||||
bytecode, find dead bytecode, and identify unnecessary checkcasts. |
||||
Look at <code>ControlFlow</code> class first for details. |
||||
|
||||
<p>The users of this package must know the specifications of |
||||
class file and Java bytecode. For more details, read this book: |
||||
|
||||
<ul>Tim Lindholm and Frank Yellin, |
||||
"The Java Virtual Machine Specification 2nd Ed.", |
||||
Addison-Wesley, 1999. |
||||
</ul> |
||||
|
||||
</body> |
||||
</html> |
@ -1,351 +0,0 @@
|
||||
/* |
||||
* Javassist, a Java-bytecode translator toolkit. |
||||
* Copyright (C) 2004 Bill Burke. 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import com.fr.third.javassist.bytecode.AnnotationDefaultAttribute; |
||||
import com.fr.third.javassist.bytecode.AnnotationsAttribute; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
import com.fr.third.javassist.bytecode.Descriptor; |
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.CtClass; |
||||
import com.fr.third.javassist.CtMethod; |
||||
import com.fr.third.javassist.NotFoundException; |
||||
import com.fr.third.javassist.bytecode.ParameterAnnotationsAttribute; |
||||
|
||||
import java.io.IOException; |
||||
import java.util.LinkedHashMap; |
||||
import java.util.Set; |
||||
import java.util.Iterator; |
||||
|
||||
/** |
||||
* The <code>annotation</code> structure. |
||||
* |
||||
* <p>An instance of this class is returned by |
||||
* <code>getAnnotations()</code> in <code>AnnotationsAttribute</code> |
||||
* or in <code>ParameterAnnotationsAttribute</code>. |
||||
* |
||||
* @see AnnotationsAttribute#getAnnotations() |
||||
* @see ParameterAnnotationsAttribute#getAnnotations() |
||||
* @see MemberValue |
||||
* @see MemberValueVisitor |
||||
* @see AnnotationsWriter |
||||
* |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author Shigeru Chiba |
||||
* @author <a href="mailto:adrian@jboss.org">Adrian Brock</a> |
||||
*/ |
||||
public class Annotation { |
||||
static class Pair { |
||||
int name; |
||||
MemberValue value; |
||||
} |
||||
|
||||
ConstPool pool; |
||||
int typeIndex; |
||||
LinkedHashMap members; // this sould be LinkedHashMap
|
||||
// but it is not supported by JDK 1.3.
|
||||
|
||||
/** |
||||
* Constructs an annotation including no members. A member can be |
||||
* later added to the created annotation by <code>addMemberValue()</code>. |
||||
* |
||||
* @param type the index into the constant pool table. |
||||
* the entry at that index must be the |
||||
* <code>CONSTANT_Utf8_Info</code> structure |
||||
* repreenting the name of the annotation interface type. |
||||
* @param cp the constant pool table. |
||||
* |
||||
* @see #addMemberValue(String, MemberValue) |
||||
*/ |
||||
public Annotation(int type, ConstPool cp) { |
||||
pool = cp; |
||||
typeIndex = type; |
||||
members = null; |
||||
} |
||||
|
||||
/** |
||||
* Constructs an annotation including no members. A member can be |
||||
* later added to the created annotation by <code>addMemberValue()</code>. |
||||
* |
||||
* @param typeName the name of the annotation interface type. |
||||
* @param cp the constant pool table. |
||||
* |
||||
* @see #addMemberValue(String, MemberValue) |
||||
*/ |
||||
public Annotation(String typeName, ConstPool cp) { |
||||
this(cp.addUtf8Info(Descriptor.of(typeName)), cp); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an annotation that can be accessed through the interface
|
||||
* represented by <code>clazz</code>. The values of the members are |
||||
* not specified. |
||||
* |
||||
* @param cp the constant pool table. |
||||
* @param clazz the interface. |
||||
* @throws NotFoundException when the clazz is not found |
||||
*/ |
||||
public Annotation(ConstPool cp, CtClass clazz) |
||||
throws NotFoundException |
||||
{ |
||||
// todo Enums are not supported right now.
|
||||
this(cp.addUtf8Info(Descriptor.of(clazz.getName())), cp); |
||||
|
||||
if (!clazz.isInterface()) |
||||
throw new RuntimeException( |
||||
"Only interfaces are allowed for Annotation creation."); |
||||
|
||||
CtMethod methods[] = clazz.getDeclaredMethods(); |
||||
if (methods.length > 0) { |
||||
members = new LinkedHashMap(); |
||||
} |
||||
|
||||
for (int i = 0; i < methods.length; i++) { |
||||
CtClass returnType = methods[i].getReturnType(); |
||||
addMemberValue(methods[i].getName(), |
||||
createMemberValue(cp, returnType)); |
||||
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Makes an instance of <code>MemberValue</code>. |
||||
* |
||||
* @param cp the constant pool table. |
||||
* @param type the type of the member. |
||||
* @return the member value |
||||
* @throws NotFoundException when the type is not found |
||||
*/ |
||||
public static MemberValue createMemberValue(ConstPool cp, CtClass type) |
||||
throws NotFoundException |
||||
{ |
||||
if (type == CtClass.booleanType) |
||||
return new BooleanMemberValue(cp); |
||||
else if (type == CtClass.byteType) |
||||
return new ByteMemberValue(cp); |
||||
else if (type == CtClass.charType) |
||||
return new CharMemberValue(cp); |
||||
else if (type == CtClass.shortType) |
||||
return new ShortMemberValue(cp); |
||||
else if (type == CtClass.intType) |
||||
return new IntegerMemberValue(cp); |
||||
else if (type == CtClass.longType) |
||||
return new LongMemberValue(cp); |
||||
else if (type == CtClass.floatType) |
||||
return new FloatMemberValue(cp); |
||||
else if (type == CtClass.doubleType) |
||||
return new DoubleMemberValue(cp); |
||||
else if (type.getName().equals("java.lang.Class")) |
||||
return new ClassMemberValue(cp); |
||||
else if (type.getName().equals("java.lang.String")) |
||||
return new StringMemberValue(cp); |
||||
else if (type.isArray()) { |
||||
CtClass arrayType = type.getComponentType(); |
||||
MemberValue member = createMemberValue(cp, arrayType); |
||||
return new ArrayMemberValue(member, cp); |
||||
} |
||||
else if (type.isInterface()) { |
||||
Annotation info = new Annotation(cp, type); |
||||
return new AnnotationMemberValue(info, cp); |
||||
} |
||||
else { |
||||
// treat as enum. I know this is not typed,
|
||||
// but JBoss has an Annotation Compiler for JDK 1.4
|
||||
// and I want it to work with that. - Bill Burke
|
||||
EnumMemberValue emv = new EnumMemberValue(cp); |
||||
emv.setType(type.getName()); |
||||
return emv; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Adds a new member. |
||||
* |
||||
* @param nameIndex the index into the constant pool table. |
||||
* The entry at that index must be |
||||
* a <code>CONSTANT_Utf8_info</code> structure. |
||||
* structure representing the member name. |
||||
* @param value the member value. |
||||
*/ |
||||
public void addMemberValue(int nameIndex, MemberValue value) { |
||||
Pair p = new Pair(); |
||||
p.name = nameIndex; |
||||
p.value = value; |
||||
addMemberValue(p); |
||||
} |
||||
|
||||
/** |
||||
* Adds a new member. |
||||
* |
||||
* @param name the member name. |
||||
* @param value the member value. |
||||
*/ |
||||
public void addMemberValue(String name, MemberValue value) { |
||||
Pair p = new Pair(); |
||||
p.name = pool.addUtf8Info(name); |
||||
p.value = value; |
||||
if (members == null) |
||||
members = new LinkedHashMap(); |
||||
|
||||
members.put(name, p); |
||||
} |
||||
|
||||
private void addMemberValue(Pair pair) { |
||||
String name = pool.getUtf8Info(pair.name); |
||||
if (members == null) |
||||
members = new LinkedHashMap(); |
||||
|
||||
members.put(name, pair); |
||||
} |
||||
|
||||
/** |
||||
* Returns a string representation of the annotation. |
||||
*/ |
||||
public String toString() { |
||||
StringBuffer buf = new StringBuffer("@"); |
||||
buf.append(getTypeName()); |
||||
if (members != null) { |
||||
buf.append("("); |
||||
Iterator mit = members.keySet().iterator(); |
||||
while (mit.hasNext()) { |
||||
String name = (String)mit.next(); |
||||
buf.append(name).append("=").append(getMemberValue(name)); |
||||
if (mit.hasNext()) |
||||
buf.append(", "); |
||||
} |
||||
buf.append(")"); |
||||
} |
||||
|
||||
return buf.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the name of the annotation type. |
||||
* |
||||
* @return the type name |
||||
*/ |
||||
public String getTypeName() { |
||||
return Descriptor.toClassName(pool.getUtf8Info(typeIndex)); |
||||
} |
||||
|
||||
/** |
||||
* Obtains all the member names. |
||||
* |
||||
* @return null if no members are defined. |
||||
*/ |
||||
public Set getMemberNames() { |
||||
if (members == null) |
||||
return null; |
||||
else |
||||
return members.keySet(); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the member value with the given name. |
||||
* |
||||
* <p>If this annotation does not have a value for the |
||||
* specified member, |
||||
* this method returns null. It does not return a |
||||
* <code>MemberValue</code> with the default value. |
||||
* The default value can be obtained from the annotation type. |
||||
* |
||||
* @param name the member name |
||||
* @return null if the member cannot be found or if the value is |
||||
* the default value. |
||||
* |
||||
* @see AnnotationDefaultAttribute |
||||
*/ |
||||
public MemberValue getMemberValue(String name) { |
||||
if (members == null) |
||||
return null; |
||||
else { |
||||
Pair p = (Pair)members.get(name); |
||||
if (p == null) |
||||
return null; |
||||
else |
||||
return p.value; |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Constructs an annotation-type object representing this annotation. |
||||
* For example, if this annotation represents <code>@Author</code>, |
||||
* this method returns an <code>Author</code> object. |
||||
* |
||||
* @param cl class loader for loading an annotation type. |
||||
* @param cp class pool for obtaining class files. |
||||
* @return the annotation |
||||
* @throws ClassNotFoundException if the class cannot found. |
||||
* @throws NoSuchClassError if the class linkage fails. |
||||
*/ |
||||
public Object toAnnotationType(ClassLoader cl, ClassPool cp) |
||||
throws ClassNotFoundException, NoSuchClassError |
||||
{ |
||||
return AnnotationImpl.make(cl, |
||||
MemberValue.loadClass(cl, getTypeName()), |
||||
cp, this); |
||||
} |
||||
|
||||
/** |
||||
* Writes this annotation. |
||||
* |
||||
* @param writer the output. |
||||
* @throws IOException for an error during the write |
||||
*/ |
||||
public void write(AnnotationsWriter writer) throws IOException { |
||||
String typeName = pool.getUtf8Info(typeIndex); |
||||
if (members == null) { |
||||
writer.annotation(typeName, 0); |
||||
return; |
||||
} |
||||
|
||||
writer.annotation(typeName, members.size()); |
||||
Iterator it = members.values().iterator(); |
||||
while (it.hasNext()) { |
||||
Pair pair = (Pair)it.next(); |
||||
writer.memberValuePair(pair.name); |
||||
pair.value.write(writer); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Returns true if the given object represents the same annotation |
||||
* as this object. The equality test checks the member values. |
||||
*/ |
||||
public boolean equals(Object obj) { |
||||
if (obj == this) |
||||
return true; |
||||
if (obj == null || obj instanceof Annotation == false) |
||||
return false; |
||||
|
||||
Annotation other = (Annotation) obj; |
||||
|
||||
if (getTypeName().equals(other.getTypeName()) == false) |
||||
return false; |
||||
|
||||
LinkedHashMap otherMembers = other.members; |
||||
if (members == otherMembers) |
||||
return true; |
||||
else if (members == null) |
||||
return otherMembers == null; |
||||
else |
||||
if (otherMembers == null) |
||||
return false; |
||||
else |
||||
return members.equals(otherMembers); |
||||
} |
||||
} |
@ -1,305 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import java.lang.reflect.InvocationHandler; |
||||
import java.lang.reflect.Method; |
||||
import java.lang.reflect.Proxy; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.CtClass; |
||||
import com.fr.third.javassist.NotFoundException; |
||||
import com.fr.third.javassist.bytecode.AnnotationDefaultAttribute; |
||||
import com.fr.third.javassist.bytecode.ClassFile; |
||||
import com.fr.third.javassist.bytecode.MethodInfo; |
||||
|
||||
/** |
||||
* Internal-use only. This is a helper class internally used for implementing |
||||
* <code>toAnnotationType()</code> in <code>Annotation</code>. |
||||
* |
||||
* @author Shigeru Chiba |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author <a href="mailto:adrian@jboss.org">Adrian Brock</a> |
||||
*/ |
||||
public class AnnotationImpl implements InvocationHandler { |
||||
private static final String JDK_ANNOTATION_CLASS_NAME = "java.lang.annotation.Annotation"; |
||||
private static Method JDK_ANNOTATION_TYPE_METHOD = null; |
||||
|
||||
private com.fr.third.javassist.bytecode.annotation.Annotation annotation; |
||||
private ClassPool pool; |
||||
private ClassLoader classLoader; |
||||
private transient Class annotationType; |
||||
private transient int cachedHashCode = Integer.MIN_VALUE; |
||||
|
||||
static { |
||||
// Try to resolve the JDK annotation type method
|
||||
try { |
||||
Class clazz = Class.forName(JDK_ANNOTATION_CLASS_NAME); |
||||
JDK_ANNOTATION_TYPE_METHOD = clazz.getMethod("annotationType", (Class[])null); |
||||
} |
||||
catch (Exception ignored) { |
||||
// Probably not JDK5+
|
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Constructs an annotation object. |
||||
* |
||||
* @param cl class loader for obtaining annotation types. |
||||
* @param clazz the annotation type. |
||||
* @param cp class pool for containing an annotation |
||||
* type (or null). |
||||
* @param anon the annotation. |
||||
* @return the annotation |
||||
*/ |
||||
public static Object make(ClassLoader cl, Class clazz, ClassPool cp, |
||||
com.fr.third.javassist.bytecode.annotation.Annotation anon) { |
||||
AnnotationImpl handler = new AnnotationImpl(anon, cp, cl); |
||||
return Proxy.newProxyInstance(cl, new Class[] { clazz }, handler); |
||||
} |
||||
|
||||
private AnnotationImpl(com.fr.third.javassist.bytecode.annotation.Annotation a, ClassPool cp, ClassLoader loader) { |
||||
annotation = a; |
||||
pool = cp; |
||||
classLoader = loader; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the name of the annotation type. |
||||
* |
||||
* @return the type name |
||||
*/ |
||||
public String getTypeName() { |
||||
return annotation.getTypeName(); |
||||
} |
||||
|
||||
/** |
||||
* Get the annotation type |
||||
* |
||||
* @return the annotation class
|
||||
* @throws NoClassDefFoundError when the class could not loaded |
||||
*/ |
||||
private Class getAnnotationType() { |
||||
if (annotationType == null) { |
||||
String typeName = annotation.getTypeName(); |
||||
try { |
||||
annotationType = classLoader.loadClass(typeName); |
||||
} |
||||
catch (ClassNotFoundException e) { |
||||
NoClassDefFoundError error = new NoClassDefFoundError("Error loading annotation class: " + typeName); |
||||
error.setStackTrace(e.getStackTrace()); |
||||
throw error; |
||||
} |
||||
} |
||||
return annotationType; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the internal data structure representing the annotation. |
||||
* |
||||
* @return the annotation |
||||
*/ |
||||
public Annotation getAnnotation() { |
||||
return annotation; |
||||
} |
||||
|
||||
/** |
||||
* Executes a method invocation on a proxy instance. |
||||
* The implementations of <code>toString()</code>, <code>equals()</code>, |
||||
* and <code>hashCode()</code> are directly supplied by the |
||||
* <code>AnnotationImpl</code>. The <code>annotationType()</code> method |
||||
* is also available on the proxy instance. |
||||
*/ |
||||
public Object invoke(Object proxy, Method method, Object[] args) |
||||
throws Throwable |
||||
{ |
||||
String name = method.getName(); |
||||
if (Object.class == method.getDeclaringClass()) { |
||||
if ("equals".equals(name)) { |
||||
Object obj = args[0]; |
||||
return new Boolean(checkEquals(obj)); |
||||
} |
||||
else if ("toString".equals(name)) |
||||
return annotation.toString(); |
||||
else if ("hashCode".equals(name)) |
||||
return new Integer(hashCode()); |
||||
} |
||||
else if ("annotationType".equals(name) |
||||
&& method.getParameterTypes().length == 0) |
||||
return getAnnotationType(); |
||||
|
||||
com.fr.third.javassist.bytecode.annotation.MemberValue mv = annotation.getMemberValue(name); |
||||
if (mv == null) |
||||
return getDefault(name, method); |
||||
else |
||||
return mv.getValue(classLoader, pool, method); |
||||
} |
||||
|
||||
private Object getDefault(String name, Method method) |
||||
throws ClassNotFoundException, RuntimeException |
||||
{ |
||||
String classname = annotation.getTypeName(); |
||||
if (pool != null) { |
||||
try { |
||||
CtClass cc = pool.get(classname); |
||||
ClassFile cf = cc.getClassFile2(); |
||||
MethodInfo minfo = cf.getMethod(name); |
||||
if (minfo != null) { |
||||
AnnotationDefaultAttribute ainfo |
||||
= (AnnotationDefaultAttribute) |
||||
minfo.getAttribute(AnnotationDefaultAttribute.tag); |
||||
if (ainfo != null) { |
||||
com.fr.third.javassist.bytecode.annotation.MemberValue mv = ainfo.getDefaultValue(); |
||||
return mv.getValue(classLoader, pool, method); |
||||
} |
||||
} |
||||
} |
||||
catch (NotFoundException e) { |
||||
throw new RuntimeException("cannot find a class file: " |
||||
+ classname); |
||||
} |
||||
} |
||||
|
||||
throw new RuntimeException("no default value: " + classname + "." |
||||
+ name + "()"); |
||||
} |
||||
|
||||
/** |
||||
* Returns a hash code value for this object. |
||||
*/ |
||||
public int hashCode() { |
||||
if (cachedHashCode == Integer.MIN_VALUE) { |
||||
int hashCode = 0; |
||||
|
||||
// Load the annotation class
|
||||
getAnnotationType(); |
||||
|
||||
Method[] methods = annotationType.getDeclaredMethods(); |
||||
for (int i = 0; i < methods.length; ++ i) { |
||||
String name = methods[i].getName(); |
||||
int valueHashCode = 0; |
||||
|
||||
// Get the value
|
||||
com.fr.third.javassist.bytecode.annotation.MemberValue mv = annotation.getMemberValue(name); |
||||
Object value = null; |
||||
try { |
||||
if (mv != null) |
||||
value = mv.getValue(classLoader, pool, methods[i]); |
||||
if (value == null) |
||||
value = getDefault(name, methods[i]); |
||||
} |
||||
catch (RuntimeException e) { |
||||
throw e; |
||||
} |
||||
catch (Exception e) { |
||||
throw new RuntimeException("Error retrieving value " + name + " for annotation " + annotation.getTypeName(), e); |
||||
} |
||||
|
||||
// Calculate the hash code
|
||||
if (value != null) { |
||||
if (value.getClass().isArray()) |
||||
valueHashCode = arrayHashCode(value); |
||||
else |
||||
valueHashCode = value.hashCode(); |
||||
} |
||||
hashCode += 127 * name.hashCode() ^ valueHashCode; |
||||
} |
||||
|
||||
cachedHashCode = hashCode; |
||||
} |
||||
return cachedHashCode; |
||||
} |
||||
|
||||
/** |
||||
* Check that another annotation equals ourselves. |
||||
* |
||||
* @param obj the other annotation |
||||
* @return the true when equals false otherwise |
||||
* @throws Exception for any problem |
||||
*/ |
||||
private boolean checkEquals(Object obj) throws Exception { |
||||
if (obj == null) |
||||
return false; |
||||
|
||||
// Optimization when the other is one of ourselves
|
||||
if (obj instanceof Proxy) { |
||||
InvocationHandler ih = Proxy.getInvocationHandler(obj); |
||||
if (ih instanceof AnnotationImpl) { |
||||
AnnotationImpl other = (AnnotationImpl) ih; |
||||
return annotation.equals(other.annotation); |
||||
} |
||||
} |
||||
|
||||
Class otherAnnotationType = (Class) JDK_ANNOTATION_TYPE_METHOD.invoke(obj, (Object[])null); |
||||
if (getAnnotationType().equals(otherAnnotationType) == false) |
||||
return false; |
||||
|
||||
Method[] methods = annotationType.getDeclaredMethods(); |
||||
for (int i = 0; i < methods.length; ++ i) { |
||||
String name = methods[i].getName(); |
||||
|
||||
// Get the value
|
||||
MemberValue mv = annotation.getMemberValue(name); |
||||
Object value = null; |
||||
Object otherValue = null; |
||||
try { |
||||
if (mv != null) |
||||
value = mv.getValue(classLoader, pool, methods[i]); |
||||
if (value == null) |
||||
value = getDefault(name, methods[i]); |
||||
otherValue = methods[i].invoke(obj, (Object[])null); |
||||
} |
||||
catch (RuntimeException e) { |
||||
throw e; |
||||
} |
||||
catch (Exception e) { |
||||
throw new RuntimeException("Error retrieving value " + name + " for annotation " + annotation.getTypeName(), e); |
||||
} |
||||
|
||||
if (value == null && otherValue != null) |
||||
return false; |
||||
if (value != null && value.equals(otherValue) == false) |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/** |
||||
* Calculates the hashCode of an array using the same |
||||
* algorithm as java.util.Arrays.hashCode() |
||||
* |
||||
* @param object the object |
||||
* @return the hashCode |
||||
*/ |
||||
private static int arrayHashCode(Object object) |
||||
{ |
||||
if (object == null) |
||||
return 0; |
||||
|
||||
int result = 1; |
||||
|
||||
Object[] array = (Object[]) object; |
||||
for (int i = 0; i < array.length; ++i) { |
||||
int elementHashCode = 0; |
||||
if (array[i] != null) |
||||
elementHashCode = array[i].hashCode(); |
||||
result = 31 * result + elementHashCode; |
||||
} |
||||
return result; |
||||
} |
||||
} |
@ -1,97 +0,0 @@
|
||||
/* |
||||
* Javassist, a Java-bytecode translator toolkit. |
||||
* Copyright (C) 2004 Bill Burke. 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.reflect.Method; |
||||
|
||||
/** |
||||
* Nested annotation. |
||||
* |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author Shigeru Chiba |
||||
*/ |
||||
public class AnnotationMemberValue extends MemberValue { |
||||
com.fr.third.javassist.bytecode.annotation.Annotation value; |
||||
|
||||
/** |
||||
* Constructs an annotation member. The initial value is not specified. |
||||
*/ |
||||
public AnnotationMemberValue(ConstPool cp) { |
||||
this(null, cp); |
||||
} |
||||
|
||||
/** |
||||
* Constructs an annotation member. The initial value is specified by |
||||
* the first parameter. |
||||
*/ |
||||
public AnnotationMemberValue(com.fr.third.javassist.bytecode.annotation.Annotation a, ConstPool cp) { |
||||
super('@', cp); |
||||
value = a; |
||||
} |
||||
|
||||
Object getValue(ClassLoader cl, ClassPool cp, Method m) |
||||
throws ClassNotFoundException |
||||
{ |
||||
return AnnotationImpl.make(cl, getType(cl), cp, value); |
||||
} |
||||
|
||||
Class getType(ClassLoader cl) throws ClassNotFoundException { |
||||
if (value == null) |
||||
throw new ClassNotFoundException("no type specified"); |
||||
else |
||||
return loadClass(cl, value.getTypeName()); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the value. |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.annotation.Annotation getValue() { |
||||
return value; |
||||
} |
||||
|
||||
/** |
||||
* Sets the value of this member. |
||||
*/ |
||||
public void setValue(Annotation newValue) { |
||||
value = newValue; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
return value.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Writes the value. |
||||
*/ |
||||
public void write(AnnotationsWriter writer) throws IOException { |
||||
writer.annotationValue(); |
||||
value.write(writer); |
||||
} |
||||
|
||||
/** |
||||
* Accepts a visitor. |
||||
*/ |
||||
public void accept(MemberValueVisitor visitor) { |
||||
visitor.visitAnnotationMemberValue(this); |
||||
} |
||||
} |
@ -1,356 +0,0 @@
|
||||
/* |
||||
* 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import java.io.*; |
||||
|
||||
import com.fr.third.javassist.bytecode.AnnotationsAttribute; |
||||
import com.fr.third.javassist.bytecode.ByteArray; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
import com.fr.third.javassist.bytecode.ParameterAnnotationsAttribute; |
||||
|
||||
/** |
||||
* A convenience class for constructing a |
||||
* <code>..Annotations_attribute</code>. |
||||
* See the source code of the <code>AnnotationsAttribute.Copier</code> class. |
||||
* |
||||
* <p>The following code snippet is an example of use of this class: |
||||
* |
||||
* <ul><pre> |
||||
* ConstPool pool = ...; |
||||
* output = new ByteArrayOutputStream(); |
||||
* writer = new AnnotationsWriter(output, pool); |
||||
* |
||||
* writer.numAnnotations(1); |
||||
* writer.annotation("Author", 2); |
||||
* writer.memberValuePair("name"); |
||||
* writer.constValueIndex("chiba"); |
||||
* writer.memberValuePair("address"); |
||||
* writer.constValueIndex("tokyo"); |
||||
* |
||||
* writer.close(); |
||||
* byte[] attribute_info = output.toByteArray(); |
||||
* AnnotationsAttribute anno |
||||
* = new AnnotationsAttribute(pool, AnnotationsAttribute.visibleTag, |
||||
* attribute_info); |
||||
* </pre></ul> |
||||
* |
||||
* <p>The code snippet above generates the annotation attribute |
||||
* corresponding to this annotation: |
||||
* |
||||
* <ul><pre> |
||||
* @Author(name = "chiba", address = "tokyo") |
||||
* </pre></ul> |
||||
* |
||||
* @see AnnotationsAttribute |
||||
* @see ParameterAnnotationsAttribute |
||||
*/ |
||||
public class AnnotationsWriter { |
||||
private OutputStream output; |
||||
private ConstPool pool; |
||||
|
||||
/** |
||||
* Constructs with the given output stream. |
||||
* |
||||
* @param os the output stream. |
||||
* @param cp the constant pool. |
||||
*/ |
||||
public AnnotationsWriter(OutputStream os, ConstPool cp) { |
||||
output = os; |
||||
pool = cp; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the constant pool given to the constructor. |
||||
*/ |
||||
public ConstPool getConstPool() { |
||||
return pool; |
||||
} |
||||
|
||||
/** |
||||
* Closes the output stream. |
||||
* |
||||
*/ |
||||
public void close() throws IOException { |
||||
output.close(); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>num_parameters</code> in |
||||
* <code>Runtime(In)VisibleParameterAnnotations_attribute</code>. |
||||
* This method must be followed by <code>num</code> calls to |
||||
* <code>numAnnotations()</code>. |
||||
*/ |
||||
public void numParameters(int num) throws IOException { |
||||
output.write(num); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>num_annotations</code> in |
||||
* <code>Runtime(In)VisibleAnnotations_attribute</code>. |
||||
* This method must be followed by <code>num</code> calls to |
||||
* <code>annotation()</code>. |
||||
*/ |
||||
public void numAnnotations(int num) throws IOException { |
||||
write16bit(num); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>annotation</code>. |
||||
* This method must be followed by <code>numMemberValuePairs</code> |
||||
* calls to <code>memberValuePair()</code>. |
||||
* |
||||
* @param type the annotation interface name. |
||||
* @param numMemberValuePairs <code>num_member_value_pairs</code> |
||||
* in <code>annotation</code>. |
||||
*/ |
||||
public void annotation(String type, int numMemberValuePairs) |
||||
throws IOException |
||||
{ |
||||
annotation(pool.addUtf8Info(type), numMemberValuePairs); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>annotation</code>. |
||||
* This method must be followed by <code>numMemberValuePairs</code> |
||||
* calls to <code>memberValuePair()</code>. |
||||
* |
||||
* @param typeIndex <code>type_index</code> in <code>annotation</code>. |
||||
* @param numMemberValuePairs <code>num_member_value_pairs</code> |
||||
* in <code>annotation</code>. |
||||
*/ |
||||
public void annotation(int typeIndex, int numMemberValuePairs) |
||||
throws IOException |
||||
{ |
||||
write16bit(typeIndex); |
||||
write16bit(numMemberValuePairs); |
||||
} |
||||
|
||||
/** |
||||
* Writes an element of a <code>member_value_pairs</code> array |
||||
* in <code>annotation</code>. |
||||
* This method must be followed by a |
||||
* call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, |
||||
* etc. |
||||
* |
||||
* @param memberName the name of the annotation type member. |
||||
*/ |
||||
public void memberValuePair(String memberName) throws IOException { |
||||
memberValuePair(pool.addUtf8Info(memberName)); |
||||
} |
||||
|
||||
/** |
||||
* Writes an element of a <code>member_value_pairs</code> array |
||||
* in <code>annotation</code>. |
||||
* This method must be followed by a |
||||
* call to <code>constValueIndex()</code>, <code>enumConstValue()</code>, |
||||
* etc. |
||||
* |
||||
* @param memberNameIndex <code>member_name_index</code> |
||||
* in <code>member_value_pairs</code> array. |
||||
*/ |
||||
public void memberValuePair(int memberNameIndex) throws IOException { |
||||
write16bit(memberNameIndex); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param value the constant value. |
||||
*/ |
||||
public void constValueIndex(boolean value) throws IOException { |
||||
constValueIndex('Z', pool.addIntegerInfo(value ? 1 : 0)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param value the constant value. |
||||
*/ |
||||
public void constValueIndex(byte value) throws IOException { |
||||
constValueIndex('B', pool.addIntegerInfo(value)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param value the constant value. |
||||
*/ |
||||
public void constValueIndex(char value) throws IOException { |
||||
constValueIndex('C', pool.addIntegerInfo(value)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param value the constant value. |
||||
*/ |
||||
public void constValueIndex(short value) throws IOException { |
||||
constValueIndex('S', pool.addIntegerInfo(value)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param value the constant value. |
||||
*/ |
||||
public void constValueIndex(int value) throws IOException { |
||||
constValueIndex('I', pool.addIntegerInfo(value)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param value the constant value. |
||||
*/ |
||||
public void constValueIndex(long value) throws IOException { |
||||
constValueIndex('J', pool.addLongInfo(value)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param value the constant value. |
||||
*/ |
||||
public void constValueIndex(float value) throws IOException { |
||||
constValueIndex('F', pool.addFloatInfo(value)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param value the constant value. |
||||
*/ |
||||
public void constValueIndex(double value) throws IOException { |
||||
constValueIndex('D', pool.addDoubleInfo(value)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param value the constant value. |
||||
*/ |
||||
public void constValueIndex(String value) throws IOException { |
||||
constValueIndex('s', pool.addUtf8Info(value)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param tag <code>tag</code> in <code>member_value</code>. |
||||
* @param index <code>const_value_index</code> |
||||
* in <code>member_value</code>. |
||||
*/ |
||||
public void constValueIndex(int tag, int index) |
||||
throws IOException |
||||
{ |
||||
output.write(tag); |
||||
write16bit(index); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>enum_const_value</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param typeName the type name of the enum constant. |
||||
* @param constName the simple name of the enum constant. |
||||
*/ |
||||
public void enumConstValue(String typeName, String constName) |
||||
throws IOException |
||||
{ |
||||
enumConstValue(pool.addUtf8Info(typeName), |
||||
pool.addUtf8Info(constName)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>enum_const_value</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param typeNameIndex <code>type_name_index</code> |
||||
* in <code>member_value</code>. |
||||
* @param constNameIndex <code>const_name_index</code> |
||||
* in <code>member_value</code>. |
||||
*/ |
||||
public void enumConstValue(int typeNameIndex, int constNameIndex) |
||||
throws IOException |
||||
{ |
||||
output.write('e'); |
||||
write16bit(typeNameIndex); |
||||
write16bit(constNameIndex); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>class_info_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param name the class name. |
||||
*/ |
||||
public void classInfoIndex(String name) throws IOException { |
||||
classInfoIndex(pool.addUtf8Info(name)); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>class_info_index</code> |
||||
* in <code>member_value</code>. |
||||
* |
||||
* @param index <code>class_info_index</code> |
||||
*/ |
||||
public void classInfoIndex(int index) throws IOException { |
||||
output.write('c'); |
||||
write16bit(index); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>annotation_value</code> |
||||
* in <code>member_value</code>. |
||||
* This method must be followed by a call to <code>annotation()</code>. |
||||
*/ |
||||
public void annotationValue() throws IOException { |
||||
output.write('@'); |
||||
} |
||||
|
||||
/** |
||||
* Writes <code>tag</code> and <code>array_value</code> |
||||
* in <code>member_value</code>. |
||||
* This method must be followed by <code>numValues</code> calls |
||||
* to <code>constValueIndex()</code>, <code>enumConstValue()</code>, |
||||
* etc. |
||||
* |
||||
* @param numValues <code>num_values</code> |
||||
* in <code>array_value</code>. |
||||
*/ |
||||
public void arrayValue(int numValues) throws IOException { |
||||
output.write('['); |
||||
write16bit(numValues); |
||||
} |
||||
|
||||
private void write16bit(int value) throws IOException { |
||||
byte[] buf = new byte[2]; |
||||
ByteArray.write16bit(value, buf, 0); |
||||
output.write(buf); |
||||
} |
||||
} |
@ -1,146 +0,0 @@
|
||||
/* |
||||
* Javassist, a Java-bytecode translator toolkit. |
||||
* Copyright (C) 2004 Bill Burke. 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.reflect.Array; |
||||
import java.lang.reflect.Method; |
||||
|
||||
/** |
||||
* Array member. |
||||
* |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author Shigeru Chiba |
||||
*/ |
||||
public class ArrayMemberValue extends com.fr.third.javassist.bytecode.annotation.MemberValue { |
||||
com.fr.third.javassist.bytecode.annotation.MemberValue type; |
||||
com.fr.third.javassist.bytecode.annotation.MemberValue[] values; |
||||
|
||||
/** |
||||
* Constructs an array. The initial value or type are not specified. |
||||
*/ |
||||
public ArrayMemberValue(ConstPool cp) { |
||||
super('[', cp); |
||||
type = null; |
||||
values = null; |
||||
} |
||||
|
||||
/** |
||||
* Constructs an array. The initial value is not specified. |
||||
* |
||||
* @param t the type of the array elements. |
||||
*/ |
||||
public ArrayMemberValue(com.fr.third.javassist.bytecode.annotation.MemberValue t, ConstPool cp) { |
||||
super('[', cp); |
||||
type = t; |
||||
values = null; |
||||
} |
||||
|
||||
Object getValue(ClassLoader cl, ClassPool cp, Method method) |
||||
throws ClassNotFoundException |
||||
{ |
||||
if (values == null) |
||||
throw new ClassNotFoundException( |
||||
"no array elements found: " + method.getName()); |
||||
|
||||
int size = values.length; |
||||
Class clazz; |
||||
if (type == null) { |
||||
clazz = method.getReturnType().getComponentType(); |
||||
if (clazz == null || size > 0) |
||||
throw new ClassNotFoundException("broken array type: " |
||||
+ method.getName()); |
||||
} |
||||
else |
||||
clazz = type.getType(cl); |
||||
|
||||
Object a = Array.newInstance(clazz, size); |
||||
for (int i = 0; i < size; i++) |
||||
Array.set(a, i, values[i].getValue(cl, cp, method)); |
||||
|
||||
return a; |
||||
} |
||||
|
||||
Class getType(ClassLoader cl) throws ClassNotFoundException { |
||||
if (type == null) |
||||
throw new ClassNotFoundException("no array type specified"); |
||||
|
||||
Object a = Array.newInstance(type.getType(cl), 0); |
||||
return a.getClass(); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the type of the elements. |
||||
* |
||||
* @return null if the type is not specified. |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.annotation.MemberValue getType() { |
||||
return type; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the elements of the array. |
||||
*/ |
||||
public com.fr.third.javassist.bytecode.annotation.MemberValue[] getValue() { |
||||
return values; |
||||
} |
||||
|
||||
/** |
||||
* Sets the elements of the array. |
||||
*/ |
||||
public void setValue(MemberValue[] elements) { |
||||
values = elements; |
||||
if (elements != null && elements.length > 0) |
||||
type = elements[0]; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
StringBuffer buf = new StringBuffer("{"); |
||||
if (values != null) { |
||||
for (int i = 0; i < values.length; i++) { |
||||
buf.append(values[i].toString()); |
||||
if (i + 1 < values.length) |
||||
buf.append(", "); |
||||
} |
||||
} |
||||
|
||||
buf.append("}"); |
||||
return buf.toString(); |
||||
} |
||||
|
||||
/** |
||||
* Writes the value. |
||||
*/ |
||||
public void write(AnnotationsWriter writer) throws IOException { |
||||
int num = values.length; |
||||
writer.arrayValue(num); |
||||
for (int i = 0; i < num; ++i) |
||||
values[i].write(writer); |
||||
} |
||||
|
||||
/** |
||||
* Accepts a visitor. |
||||
*/ |
||||
public void accept(MemberValueVisitor visitor) { |
||||
visitor.visitArrayMemberValue(this); |
||||
} |
||||
} |
@ -1,104 +0,0 @@
|
||||
/* |
||||
* Javassist, a Java-bytecode translator toolkit. |
||||
* Copyright (C) 2004 Bill Burke. 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.reflect.Method; |
||||
|
||||
/** |
||||
* Boolean constant value. |
||||
* |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author Shigeru Chiba |
||||
*/ |
||||
public class BooleanMemberValue extends MemberValue { |
||||
int valueIndex; |
||||
|
||||
/** |
||||
* Constructs a boolean constant value. The initial value is specified |
||||
* by the constant pool entry at the given index. |
||||
* |
||||
* @param index the index of a CONSTANT_Integer_info structure. |
||||
*/ |
||||
public BooleanMemberValue(int index, ConstPool cp) { |
||||
super('Z', cp); |
||||
this.valueIndex = index; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a boolean constant value. |
||||
* |
||||
* @param b the initial value. |
||||
*/ |
||||
public BooleanMemberValue(boolean b, ConstPool cp) { |
||||
super('Z', cp); |
||||
setValue(b); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a boolean constant value. The initial value is false. |
||||
*/ |
||||
public BooleanMemberValue(ConstPool cp) { |
||||
super('Z', cp); |
||||
setValue(false); |
||||
} |
||||
|
||||
Object getValue(ClassLoader cl, ClassPool cp, Method m) { |
||||
return new Boolean(getValue()); |
||||
} |
||||
|
||||
Class getType(ClassLoader cl) { |
||||
return boolean.class; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the value of the member. |
||||
*/ |
||||
public boolean getValue() { |
||||
return cp.getIntegerInfo(valueIndex) != 0; |
||||
} |
||||
|
||||
/** |
||||
* Sets the value of the member. |
||||
*/ |
||||
public void setValue(boolean newValue) { |
||||
valueIndex = cp.addIntegerInfo(newValue ? 1 : 0); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
return getValue() ? "true" : "false"; |
||||
} |
||||
|
||||
/** |
||||
* Writes the value. |
||||
*/ |
||||
public void write(AnnotationsWriter writer) throws IOException { |
||||
writer.constValueIndex(getValue()); |
||||
} |
||||
|
||||
/** |
||||
* Accepts a visitor. |
||||
*/ |
||||
public void accept(MemberValueVisitor visitor) { |
||||
visitor.visitBooleanMemberValue(this); |
||||
} |
||||
} |
@ -1,104 +0,0 @@
|
||||
/* |
||||
* Javassist, a Java-bytecode translator toolkit. |
||||
* Copyright (C) 2004 Bill Burke. 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.reflect.Method; |
||||
|
||||
/** |
||||
* Byte constant value. |
||||
* |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author Shigeru Chiba |
||||
*/ |
||||
public class ByteMemberValue extends MemberValue { |
||||
int valueIndex; |
||||
|
||||
/** |
||||
* Constructs a byte constant value. The initial value is specified |
||||
* by the constant pool entry at the given index. |
||||
* |
||||
* @param index the index of a CONSTANT_Integer_info structure. |
||||
*/ |
||||
public ByteMemberValue(int index, ConstPool cp) { |
||||
super('B', cp); |
||||
this.valueIndex = index; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a byte constant value. |
||||
* |
||||
* @param b the initial value. |
||||
*/ |
||||
public ByteMemberValue(byte b, ConstPool cp) { |
||||
super('B', cp); |
||||
setValue(b); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a byte constant value. The initial value is 0. |
||||
*/ |
||||
public ByteMemberValue(ConstPool cp) { |
||||
super('B', cp); |
||||
setValue((byte)0); |
||||
} |
||||
|
||||
Object getValue(ClassLoader cl, ClassPool cp, Method m) { |
||||
return new Byte(getValue()); |
||||
} |
||||
|
||||
Class getType(ClassLoader cl) { |
||||
return byte.class; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the value of the member. |
||||
*/ |
||||
public byte getValue() { |
||||
return (byte)cp.getIntegerInfo(valueIndex); |
||||
} |
||||
|
||||
/** |
||||
* Sets the value of the member. |
||||
*/ |
||||
public void setValue(byte newValue) { |
||||
valueIndex = cp.addIntegerInfo(newValue); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
return Byte.toString(getValue()); |
||||
} |
||||
|
||||
/** |
||||
* Writes the value. |
||||
*/ |
||||
public void write(AnnotationsWriter writer) throws IOException { |
||||
writer.constValueIndex(getValue()); |
||||
} |
||||
|
||||
/** |
||||
* Accepts a visitor. |
||||
*/ |
||||
public void accept(MemberValueVisitor visitor) { |
||||
visitor.visitByteMemberValue(this); |
||||
} |
||||
} |
@ -1,105 +0,0 @@
|
||||
/* |
||||
* Javassist, a Java-bytecode translator toolkit. |
||||
* Copyright (C) 2004 Bill Burke. 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.reflect.Method; |
||||
|
||||
/** |
||||
* Char constant value. |
||||
* |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author Shigeru Chiba |
||||
*/ |
||||
public class CharMemberValue extends MemberValue { |
||||
int valueIndex; |
||||
|
||||
/** |
||||
* Constructs a char constant value. The initial value is specified |
||||
* by the constant pool entry at the given index. |
||||
* |
||||
* @param index the index of a CONSTANT_Integer_info structure. |
||||
*/ |
||||
public CharMemberValue(int index, ConstPool cp) { |
||||
super('C', cp); |
||||
this.valueIndex = index; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a char constant value. |
||||
* |
||||
* @param c the initial value. |
||||
*/ |
||||
public CharMemberValue(char c, ConstPool cp) { |
||||
super('C', cp); |
||||
setValue(c); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a char constant value. The initial value is '\0'. |
||||
*/ |
||||
public CharMemberValue(ConstPool cp) { |
||||
super('C', cp); |
||||
setValue('\0'); |
||||
} |
||||
|
||||
Object getValue(ClassLoader cl, ClassPool cp, Method m) { |
||||
return new Character(getValue()); |
||||
} |
||||
|
||||
Class getType(ClassLoader cl) { |
||||
return char.class; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the value of the member. |
||||
*/ |
||||
public char getValue() { |
||||
return (char)cp.getIntegerInfo(valueIndex); |
||||
} |
||||
|
||||
/** |
||||
* Sets the value of the member. |
||||
*/ |
||||
public void setValue(char newValue) { |
||||
valueIndex = cp.addIntegerInfo(newValue); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
return Character.toString(getValue()); |
||||
} |
||||
|
||||
/** |
||||
* Writes the value. |
||||
*/ |
||||
public void write(AnnotationsWriter writer) throws IOException { |
||||
writer.constValueIndex(getValue()); |
||||
} |
||||
|
||||
/** |
||||
* Accepts a visitor. |
||||
*/ |
||||
public void accept(MemberValueVisitor visitor) { |
||||
visitor.visitCharMemberValue(this); |
||||
} |
||||
} |
@ -1,140 +0,0 @@
|
||||
/* |
||||
* Javassist, a Java-bytecode translator toolkit. |
||||
* Copyright (C) 2004 Bill Burke. 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.bytecode.BadBytecode; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
import com.fr.third.javassist.bytecode.Descriptor; |
||||
import com.fr.third.javassist.bytecode.SignatureAttribute; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.reflect.Method; |
||||
|
||||
/** |
||||
* Class value. |
||||
* |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author Shigeru Chiba |
||||
*/ |
||||
public class ClassMemberValue extends MemberValue { |
||||
int valueIndex; |
||||
|
||||
/** |
||||
* Constructs a class value. The initial value is specified |
||||
* by the constant pool entry at the given index. |
||||
* |
||||
* @param index the index of a CONSTANT_Utf8_info structure. |
||||
*/ |
||||
public ClassMemberValue(int index, ConstPool cp) { |
||||
super('c', cp); |
||||
this.valueIndex = index; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a class value. |
||||
* |
||||
* @param className the initial value. |
||||
*/ |
||||
public ClassMemberValue(String className, ConstPool cp) { |
||||
super('c', cp); |
||||
setValue(className); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a class value. |
||||
* The initial value is java.lang.Class. |
||||
*/ |
||||
public ClassMemberValue(ConstPool cp) { |
||||
super('c', cp); |
||||
setValue("java.lang.Class"); |
||||
} |
||||
|
||||
Object getValue(ClassLoader cl, ClassPool cp, Method m) |
||||
throws ClassNotFoundException { |
||||
final String classname = getValue(); |
||||
if (classname.equals("void")) |
||||
return void.class; |
||||
else if (classname.equals("int")) |
||||
return int.class; |
||||
else if (classname.equals("byte")) |
||||
return byte.class; |
||||
else if (classname.equals("long")) |
||||
return long.class; |
||||
else if (classname.equals("double")) |
||||
return double.class; |
||||
else if (classname.equals("float")) |
||||
return float.class; |
||||
else if (classname.equals("char")) |
||||
return char.class; |
||||
else if (classname.equals("short")) |
||||
return short.class; |
||||
else if (classname.equals("boolean")) |
||||
return boolean.class; |
||||
else |
||||
return loadClass(cl, classname); |
||||
} |
||||
|
||||
Class getType(ClassLoader cl) throws ClassNotFoundException { |
||||
return loadClass(cl, "java.lang.Class"); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the value of the member. |
||||
* |
||||
* @return fully-qualified class name. |
||||
*/ |
||||
public String getValue() { |
||||
String v = cp.getUtf8Info(valueIndex); |
||||
try { |
||||
return SignatureAttribute.toTypeSignature(v).jvmTypeName(); |
||||
} catch (BadBytecode e) { |
||||
throw new RuntimeException(e); |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* Sets the value of the member. |
||||
* |
||||
* @param newClassName fully-qualified class name. |
||||
*/ |
||||
public void setValue(String newClassName) { |
||||
String setTo = Descriptor.of(newClassName); |
||||
valueIndex = cp.addUtf8Info(setTo); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
return getValue().replace('$', '.') + ".class"; |
||||
} |
||||
|
||||
/** |
||||
* Writes the value. |
||||
*/ |
||||
public void write(AnnotationsWriter writer) throws IOException { |
||||
writer.classInfoIndex(cp.getUtf8Info(valueIndex)); |
||||
} |
||||
|
||||
/** |
||||
* Accepts a visitor. |
||||
*/ |
||||
public void accept(MemberValueVisitor visitor) { |
||||
visitor.visitClassMemberValue(this); |
||||
} |
||||
} |
@ -1,106 +0,0 @@
|
||||
/* |
||||
* Javassist, a Java-bytecode translator toolkit. |
||||
* Copyright (C) 2004 Bill Burke. 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.fr.third.javassist.bytecode.annotation; |
||||
|
||||
import com.fr.third.javassist.ClassPool; |
||||
import com.fr.third.javassist.bytecode.ConstPool; |
||||
|
||||
import java.io.IOException; |
||||
import java.lang.reflect.Method; |
||||
|
||||
/** |
||||
* Double floating-point number constant value. |
||||
* |
||||
* @author <a href="mailto:bill@jboss.org">Bill Burke</a> |
||||
* @author Shigeru Chiba |
||||
* @version $Revision: 1.7 $ |
||||
*/ |
||||
public class DoubleMemberValue extends MemberValue { |
||||
int valueIndex; |
||||
|
||||
/** |
||||
* Constructs a double constant value. The initial value is specified |
||||
* by the constant pool entry at the given index. |
||||
* |
||||
* @param index the index of a CONSTANT_Double_info structure. |
||||
*/ |
||||
public DoubleMemberValue(int index, ConstPool cp) { |
||||
super('D', cp); |
||||
this.valueIndex = index; |
||||
} |
||||
|
||||
/** |
||||
* Constructs a double constant value. |
||||
* |
||||
* @param d the initial value. |
||||
*/ |
||||
public DoubleMemberValue(double d, ConstPool cp) { |
||||
super('D', cp); |
||||
setValue(d); |
||||
} |
||||
|
||||
/** |
||||
* Constructs a double constant value. The initial value is 0.0. |
||||
*/ |
||||
public DoubleMemberValue(ConstPool cp) { |
||||
super('D', cp); |
||||
setValue(0.0); |
||||
} |
||||
|
||||
Object getValue(ClassLoader cl, ClassPool cp, Method m) { |
||||
return new Double(getValue()); |
||||
} |
||||
|
||||
Class getType(ClassLoader cl) { |
||||
return double.class; |
||||
} |
||||
|
||||
/** |
||||
* Obtains the value of the member. |
||||
*/ |
||||
public double getValue() { |
||||
return cp.getDoubleInfo(valueIndex); |
||||
} |
||||
|
||||
/** |
||||
* Sets the value of the member. |
||||
*/ |
||||
public void setValue(double newValue) { |
||||
valueIndex = cp.addDoubleInfo(newValue); |
||||
} |
||||
|
||||
/** |
||||
* Obtains the string representation of this object. |
||||
*/ |
||||
public String toString() { |
||||
return Double.toString(getValue()); |
||||
} |
||||
|
||||
/** |
||||
* Writes the value. |
||||
*/ |
||||
public void write(AnnotationsWriter writer) throws IOException { |
||||
writer.constValueIndex(getValue()); |
||||
} |
||||
|
||||
/** |
||||
* Accepts a visitor. |
||||
*/ |
||||
public void accept(MemberValueVisitor visitor) { |
||||
visitor.visitDoubleMemberValue(this); |
||||
} |
||||
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue