Browse Source

javassist.expr.NewArray has been implemented.


git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@120 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba 20 years ago
parent
commit
3b946e08d5

+ 5
- 2
Readme.html View File

@@ -255,10 +255,13 @@ see javassist.Dump.

<h2>Changes</h2>

<p>- version 3.0
<p>- version 3.0 beta 3

<ul>
<li>CtClass.toClass() has been reimplemented.
<li>CtClass.toClass() has been reimplemented. The behavior has been
changed.
<li>javassist.expr.NewArray has been implemented. It enables modifying
an expression for array creation.
</ul>

<p>- version 3.0 beta in May 18th, 2004.

+ 29
- 0
src/main/javassist/bytecode/Descriptor.java View File

@@ -511,6 +511,35 @@ public class Descriptor {
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.

+ 8
- 0
src/main/javassist/compiler/Javac.java View File

@@ -323,6 +323,7 @@ public class Javac {
* parameters. $args represents an array of all the parameters.
* It also makes $$ available as a parameter list of method call.
* $0 can represent a local variable other than THIS (variable 0).
* $class is also made available.
*
* <p>This must be called before calling <code>compileStmnt()</code> and
* <code>compileExpr()</code>. The correct value of
@@ -332,6 +333,8 @@ public class Javac {
* @param varNo the register number of $0 (use0 is true)
* or $1 (otherwise).
* @param target the type of $0 (it can be null if use0 is false).
* It is used as the name of the type represented
* by $class.
* @param isStatic true if the method in which the compiled bytecode
* is embedded is static.
*/
@@ -345,14 +348,17 @@ public class Javac {

/**
* Prepares to use cast $r, $w, $_, and $type.
* $type is made to represent the specified return type.
* It also enables to write a return statement with a return value
* for void method.
*
* <p>If the return type is void, ($r) does nothing.
* The type of $_ is java.lang.Object.
*
* @param type the return type.
* @param useResultVar true if $_ is used.
* @return -1 or the variable index assigned to $_.
* @see #recordType(CtClass)
*/
public int recordReturnType(CtClass type, boolean useResultVar)
throws CompileError
@@ -365,6 +371,8 @@ public class Javac {
/**
* Prepares to use $type. Note that recordReturnType() overwrites
* the value of $type.
*
* @param t the type represented by $type.
*/
public void recordType(CtClass t) {
gen.recordType(t);

+ 11
- 5
src/main/javassist/compiler/JvstCodeGen.java View File

@@ -458,7 +458,7 @@ public class JvstCodeGen extends MemberCodeGen {
}

/**
* Makes method parameters $0, $1, ..., $args, and $$ available.
* Makes method parameters $0, $1, ..., $args, $$, and $class available.
* $0 is equivalent to THIS if the method is not static. Otherwise,
* if the method is static, then $0 is not available.
*/
@@ -472,15 +472,20 @@ public class JvstCodeGen extends MemberCodeGen {
}

/**
* Makes method parameters $0, $1, ..., $args, and $$ available.
* Makes method parameters $0, $1, ..., $args, $$, and $class available.
* $0 is available only if use0 is true. It might not be equivalent
* to THIS.
*
* @paaram use0 true if $0 is used.
* @param params the parameter types (the types of $1, $2, ..)
* @param prefix it must be "$" (the first letter of $0, $1, ...)
* @param paramVarName it must be "$args"
* @param paramsName it must be "$$"
* @param use0 true if $0 is used.
* @param paramBase the register number of $0 (use0 is true)
* or $1 (otherwise).
* @param target the class of $0. If use0 is false, target
* can be null.
* can be null. The value of "target" is also used
* as the name of the type represented by $class.
* @param isStatic true if the method in which the compiled bytecode
* is embedded is static.
*/
@@ -499,7 +504,8 @@ public class JvstCodeGen extends MemberCodeGen {
paramVarBase = paramBase;
useParam0 = use0;

param0Type = MemberResolver.jvmToJavaName(target);
if (target != null)
param0Type = MemberResolver.jvmToJavaName(target);

inStaticMethod = isStatic;
varNo = paramBase;

+ 56
- 34
src/main/javassist/expr/ExprEditor.java View File

@@ -108,44 +108,57 @@ public class ExprEditor {
int pos = iterator.next();
int c = iterator.byteAt(pos);

if (c == Opcode.INVOKESTATIC || c == Opcode.INVOKEINTERFACE
|| c == Opcode.INVOKEVIRTUAL) {
expr = new MethodCall(pos, iterator, clazz, minfo);
edit((MethodCall)expr);
}
else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC
|| c == Opcode.PUTFIELD || c == Opcode.PUTSTATIC) {
expr = new FieldAccess(pos, iterator, clazz, minfo, c);
edit((FieldAccess)expr);
}
else if (c == Opcode.NEW) {
int index = iterator.u16bitAt(pos + 1);
newList = new NewOp(newList, pos,
cp.getClassInfo(index));
}
else if (c == Opcode.INVOKESPECIAL) {
if (newList != null && cp.isConstructor(newList.type,
iterator.u16bitAt(pos + 1)) > 0) {
expr = new NewExpr(pos, iterator, clazz, minfo,
newList.type, newList.pos);
edit((NewExpr)expr);
newList = newList.next;
}
else {
if (c < Opcode.GETSTATIC) // c < 178
/* skip */;
else if (c < Opcode.NEWARRAY) { // c < 188
if (c == Opcode.INVOKESTATIC
|| c == Opcode.INVOKEINTERFACE
|| c == Opcode.INVOKEVIRTUAL) {
expr = new MethodCall(pos, iterator, clazz, minfo);
MethodCall mcall = (MethodCall)expr;
if (!mcall.getMethodName().equals(
edit((MethodCall)expr);
}
else if (c == Opcode.GETFIELD || c == Opcode.GETSTATIC
|| c == Opcode.PUTFIELD
|| c == Opcode.PUTSTATIC) {
expr = new FieldAccess(pos, iterator, clazz, minfo, c);
edit((FieldAccess)expr);
}
else if (c == Opcode.NEW) {
int index = iterator.u16bitAt(pos + 1);
newList = new NewOp(newList, pos,
cp.getClassInfo(index));
}
else if (c == Opcode.INVOKESPECIAL) {
if (newList != null && cp.isConstructor(newList.type,
iterator.u16bitAt(pos + 1)) > 0) {
expr = new NewExpr(pos, iterator, clazz, minfo,
newList.type, newList.pos);
edit((NewExpr)expr);
newList = newList.next;
}
else {
expr = new MethodCall(pos, iterator, clazz, minfo);
MethodCall mcall = (MethodCall)expr;
if (!mcall.getMethodName().equals(
MethodInfo.nameInit))
edit(mcall);
edit(mcall);
}
}
}
else if (c == Opcode.INSTANCEOF) {
expr = new Instanceof(pos, iterator, clazz, minfo);
edit((Instanceof)expr);
}
else if (c == Opcode.CHECKCAST) {
expr = new Cast(pos, iterator, clazz, minfo);
edit((Cast)expr);
else { // c >= 188
if (c == Opcode.NEWARRAY || c == Opcode.ANEWARRAY
|| c == Opcode.MULTIANEWARRAY) {
expr = new NewArray(pos, iterator, clazz, minfo, c);
edit((NewArray)expr);
}
else if (c == Opcode.INSTANCEOF) {
expr = new Instanceof(pos, iterator, clazz, minfo);
edit((Instanceof)expr);
}
else if (c == Opcode.CHECKCAST) {
expr = new Cast(pos, iterator, clazz, minfo);
edit((Cast)expr);
}
}

if (expr != null && expr.edited()) {
@@ -187,6 +200,15 @@ public class ExprEditor {
*/
public void edit(NewExpr e) throws CannotCompileException {}

/**
* Edits an expression for array creation (overridable).
* The default implementation performs nothing.
*
* @param a the <tt>new</tt> expression for creating an array.
* @throws CannotCompileException
*/
public void edit(NewArray a) throws CannotCompileException {}

/**
* Edits a method call (overridable).
* The default implementation performs nothing.

+ 281
- 0
src/main/javassist/expr/NewArray.java View File

@@ -0,0 +1,281 @@
/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999-2004 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.
*
* 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 javassist.expr;

import javassist.*;
import javassist.bytecode.*;
import javassist.compiler.*;
import javassist.compiler.ast.ASTList;

/**
* Array creation.
*
* <p>This class does not provide methods for obtaining the initial
* values of array elements.
*/
public class NewArray extends Expr {
int opcode;

NewArray(int pos, CodeIterator i, CtClass declaring, MethodInfo m,
int op) {
super(pos, i, declaring, m);
opcode = op;
}

/**
* Returns the method or constructor containing the array creation
* represented by this object.
*/
public CtBehavior where() { return super.where(); }

/**
* Returns the line number of the source line containing the
* array creation.
*
* @return -1 if this information is not available.
*/
public int getLineNumber() {
return super.getLineNumber();
}

/**
* Returns the source file containing the array creation.
*
* @return null if this information is not available.
*/
public String getFileName() {
return super.getFileName();
}

/**
* Returns the list of exceptions that the expression may throw.
* This list includes both the exceptions that the try-catch statements
* including the expression can catch and the exceptions that
* the throws declaration allows the method to throw.
*/
public CtClass[] mayThrow() {
return super.mayThrow();
}

/**
* Returns the type of array components. If the created array is
* a two-dimensional array of <tt>int</tt>,
* the type returned by this method is
* not <tt>int[]</tt> but <tt>int</tt>.
*/
public CtClass getComponentType() throws NotFoundException {
if (opcode == Opcode.NEWARRAY) {
int atype = iterator.byteAt(currentPos + 1);
return getPrimitiveType(atype);
}
else if (opcode == Opcode.ANEWARRAY
|| opcode == Opcode.MULTIANEWARRAY) {
int index = iterator.u16bitAt(currentPos + 1);
String desc = getConstPool().getClassInfo(index);
int dim = Descriptor.arrayDimension(desc);
desc = Descriptor.toArrayComponent(desc, dim);
return Descriptor.toCtClass(desc, thisClass.getClassPool());
}
else
throw new RuntimeException("bad opcode: " + opcode);
}

CtClass getPrimitiveType(int atype) {
switch (atype) {
case Opcode.T_BOOLEAN :
return CtClass.booleanType;
case Opcode.T_CHAR :
return CtClass.charType;
case Opcode.T_FLOAT :
return CtClass.floatType;
case Opcode.T_DOUBLE :
return CtClass.doubleType;
case Opcode.T_BYTE :
return CtClass.byteType;
case Opcode.T_SHORT :
return CtClass.shortType;
case Opcode.T_INT :
return CtClass.intType;
case Opcode.T_LONG :
return CtClass.longType;
default :
throw new RuntimeException("bad atype: " + atype);
}
}

/**
* Returns the dimension of the created array.
*/
public int getDimension() {
if (opcode == Opcode.NEWARRAY)
return 1;
else if (opcode == Opcode.ANEWARRAY
|| opcode == Opcode.MULTIANEWARRAY) {
int index = iterator.u16bitAt(currentPos + 1);
String desc = getConstPool().getClassInfo(index);
return Descriptor.arrayDimension(desc)
+ (opcode == Opcode.ANEWARRAY ? 1 : 0);
}
else
throw new RuntimeException("bad opcode: " + opcode);
}

/**
* Returns the number of dimensions of arrays to be created.
* If the opcode is multianewarray, this method returns the second
* operand. Otherwise, it returns 1.
*/
public int getCreatedDimensions() {
if (opcode == Opcode.MULTIANEWARRAY)
return iterator.byteAt(currentPos + 3);
else
return 1;
}

/**
* Replaces the array creation with the bytecode derived from
* the given source text.
*
* <p>$0 is available even if the called method is static.
* If the field access is writing, $_ is available but the value
* of $_ is ignored.
*
* @param statement a Java statement.
*/
public void replace(String statement) throws CannotCompileException {
try {
replace2(statement);
}
catch (CompileError e) { throw new CannotCompileException(e); }
catch (NotFoundException e) { throw new CannotCompileException(e); }
catch (BadBytecode e) {
throw new CannotCompileException("broken method");
}
}

private void replace2(String statement)
throws CompileError, NotFoundException, BadBytecode,
CannotCompileException
{
ConstPool constPool = getConstPool();
int pos = currentPos;
CtClass retType;
int codeLength;
int index = 0;
int dim = 1;
String desc;
if (opcode == Opcode.NEWARRAY) {
index = iterator.byteAt(currentPos + 1); // atype
CtPrimitiveType cpt = (CtPrimitiveType)getPrimitiveType(index);
desc = "[" + cpt.getDescriptor();
codeLength = 2;
}
else if (opcode == Opcode.ANEWARRAY) {
index = iterator.u16bitAt(pos + 1);
desc = constPool.getClassInfo(index);
if (desc.startsWith("["))
desc = "[" + desc;
else
desc = "[L" + desc + ";";

codeLength = 3;
}
else if (opcode == Opcode.MULTIANEWARRAY) {
index = iterator.u16bitAt(currentPos + 1);
desc = constPool.getClassInfo(index);
dim = iterator.byteAt(currentPos + 3);
codeLength = 4;
}
else
throw new RuntimeException("bad opcode: " + opcode);

retType = Descriptor.toCtClass(desc, thisClass.getClassPool());

Javac jc = new Javac(thisClass);
CodeAttribute ca = iterator.get();

CtClass[] params = new CtClass[dim];
for (int i = 0; i < dim; ++i)
params[i] = CtClass.intType;

int paramVar = ca.getMaxLocals();
jc.recordParams(javaLangObject, params,
true, paramVar, withinStatic());

/* Is $_ included in the source code?
*/
checkResultValue(retType, statement);
int retVar = jc.recordReturnType(retType, true);
jc.recordProceed(new ProceedForArray(retType, opcode, index, dim));

Bytecode bytecode = jc.getBytecode();
storeStack(params, true, paramVar, bytecode);
jc.recordLocalVariables(ca, pos);

bytecode.addOpcode(ACONST_NULL); // initialize $_
bytecode.addAstore(retVar);

jc.compileStmnt(statement);
bytecode.addAload(retVar);

replace0(pos, bytecode, codeLength);
}

/* <array type> $proceed(<dim> ..)
*/
static class ProceedForArray implements ProceedHandler {
CtClass arrayType;
int opcode;
int index, dimension;

ProceedForArray(CtClass type, int op, int i, int dim) {
arrayType = type;
opcode = op;
index = i;
dimension = dim;
}

public void doit(JvstCodeGen gen, Bytecode bytecode, ASTList args)
throws CompileError
{
int num = gen.getMethodArgsLength(args);
if (num != dimension)
throw new CompileError(Javac.proceedName
+ "() with a wrong number of parameters");

gen.atMethodArgs(args, new int[num],
new int[num], new String[num]);
bytecode.addOpcode(opcode);
if (opcode == Opcode.ANEWARRAY)
bytecode.addIndex(index);
else if (opcode == Opcode.NEWARRAY)
bytecode.add(index);
else /* if (opcode == Opcode.MULTIANEWARRAY) */ {
bytecode.addIndex(index);
bytecode.add(dimension);
bytecode.growStack(1 - dimension);
}

gen.setType(arrayType);
}

public void setReturnType(JvstTypeChecker c, ASTList args)
throws CompileError
{
c.setType(arrayType);
}
}
}

+ 104
- 13
tutorial/tutorial2.html View File

@@ -516,6 +516,7 @@ variable is available only in <code>insertAfter()</code> in

<p>The value of <code>$class</code> is an <code>java.lang.Class</code>
object representing the class in which the edited method is declared.
This represents the type of <code>$0</code>.

<h4>addCatch()</h4>

@@ -613,10 +614,13 @@ the formal result type.</td>

<tr>
<td><code>$class</code></td>
<td>A <code>java.lang.Class</code> object representing
the class currently edited.</td>
<td rowspan=2>A <code>java.lang.Class</code> object representing
the class that declares the method<br>
currently edited (the type of $0).</td>
</tr>

<tr><td>&nbsp</td></tr>

</table>
</ul>

@@ -795,8 +799,9 @@ The method <code>replace()</code> in
source text representing the substitued statement or
block for the field access.

<p>
In the source text, the identifiers starting with <code>$</code>
have also special meaning:
have special meaning:

<ul><table border=0>
<tr>
@@ -875,7 +880,7 @@ is the type of the field.
<h4>javassist.expr.NewExpr</h4>

<p>A <code>NewExpr</code> object represents object creation
with the <code>new</code> operator.
with the <code>new</code> operator (not including array creation).
The method <code>edit()</code> in <code>ExprEditor</code>
receives this object if object creation is found.
The method <code>replace()</code> in
@@ -883,8 +888,9 @@ The method <code>replace()</code> in
source text representing the substitued statement or
block for the object creation.

<p>
In the source text, the identifiers starting with <code>$</code>
have also special meaning:
have special meaning:

<ul><table border=0>

@@ -919,16 +925,16 @@ The type of the created object.
</td>
</tr>

<tr><td><code>$class</code> &nbsp &nbsp</td>
<td>A <code>java.lang.Class</code> object representing
the class of the created object.
</td></tr>

<tr><td><code>$sig</code> &nbsp &nbsp</td>
<td>An array of <code>java.lang.Class</code> objects representing
the formal parameter types.</td>
</tr>

<tr><td><code>$type</code> &nbsp &nbsp</td>
<td>A <code>java.lang.Class</code> object representing
the class of the created object.
</td></tr>

<tr><td><code>$proceed</code> &nbsp &nbsp</td>
<td>The name of a virtual method executing the original
object creation.
@@ -942,6 +948,88 @@ object creation.
<code>$args</code> and <code>$$</code>
are also available.

<h4>javassist.expr.NewArray</h4>

<p>A <code>NewArray</code> object represents array creation
with the <code>new</code> operator.
The method <code>edit()</code> in <code>ExprEditor</code>
receives this object if array creation is found.
The method <code>replace()</code> in
<code>NewArray</code> receives
source text representing the substitued statement or
block for the array creation.

<p>
In the source text, the identifiers starting with <code>$</code>
have special meaning:

<ul><table border=0>

<tr>
<td><code>$0</code></td>
<td>
<code>null</code>.
</td>
</tr>

<tr>
<td><code>$1</code>, <code>$2</code>, ... &nbsp &nbsp</td>
<td>
The size of each dimension.
</td>
</tr>

<tr>
<td><code>$_</code></td>
<td rowspan=2>
The resulting value of the array creation.
<br>A newly created array must be stored in this variable.
</td>
</tr>

<tr><td>&nbsp</td></tr>

<tr>
<td><code>$r</code></td>
<td>
The type of the created array.
</td>
</tr>

<tr><td><code>$type</code> &nbsp &nbsp</td>
<td>A <code>java.lang.Class</code> object representing
the class of the created array.
</td></tr>

<tr><td><code>$proceed</code> &nbsp &nbsp</td>
<td>The name of a virtual method executing the original
array creation.
.</td>
</tr>

</table>
</ul>

<p>The other identifiers such as <code>$w</code>,
<code>$args</code> and <code>$$</code>
are also available.

<p>For example, if the array creation is the following expression,

<ul><pre>
String[][] s = new String[3][4];
</pre></ul>

then the value of $1 and $2 are 3 and 4, respectively. $3 is not available.

<p>If the array creation is the following expression,

<ul><pre>
String[][] s = new String[3][];
</pre></ul>

then the value of $1 is 3 but $2 is not available.

<h4>javassist.expr.Instanceof</h4>

<p>A <code>Instanceof</code> object represents an <code>instanceof</code>
@@ -953,8 +1041,9 @@ The method <code>replace()</code> in
source text representing the substitued statement or
block for the expression.

<p>
In the source text, the identifiers starting with <code>$</code>
have also special meaning:
have special meaning:

<ul><table border=0>

@@ -1028,8 +1117,9 @@ The method <code>replace()</code> in
source text representing the substitued statement or
block for the expression.

<p>
In the source text, the identifiers starting with <code>$</code>
have also special meaning:
have special meaning:

<ul><table border=0>

@@ -1103,8 +1193,9 @@ The method <code>insertBefore()</code> in
<code>Handler</code> compiles the received
source text and inserts it at the beginning of the <code>catch</code> clause.

<p>
In the source text, the identifiers starting with <code>$</code>
have special meaning:
have meaning:

<ul><table border=0>


Loading…
Cancel
Save