]> source.dussan.org Git - javassist.git/commitdiff
javassist.expr.NewArray has been implemented.
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Mon, 2 Aug 2004 18:50:41 +0000 (18:50 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Mon, 2 Aug 2004 18:50:41 +0000 (18:50 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@120 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

Readme.html
src/main/javassist/bytecode/Descriptor.java
src/main/javassist/compiler/Javac.java
src/main/javassist/compiler/JvstCodeGen.java
src/main/javassist/expr/ExprEditor.java
src/main/javassist/expr/NewArray.java [new file with mode: 0644]
tutorial/tutorial2.html

index b968d9d8f962a06e6d5f3755f531903f247c090d..a1db77668865d9c8135a7755dd89db1238ba3bde 100644 (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.
index 9c5b69c7f29e9942e30f10831d186a58a065a556..4a352aaf9f951d8f5be63e8190dc1ae3024e1631 100644 (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.
index 216d0198bfef3753a40cde98b25cba0469bdb19e..67d0cef566f0c4e6be6a253728ff0541ee0db162 100644 (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);
index 6c78f477c1692839b55eb4c41799c2f570e110f0..6800a9c8987cdbb819cf3ed41227d07ee4042038 100644 (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;
index f4ef04eb2338206273a8411bdcd68f3ebe8f806a..8f7cacb8c6dcbaba749578f9468568151790bddd 100644 (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.
diff --git a/src/main/javassist/expr/NewArray.java b/src/main/javassist/expr/NewArray.java
new file mode 100644 (file)
index 0000000..db34cf8
--- /dev/null
@@ -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);
+        }
+    }
+}
index 937c442794a5cc39a6e0a1fb10d90548c53595e4..50d24712bdbcb7e749f2bc74addccb799184e8c0 100644 (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>