You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
810 lines
29 KiB
810 lines
29 KiB
5 years ago
|
/*
|
||
|
* 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";
|
||
|
}
|
||
|
}
|
||
|
}
|