]> source.dussan.org Git - javassist.git/commitdiff
discarded the last changes
authorchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Mon, 30 Aug 2004 17:41:36 +0000 (17:41 +0000)
committerchiba <chiba@30ef5769-5b8d-40dd-aea6-55b5d6557bb3>
Mon, 30 Aug 2004 17:41:36 +0000 (17:41 +0000)
git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@129 30ef5769-5b8d-40dd-aea6-55b5d6557bb3

Readme.html
src/main/javassist/compiler/CodeGen.java
src/main/javassist/compiler/TypeChecker.java
tutorial/tutorial.html
tutorial/tutorial2.html
tutorial/tutorial3.html

index a1db77668865d9c8135a7755dd89db1238ba3bde..035bd6bd706e537502e164c0aadb1c622216355f 100644 (file)
@@ -262,6 +262,9 @@ see javassist.Dump.
       changed.
   <li>javassist.expr.NewArray has been implemented.  It enables modifying
       an expression for array creation.
+  <li><code>.class</code> notation has been supported.  The modified class
+      file needs javassist.runtime.DotClass at runtime.
+  <li>a bug in <code>CtClass.getMethods()</code> has been fixed.
 </ul>
 
 <p>- version 3.0 beta in May 18th, 2004.
@@ -565,7 +568,7 @@ Andreas Salathe, Dante Torres estrada, S. Pam, Nuno Santos,
 Denis Taye, Colin Sampaleanu, Robert Bialek, Asato Shimotaki,
 Howard Lewis Ship, Richard Jones, Marjan Sterjev,
 Bruce McDonald, Mark Brennan, Vlad Skarzhevskyy,
-Brett Randall, and Tsuyoshi Murakami
+Brett Randall, Tsuyoshi Murakami, and Nathan Meyers
 for their contributions.
 
 <p><br>
index 2c186eed0e16743b205b160ae8e6387ebbe25ce9..35d068177d334c688373302cdcd41980cd3ac03c 100644 (file)
@@ -199,28 +199,20 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
     }
 
     public void compileExpr(ASTree expr) throws CompileError {
-        expr = doTypeCheck(expr);
+        doTypeCheck(expr);
         expr.accept(this);
     }
 
     public boolean compileBooleanExpr(boolean branchIf, ASTree expr)
         throws CompileError
     {
-        expr = doTypeCheck(expr);
+        doTypeCheck(expr);
         return booleanExpr(branchIf, expr);
     }
 
-    /* This returns a different expression from the given one
-     * if the given expression has been modified.
-     */
-    private ASTree doTypeCheck(ASTree expr) throws CompileError {
-        if (typeChecker != null) {
+    public void doTypeCheck(ASTree expr) throws CompileError {
+        if (typeChecker != null)
             expr.accept(typeChecker);
-            ASTree expr2 = typeChecker.modifiedExpr; 
-            return expr2 == null ? expr : expr2;
-        }
-        else
-            return expr;
     }
 
     public void atASTList(ASTList n) throws CompileError { fatal(); }
@@ -308,7 +300,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
         int op = st.getOperator();
         if (op == EXPR) {
             ASTree expr = st.getLeft();
-            expr = doTypeCheck(expr);
+            doTypeCheck(expr);
             if (expr instanceof AssignExpr)
                 atAssignExpr((AssignExpr)expr, false);
             else if (isPlusPlusExpr(expr)) {
@@ -568,7 +560,7 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
          */
         ASTree init = d.getInitializer();
         if (init != null) {
-            init = doTypeCheck(init);        
+            doTypeCheck(init);        
             atVariableAssign(null, '=', null, d, init, false);
         }
     }
@@ -798,10 +790,13 @@ public abstract class CodeGen extends Visitor implements Opcode, TokenId {
         int k = lookupBinOp(token);
         if (k >= 0) {
             expr.oprand1().accept(this);
+            ASTree right = expr.oprand2();
+            if (right == null)
+                return;     // see TypeChecker.atBinExpr().
+
             int type1 = exprType;
             int dim1 = arrayDim;
             String cname1 = className;
-            ASTree right = expr.oprand2();
             right.accept(this);
             if (dim1 != arrayDim)
                 throw new CompileError("incompatible array types");
index d57b95a5f68c82c9b2d4fb04a26d35d6855ee809..196c7642e6e802cf943feebb1e38899cd350b092 100644 (file)
@@ -17,17 +17,11 @@ package javassist.compiler;
 
 import javassist.CtClass;
 import javassist.CtField;
-import javassist.Modifier;
 import javassist.ClassPool;
 import javassist.NotFoundException;
 import javassist.compiler.ast.*;
 import javassist.bytecode.*;
 
-/**
- * This class does type checking and, if needed, transformes the original
- * abstract syntax tree.  The resulting tree is available from
- * this.modifiedExpr.
- */
 public class TypeChecker extends Visitor implements Opcode, TokenId {
     static final String javaLangObject = "java.lang.Object";
     static final String jvmJavaLangObject = "java/lang/Object";
@@ -40,7 +34,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
     protected int exprType;     // VOID, NULL, CLASS, BOOLEAN, INT, ...
     protected int arrayDim;
     protected String className; // JVM-internal representation
-    protected ASTree modifiedExpr; // null if the given expr was not changed
 
     protected MemberResolver resolver;
     protected CtClass   thisClass;
@@ -105,7 +98,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
             exprType = CLASS;
             arrayDim = 0;
             className = MemberResolver.javaToJvmName(cname);
-            modifiedExpr = null;
         }
     }
 
@@ -117,12 +109,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
             atMultiNewArray(type, classname, size);
         else {
             size.head().accept(this);
-            if (modifiedExpr != null)
-                size.setHead(modifiedExpr);
-
             exprType = type;
             arrayDim = 1;
-            modifiedExpr = null;
             if (type == CLASS)
                 className = resolveClassName(classname);
             else
@@ -142,11 +130,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
 
             ++count;
             s.accept(this);
-            if (modifiedExpr != null)
-                size.setHead(modifiedExpr);
         }
 
-        modifiedExpr = null;
         exprType = type;
         arrayDim = dim;
         if (type == CLASS)
@@ -189,80 +174,49 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         int varArray = d.getArrayDim();
         String varClass = d.getClassName();
 
-        if (op != '=') {
+        if (op != '=')
             atVariable(var);
-            if (modifiedExpr != null)
-                expr.setOprand1(modifiedExpr);
-        }
 
         right.accept(this);
-        if (modifiedExpr != null)
-            expr.setOprand2(modifiedExpr);
-
         exprType = varType;
         arrayDim = varArray;
         className = varClass;
-        modifiedExpr = null;
     }
 
     private void atArrayAssign(Expr expr, int op, Expr array,
                         ASTree right) throws CompileError
     {
-        atArrayRead(array);
-        if (modifiedExpr != null)
-            expr.setOprand1(modifiedExpr);
-
+        atArrayRead(array.oprand1(), array.oprand2());
         int aType = exprType;
         int aDim = arrayDim;
         String cname = className;
         right.accept(this);
-        if (modifiedExpr != null)
-            expr.setOprand2(modifiedExpr);
-
         exprType = aType;
         arrayDim = aDim;
         className = cname;
-        modifiedExpr = null;
     }
 
     protected void atFieldAssign(Expr expr, int op, ASTree left, ASTree right)
         throws CompileError
     {
-        CtField f = atFieldRead(left);
+        CtField f = fieldAccess(left);
+        atFieldRead(f);
         int fType = exprType;
         int fDim = arrayDim;
         String cname = className;
-        if (modifiedExpr != null)
-            expr.setOprand1(modifiedExpr);
-
-        if (Modifier.isFinal(f.getModifiers()))
-            throw new CompileError("assignment to a final field");
-
         right.accept(this);
-        if (modifiedExpr != null)
-            expr.setOprand2(modifiedExpr);
-
         exprType = fType;
         arrayDim = fDim;
         className = cname;
-        modifiedExpr = null;
     }
 
     public void atCondExpr(CondExpr expr) throws CompileError {
         booleanExpr(expr.condExpr());
-        if (modifiedExpr != null)
-            expr.setCond(modifiedExpr);
-
         expr.thenExpr().accept(this);
-        if (modifiedExpr != null)
-            expr.setThen(modifiedExpr);
-
         int type1 = exprType;
         int dim1 = arrayDim;
         String cname1 = className;
         expr.elseExpr().accept(this);
-        if (modifiedExpr != null)
-            expr.setElse(modifiedExpr);
 
         if (dim1 == 0 && dim1 == arrayDim)
             if (CodeGen.rightIsStrong(type1, exprType))
@@ -271,89 +225,63 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
                 expr.setElse(new CastExpr(type1, 0, expr.elseExpr()));
                 exprType = type1;
             }
-
-        modifiedExpr = null;
     }
 
     public void atBinExpr(BinExpr expr) throws CompileError {
         int token = expr.getOperator();
         int k = CodeGen.lookupBinOp(token);
-        if (k < 0) {
-            /* equation: &&, ||, ==, !=, <=, >=, <, >
-            */
-            booleanExpr(expr);
-        }
-        else {
+        if (k >= 0) {
             /* arithmetic operators: +, -, *, /, %, |, ^, &, <<, >>, >>>
              */
-            if (token != '+')
-                atNonPlusExpr(expr, token);
-            else {
+            if (token == '+') {
                 Expr e = atPlusExpr(expr);
                 if (e != null) {
                     /* String concatenation has been translated into
                      * an expression using StringBuffer.
                      */
                     e = CallExpr.makeCall(Expr.make('.', e,
-                                          new Member("toString")), null);
+                                            new Member("toString")), null);
+                    expr.setLeft(e);
+                    expr.setOprand2(null);    // <---- look at this!
                     className = jvmJavaLangString;
-                    modifiedExpr = e;       // expr will be replaced with e.
                 }
             }
+            else {
+                expr.oprand1().accept(this);
+                int type1 = exprType;
+                expr.oprand2().accept(this);
+                computeBinExprType(expr, token, type1);
+            }
         }
-    }
-
-    private void atNonPlusExpr(BinExpr expr, int token) throws CompileError {
-        ASTree left = expr.oprand1();
-        ASTree right = expr.oprand2();
-
-        left.accept(this);
-        if (modifiedExpr != null) {
-            left = modifiedExpr;
-            expr.setOprand1(left);
-        }
-
-        int type1 = exprType;
-        right.accept(this);
-        if (modifiedExpr != null) {
-            right = modifiedExpr;
-            expr.setOprand2(right);
+        else {
+            /* equation: &&, ||, ==, !=, <=, >=, <, >
+            */
+            booleanExpr(expr);
         }
-
-        modifiedExpr = computeConstExpr(token, left, right);
-        computeBinExprType(expr, token, type1);
     }
 
-    /* This method deals with string concatenation.  It converts a +
-     * expression on String such as:
-     *     "value:" + i + "."
-     * into:
-     *     new StringBuffer().append("value:").append(i).append(".")
-     *                          .toString()
-     *
-     * This method also inserts a cast operator for the right operand
-     * if needed.
-     *
-     * EXPR must be a + expression.
-     *
-     * atPlusExpr() returns null if the expression is not a string
-     * concatenation.
-     */
+    // expr must be a + expression.
     private Expr atPlusExpr(BinExpr expr) throws CompileError {
         ASTree left = expr.oprand1();
         ASTree right = expr.oprand2();
+        if (right == null) {
+            /* this expression has been already type-checked since it is
+               string concatenation.
+               see atBinExpr() above.
+             */
+            exprType = CLASS;
+            arrayDim = 0;
+            className = jvmJavaLangString;
+            return null;
+        }
 
         if (isPlusExpr(left)) {
             Expr newExpr = atPlusExpr((BinExpr)left);
             if (newExpr != null) {
                 right.accept(this);
-                if (modifiedExpr != null)
-                    right = modifiedExpr;
-
                 exprType = CLASS;
                 arrayDim = 0;
                 className = "java/lang/StringBuffer";
-                modifiedExpr = null;
                 return makeAppendCall(newExpr, right);
             }
         }
@@ -363,37 +291,17 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         int type1 = exprType;
         int dim1 = arrayDim;
         String cname = className;
-        if (modifiedExpr != null) {
-            left = modifiedExpr;
-            expr.setOprand1(left);
-        }
-
         right.accept(this);
-        if (modifiedExpr != null) {
-            right = modifiedExpr;
-            expr.setOprand2(right);
-        }
-
-        modifiedExpr = computeConstExpr('+', left, right);
         if ((type1 == CLASS && dim1 == 0 && jvmJavaLangString.equals(cname))
             || (exprType == CLASS && arrayDim == 0
-                && jvmJavaLangString.equals(className)))
-        {
+                && jvmJavaLangString.equals(className))) {
+            ASTList sbufClass = ASTList.make(new Symbol("java"),
+                            new Symbol("lang"), new Symbol("StringBuffer"));
+            ASTree e = new NewExpr(sbufClass, null);
             exprType = CLASS;
             arrayDim = 0;
-            if (modifiedExpr != null) {
-                // this expression is constant.
-                className = jvmJavaLangString;
-                return null;
-            }
-            else {
-                className = "java/lang/StringBuffer";
-                ASTList sbufClass = ASTList.make(new Symbol("java"),
-                                                 new Symbol("lang"),
-                                                 new Symbol("StringBuffer"));
-                ASTree e = new NewExpr(sbufClass, null);
-                return makeAppendCall(makeAppendCall(e, left), right);
-            }
+            className = "java/lang/StringBuffer";
+            return makeAppendCall(makeAppendCall(e, left), right);
         }
         else {
             computeBinExprType(expr, '+', type1);
@@ -428,54 +336,33 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
 
         if (CodeGen.isP_INT(exprType))
             exprType = INT;         // type1 may be BYTE, ...
-
-        arrayDim = 0;
-        // don't change the value of modifiedExpr.
     }
 
     private void booleanExpr(ASTree expr)
         throws CompileError
     {
-        ASTree modExpr = null;
         int op = CodeGen.getCompOperator(expr);
         if (op == EQ) {         // ==, !=, ...
             BinExpr bexpr = (BinExpr)expr;
             bexpr.oprand1().accept(this);
-            if (modifiedExpr != null)
-                bexpr.setOprand1(modifiedExpr);
-
             int type1 = exprType;
             int dim1 = arrayDim;
             bexpr.oprand2().accept(this);
-            if (modifiedExpr != null)
-                bexpr.setOprand2(modifiedExpr);
-
             if (dim1 == 0 && arrayDim == 0)
                 insertCast(bexpr, type1, exprType);
         }
-        else if (op == '!') {
+        else if (op == '!')
             ((Expr)expr).oprand1().accept(this);
-            if (modifiedExpr != null)
-                ((Expr)expr).setOprand1(modifiedExpr);
-        }
         else if (op == ANDAND || op == OROR) {
             BinExpr bexpr = (BinExpr)expr;
             bexpr.oprand1().accept(this);
-            if (modifiedExpr != null)
-                bexpr.setOprand1(modifiedExpr);
-
             bexpr.oprand2().accept(this);
-            if (modifiedExpr != null)
-                bexpr.setOprand2(modifiedExpr);
         }
-        else {               // others
+        else                // others
             expr.accept(this);
-            modExpr = modifiedExpr;
-        }
 
         exprType = BOOLEAN;
         arrayDim = 0;
-        modifiedExpr = modExpr;
     }
 
     private void insertCast(BinExpr expr, int type1, int type2)
@@ -487,37 +374,18 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
             exprType = type1;
     }
 
-    private ASTree computeConstExpr(int op, ASTree left, ASTree right) {
-        if (left instanceof StringL && right instanceof StringL && op == '+')
-            return new StringL(((StringL)left).get() + ((StringL)right).get());
-        else if (left instanceof IntConst)
-            return ((IntConst)left).compute(op, right);
-        else if (left instanceof DoubleConst)
-            return ((DoubleConst)left).compute(op, right);
-        else
-            return null;        // not constant expression
-    }
-
     public void atCastExpr(CastExpr expr) throws CompileError {
         String cname = resolveClassName(expr.getClassName());
         expr.getOprand().accept(this);
-        if (modifiedExpr != null)
-            expr.setOprand(modifiedExpr);
-
         exprType = expr.getType();
         arrayDim = expr.getArrayDim();
         className = cname;
-        modifiedExpr = null;
     }
 
     public void atInstanceOfExpr(InstanceOfExpr expr) throws CompileError {
         expr.getOprand().accept(this);
-        if (modifiedExpr != null)
-            expr.setOprand(modifiedExpr);
-
         exprType = BOOLEAN;
         arrayDim = 0;
-        modifiedExpr = null;
     }
 
     public void atExpr(Expr expr) throws CompileError {
@@ -543,7 +411,7 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
                 atFieldRead(expr);
         }
         else if (token == ARRAY)
-            atArrayRead(expr);
+            atArrayRead(oprand, expr.oprand2());
         else if (token == PLUSPLUS || token == MINUSMINUS)
             atPlusPlus(token, oprand, expr);
         else if (token == '!')
@@ -551,40 +419,13 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         else if (token == CALL)              // method call
             fatal();
         else {
-            oprand.accept(this);
-            if (modifiedExpr != null) {
-                oprand = modifiedExpr;
-                expr.setOprand1(oprand);
-            }
-
-            modifiedExpr = computeConstExpr(token, oprand);
-            if (token == '-' || token == '~') {
+            expr.oprand1().accept(this);
+            if (token == '-' || token == '~')
                 if (CodeGen.isP_INT(exprType))
                     exprType = INT;         // type may be BYTE, ...
-            }
         }
     }
 
-    private ASTree computeConstExpr(int op, ASTree oprand) {
-        if (oprand instanceof IntConst) {
-            IntConst c = (IntConst)oprand;
-            long v = c.get();
-            if (op == '-')
-                v = -v;
-            else if (op == '~')
-                v = ~v;
-
-            c.set(v);
-        }
-        else if (oprand instanceof DoubleConst) {
-            DoubleConst c = (DoubleConst)oprand;
-            if (op == '-')
-                c.set(-c.get());
-        }
-
-        return null;
-    }
-
     public void atCallExpr(CallExpr expr) throws CompileError {
         String mname = null;
         CtClass targetClass = null;
@@ -614,8 +455,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
                 ASTree target = e.oprand1();
                 try {
                     target.accept(this);
-                    if (modifiedExpr != null)
-                        e.setOprand1(modifiedExpr);
                 }
                 catch (NoFieldException nfe) {
                     if (nfe.getExpr() != target)
@@ -643,7 +482,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         MemberResolver.Method minfo
             = atMethodCallCore(targetClass, mname, args);
         expr.setMethod(minfo);
-        modifiedExpr = null;
     }
 
     private static void badMethod() throws CompileError {
@@ -651,8 +489,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
     }
 
     /**
-     * modifiedExpr is not set.
-     *
      * @return  a pair of the class declaring the invoked method
      *          and the MethodInfo of that method.  Never null.
      */
@@ -695,9 +531,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         while (args != null) {
             ASTree a = args.head();
             a.accept(this);
-            if (modifiedExpr != null)
-                args.setHead(modifiedExpr);
-
             types[i] = exprType;
             dims[i] = arrayDim;
             cnames[i] = className;
@@ -706,8 +539,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         }
     }
 
-    /* modifiedExpr is not set.
-     */
     void setReturnType(String desc) throws CompileError {
         int i = desc.indexOf(')');
         if (i < 0)
@@ -735,8 +566,11 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         }
     }
 
-    private CtField atFieldRead(ASTree expr) throws CompileError {
-        CtField f = fieldAccess(expr);
+    private void atFieldRead(ASTree expr) throws CompileError {
+        atFieldRead(fieldAccess(expr));
+    }
+
+    private void atFieldRead(CtField f) throws CompileError {
         FieldInfo finfo = f.getFieldInfo2();
         String type = finfo.getDescriptor();
 
@@ -755,9 +589,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
             className = type.substring(i + 1, type.indexOf(';', i + 1));
         else
             className = null;
-
-        modifiedExpr = null; ??
-        return f;
     }
 
     protected CtField fieldAccess(ASTree expr) throws CompileError {
@@ -780,9 +611,6 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
             else if (op == '.')
                 try {
                     e.oprand1().accept(this);
-                    if (modifiedExpr != null)
-                        e.setOprand1(modifiedExpr);
-
                     if (exprType == CLASS && arrayDim == 0)
                         return resolver.lookupFieldByJvmName(className,
                                                     (Symbol)e.oprand2());
@@ -808,38 +636,25 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
         exprType = CLASS;
         arrayDim = 0;
         className =jvmJavaLangClass;
-        modifiedExpr = null;
     }
 
     public void atArrayLength(Expr expr) throws CompileError {
         expr.oprand1().accept(this);
-        if (modifiedExpr != null)
-            expr.setOprand1(modifiedExpr);
-
         exprType = INT;
         arrayDim = 0;
-        modifiedExpr = null;
     }
 
-    public void atArrayRead(Expr expr) throws CompileError {
-        ASTree array = expr.oprand1();
+    public void atArrayRead(ASTree array, ASTree index)
+        throws CompileError
+    {
         array.accept(this);
-        if (modifiedExpr != null)
-            expr.setOprand1(modifiedExpr);
-
         int type = exprType;
         int dim = arrayDim;
         String cname = className;
-
-        ASTree index = expr.oprand2();
         index.accept(this);
-        if (modifiedExpr != null)
-            expr.setOprand2(modifiedExpr);
-
         exprType = type;
         arrayDim = dim - 1;
         className = cname;
-        modifiedExpr = null;
     }
 
     private void atPlusPlus(int token, ASTree oprand, Expr expr)
@@ -853,13 +668,12 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
             Declarator d = ((Variable)oprand).getDeclarator();
             exprType = d.getType();
             arrayDim = d.getArrayDim();
-            modifiedExpr = null;
         }
         else {
             if (oprand instanceof Expr) {
                 Expr e = (Expr)oprand;
                 if (e.getOperator() == ARRAY) {
-                    atArrayRead(e);
+                    atArrayRead(e.oprand1(), e.oprand2());
                     // arrayDim should be 0.
                     int t = exprType;
                     if (t == INT || t == BYTE || t == CHAR || t == SHORT)
@@ -875,7 +689,8 @@ public class TypeChecker extends Visitor implements Opcode, TokenId {
 
     protected void atFieldPlusPlus(ASTree oprand) throws CompileError
     {
-        atFieldRead(oprand);
+        CtField f = fieldAccess(oprand);
+        atFieldRead(f);
         int t = exprType;
         if (t == INT || t == BYTE || t == CHAR || t == SHORT)
             exprType = INT;
index 064f8da8f23cefe312e577044a691cf4496ec8cc..84de35b495f2cb754fd7d4cf1864b4c6b653873e 100644 (file)
@@ -18,19 +18,18 @@ Shigeru Chiba
 
 <p><div align="right"><a href="tutorial2.html">Next page</a></div>
 
-<ul>1. <a href="#read">Reading bytecode</a>
-<br>2. <a href="#def">Defining a new class</a>
-<br>3. <a href="#pool">ClassPool</a>
-<br>4. <a href="#load">Class loader</a>
-<br>5. <a href="tutorial2.html#intro">Introspection and customization</a>
-<br>6. <a href="tutorial3.html#intro">Bytecode level API</a>
+<ul>1. <a href="#read">Reading and writing bytecode</a>
+<br>2. <a href="#pool">ClassPool</a>
+<br>3. <a href="#load">Class loader</a>
+<br>4. <a href="tutorial2.html#intro">Introspection and customization</a>
+<br>5. <a href="tutorial3.html#intro">Bytecode level API</a>
 
 </ul>
 
 <p><br>
 
 <a name="read">
-<h2>1. Reading bytecode</h2>
+<h2>1. Reading and writing bytecode</h2>
 
 <p>Javassist is a class library for dealing with Java bytecode.
 Java bytecode is stored in a binary file called a class file.
@@ -91,6 +90,59 @@ modified bytecode.  To obtain the bytecode, call <code>toBytecode()</code>:
 byte[] b = cc.toBytecode();
 </pre></ul>
 
+<a name="def">
+<h4>Defining a new class</h4>
+
+<p>To define a new class from scratch, <code>makeClass()</code>
+must be called on a <code>ClassPool</code>.
+
+<ul><pre>
+ClassPool pool = ClassPool.getDefault();
+CtClass cc = pool.makeClass("Point");
+</pre></ul>
+
+<p>This program defines a class <code>Point</code>
+including no members.
+
+<h4>Frozen classes</h4>
+
+<p>If a <code>CtClass</code> object is converted into a class file by
+<code>writeFile()</code>, <code>toClass()</code>, or
+<code>toBytecode()</code>, Javassist freezes that <code>CtClass</code>
+object.  Further modifications of that <code>CtClass</code> object are
+not permitted.
+
+<p>When Javassist freezes a <code>CtClass</code> object, it also
+prunes the data structure contained in that object.  To reduce memory
+consumption, Javassist discards some part of data structure, for
+example, the data of method bodies.  Thus, after a
+<code>CtClass</code> object is pruned, the bytecode of a method is not
+accessible although method names and signatures are accessible.
+
+<p>To disallow pruning a <code>CtClass</code>, <code>stopPruning()</code>
+must be called in advance:
+
+<ul><pre>
+CtClasss cc = ...;
+cc.stopPruning(true);
+    :
+cc.writeFile();                             // convert to a class file.
+// cc is not pruned.
+</pre></ul>
+
+<p>If a <code>CtClass</code> is not pruned, it can be defrost so that
+modifications of the class definition can be permitted.  For example,
+
+<ul><pre>
+CtClasss cc = ...;
+cc.stopPruning(true);
+    :
+cc.writeFile();
+cc.defrost();
+cc.setSuperclass(...);    // OK since the class is not frozen.
+</pre></ul>
+
+
 <h4>Class search path</h4>
 
 <p>The default <code>ClassPool</code> returned
@@ -187,21 +239,106 @@ included in the search path.
 
 <p><br>
 
-<a name="def">
-<h2>2. Defining a new class</h2>
+<a name="pool">
+<h2>2. ClassPool</h2>
 
-<p>To define a new class from scratch, <code>makeClass()</code>
-must be called on a <code>ClassPool</code>.
+<p>
+A <code>ClassPool</code> object is a container of <code>CtClass</code>
+objects.  Once a <code>CtClass</code> object is created, it is
+recorded in a <code>ClassPool</code> for ever.  This is because a
+compiler may need to access the <code>CtClass</code> object later when
+it compiles source code that refers to the class represented by that
+<code>CtClass</code>.
+
+<p>
+For example, suppose that a new method <code>getter()</code> is added
+to a <code>CtClass</code> object representing <code>Point</code>
+class.  Later, the program attempts to compile source code including a
+method call to <code>getter()</code> in <code>Point</code> and use the
+compiled code as the body of a method, which will be added to another
+class <code>Line</code>.  If the <code>CtClass</code> object representing
+<code>Point</code> is lost, the compiler cannot compile the method call
+to <code>getter()</code>.  Note that the original class definition does
+not include <code>getter()</code>.  Therefore, to correctly compile
+such a method call, the <code>ClassPool</code>
+must contain all the instances of <code>CtClass</code> all the time of
+program execution.
+
+<h4>Avoid out of memory</h4>
+
+<p>
+This specification of <code>ClassPool</code> may cause huge memory
+consumption if the number of <code>CtClass</code> objects becomes
+amazingly large (this rarely happens since Javassist tries to reduce
+memory consumption in various ways).  To avoid this problem, you
+can explicitly remove an unnecessary <code>CtClass</code> object from
+the <code>ClassPool</code>.  If you call <code>detach()</code> on a
+<code>CtClass</code> object, then that <code>CtClass</code> object is
+removed from the <code>ClassPool</code>.  For example,
 
 <ul><pre>
-ClassPool pool = ClassPool.getDefault();
-CtClass cc = pool.makeClass("Point");
+CtClass cc = ... ;
+cc.writeFile();
+cc.detach();
 </pre></ul>
 
-<p>This program defines a class <code>Point</code>
-including no members.
+<p>You must not call any method on that
+<code>CtClass</code> object after <code>detach()</code> is called.
+
+<p>
+Another idea is to occasionally replace a <code>ClassPool</code> with
+a new one and discard the old one.  If an old <code>ClassPool</code>
+is garbage collected, the <code>CtClass</code> objects included in
+that <code>ClassPool</code> are also garbage collected.
+To create a new instance of <code>ClassPool</code>, execute the following
+code snippet:
 
-<p>A new class can be also defined as a copy of an existing class.
+<ul><pre>
+ClassPool cp = new ClassPool();
+cp.appendSystemPath(); // or append another path by appendClassPath()
+</pre></ul>
+
+<p>This creates a <code>ClassPool</code> object that behaves as the
+default <code>ClassPool</code> returned by
+<code>ClassPool.getDefault()</code> does.
+Note that <code>ClassPool.getDefault()</code> is a singleton factory method
+provided for convenience.  Therefore, the default <code>ClassPool</code>
+is never garbage-collected.
+
+<h4>Cascaded ClassPools.</h4>
+
+<p>
+<code>ClassPool</code> objects can be cascaded like
+<code>java.lang.ClassLoader</code>.  For example,
+
+<ul><pre>
+ClassPool parent = ClassPool.getDefault();
+ClassPool child = new ClassPool(parent);
+child.insertClassPath("./classes");
+</pre></ul>
+
+<p>
+If <code>child.get()</code> is called, the child <code>ClassPool</code>
+first delegates to the parent <code>ClassPool</code>.  If the parent
+<code>ClassPool</code> fails to find a class file, then the child
+<code>ClassPool</code> attempts to find a class file
+under the <code>./classes</code> directory.
+
+<p>
+If <code>child.childFirstLookup</code> is true, the child
+<code>ClassPool</code> attempts to find a class file before delegating
+to the parent <code>ClassPool</code>.  For example,
+
+<ul><pre>
+ClassPool parent = ClassPool.getDefault();
+ClassPool child = new ClassPool(parent);
+child.appendSystemPath();         // the same class path as the default one.
+child.childFirstLookup = true;    // changes the behavior of the child.
+</pre></ul>
+
+<h4>Changing a class name for defining a new class</h4>
+
+<p>A new class can be defined as a copy of an existing class.
 The program below does that:
 
 <ul><pre>
@@ -258,26 +395,26 @@ mapping between classes and <code>CtClass</code> objects.  Javassist
 never allows two distinct <code>CtClass</code> objects to represent
 the same class unless two independent <code>ClassPool</code> are created.
 This is a significant feature for consistent program
-transformation.  To create multiple
-instances of <code>ClassPool</code>, write the following code:
+transformation.
+
+<p>To create another copy of the default instance of
+<code>ClassPool</code>, which is returned by
+<code>ClassPool.getDefault()</code>, execute the following code
+snippet (this code was already shown above):
 
 <ul><pre>
 ClassPool cp = new ClassPool();
 cp.appendSystemPath(); // or append another path by appendClassPath()
 </pre></ul>
 
-<p>This creates a <code>ClassPool</code> object that behaves as the
-default <code>ClassPool</code> returned by
-<code>ClassPool.getDefault()</code> does.
-<code>ClassPool.getDefault()</code> is a singleton factory method
-provided for convenience.
-
 <p>If you have two <code>ClassPool</code> objects, then you can
 obtain, from each <code>ClassPool</code>, a distinct
 <code>CtClass</code> object representing the same class file.  You can
 differently modify these <code>CtClass</code> objects to generate
 different versions of the class.
 
+<h4>Renaming a frozen class for defining a new class</h4>
+
 <p>Once a <code>CtClass</code> object is converted into a class file
 by <code>writeFile()</code> or <code>toBytecode()</code>, Javassist
 rejects further modifications of that <code>CtClass</code> object.
@@ -314,67 +451,10 @@ can be executed after <code>writeFile()</code> or <code>toBytecode()</code>
 is called on the the <code>CtClass</code> object representing <code>Point</code>
 class.
 
-
-<p><br>
-
-<a name="pool">
-<h2>3. ClassPool</h2>
-
-<p>
-A <code>ClassPool</code> object is a container of <code>CtClass</code>
-objects.  Once a <code>CtClass</code> object is created, it is
-recorded in a <code>ClassPool</code> for ever.  This is because a
-compiler may need to access the <code>CtClass</code> object later when
-it compiles source code that refers to the class represented by that
-<code>CtClass</code>.  If the class definition represented by that
-<code>CtClass</code> object is different from that of the original class
-file, the compiler cannot correctly compile the source code without
-the <code>CtClass</code> object.
-
-<p>
-This specification of <code>ClassPool</code> may cause huge memory
-consumption if the number of <code>CtClass</code> objects becomes large.
-To avoid this problem, you can explicitly remove an unnecessary
-<code>CtClass</code> object from the <code>ClassPool</code>.  If you
-call <code>detach()</code> on a <code>CtClass</code> object, then that
-<code>CtClass</code> object is removed from the <code>ClassPool</code>.
-For example,
-
-<ul><pre>
-CtClass cc = ... ;
-cc.writeFile();
-cc.detach();
-</pre></ul>
-
-<p>You must not call any method on that
-<code>CtClass</code> object after <code>detach()</code> is called.
-
-<p><code>ClassPool</code> objects can be cascaded like
-<code>java.lang.ClassLoader</code>.  For example,
-
-<ul><pre>
-ClassPool parent = ClassPool.getDefault();
-ClassPool child = new ClassPool(parent);
-</pre></ul>
-
-<p>If <code>child.get()</code> is called, the child <code>ClassPool</code>
-first delegates to the parent <code>ClassPool</code>.  If the parent
-<code>ClassPool</code> fails to find a class file, then the child
-<code>ClassPool</code> attempts to find a class file.
-If <code>child.childFirstLookup</code> is true, the child
-<code>ClassPool</code> attempts to find a class file before delegating
-to the parent <code>ClassPool</code>.  For example,
-
-<ul><pre>
-ClassPool parent = ClassPool.getDefault();
-ClassPool child = new ClassPool(parent);
-child.childFirstLookup = true;    // changes the behavior of the child.
-</pre></ul>
-
 <p><br>
 
 <a name="load">
-<h2>4. Class loader</h2>
+<h2>3. Class loader</h2>
 
 <p>If what classes must be modified is known in advance,
 the easiest way for modifying the classes is as follows:
@@ -396,7 +476,7 @@ by Javassist.
 
 <p><br>
 
-<h3>4.1 The <code>toClass</code> method in <code>CtClass</code></h3>
+<h3>3.1 The <code>toClass</code> method in <code>CtClass</code></h3>
 
 <p>The <code>CtClass</code> provides a convenience method
 <code>toClass()</code>, which requests the context class loader for
@@ -475,7 +555,7 @@ more complex functionality, you should write your own class loader.
 
 <p><br>
 
-<h3>4.2 Class loading in Java</h3>
+<h3>3.2 Class loading in Java</h3>
 
 <p>In Java, multiple class loaders can coexist and
 each class loader creates its own name space.
@@ -655,7 +735,7 @@ be helpful:
 
 <p><br>
 
-<h3>4.3 Using <code>javassist.Loader</code></h3>
+<h3>3.3 Using <code>javassist.Loader</code></h3>
 
 <p>Javassist provides a class loader
 <code>javassist.Loader</code>.  This class loader uses a
@@ -792,7 +872,7 @@ make sure whether all the classes using that class have been loaded by
 
 <p><br>
 
-<h3>4.4 Writing a class loader</h3>
+<h3>3.4 Writing a class loader</h3>
 
 <p>A simple class loader using Javassist is as follows:
 
@@ -863,7 +943,7 @@ Hence, the
 
 <p><br>
 
-<h3>4.5 Modifying a system class</h3>
+<h3>3.5 Modifying a system class</h3>
 
 <p>The system classes like <code>java.lang.String</code> cannot be
 loaded by a class loader other than the system class loader.
index 50d24712bdbcb7e749f2bc74addccb799184e8c0..9c158377b7e37b6bdc65cc2af45e74ab3db01c94 100644 (file)
@@ -13,7 +13,7 @@
 <div align="right"><a href="tutorial3.html">Next page</a></div>
 
 <p>
-<a href="#intro">5. Introspection and customization</a>
+<a href="#intro">4. Introspection and customization</a>
 <ul>
 <li><a href="#before">Inserting source text at the beginning/end of a method body</a>
 <br><li><a href="#alter">Altering a method body</a>
@@ -25,7 +25,7 @@
 <p><br>
 
 <a name="intro">
-<h2>5. Introspection and customization</h2>
+<h2>4. Introspection and customization</h2>
 
 <p><code>CtClass</code> provides methods for introspection.  The
 introspective ability of Javassist is compatible with that of
@@ -115,7 +115,7 @@ of the <code>javassist.runtime</code> package.
 <p><br>
 
 <a name="before">
-<h3>5.1 Inserting source text at the beginning/end of a method body</h3>
+<h3>4.1 Inserting source text at the beginning/end of a method body</h3>
 
 <p><code>CtMethod</code> and <code>CtConstructor</code> provide
 methods <code>insertBefore()</code>, <code>insertAfter()</code>, and
@@ -553,7 +553,7 @@ catch (java.io.IOException e) {
 <p><br>
 
 <a name="alter">
-<h3>5.2 Altering a method body</h3>
+<h3>4.2 Altering a method body</h3>
 
 <p><code>CtMethod</code> and <code>CtConstructor</code> provide
 <code>setBody()</code> for substituting a whole
@@ -1238,7 +1238,7 @@ exception.
 <p><br>
 
 <a name="add">
-<h3>5.3 Adding a new method or field</h3>
+<h3>4.3 Adding a new method or field</h3>
 
 <h4>Adding a method</h4>
 
@@ -1362,7 +1362,7 @@ does not end with a semi colon (<code>;</code>).
 <p><br>
 
 <a name="runtime">
-<h3>5.4 Runtime support classes</h3>
+<h3>4.4 Runtime support classes</h3>
 
 <p>In most cases, a class modified by Javassist does not require
 Javassist to run.  However, some kinds of bytecode generated by the
@@ -1376,7 +1376,7 @@ Javassist classes are never used at runtime of the modified classes.
 <p><br>
 
 <a name="limit">
-<h3>5.5 Limitations</h3>
+<h3>4.5 Limitations</h3>
 
 <p>In the current implementation, the Java compiler included in Javassist
 has several limitations with respect to the language that the compiler can
@@ -1389,13 +1389,6 @@ declarations.  However, the <code>java.lang</code> package is an
 exception; for example, the compiler accepts <code>Object</code> as
 well as <code>java.lang.Object</code>.
 
-<p><li>The <code>.class</code> notation is not supported.  Use the
-method <code>Class.forName()</code>.
-In regular
-Java, an expression <code>Point.class</code> means a <code>Class</code>
-object representing the <code>Point</code> class.  This notation is
-not available.
-
 <p><li>Array initializers, a comma-separated list of expressions
 enclosed by braces <code>{</code> and <code>}</code>, are not
 supported.
index c965a64c3c9ce6cba8c68e725f5524d3ea8f658b..af0a4c1b2bd5a717d493a62864eac2b3fab25375 100644 (file)
@@ -12,7 +12,7 @@
 <div align="left"><a href="tutorial2.html">Previous page</a></div>
 
 <p>
-<a href="#intro">6. Bytecode level API</a>
+<a href="#intro">5. Bytecode level API</a>
 <ul>
 <li><a href="#classfile">Obtaining a <code>ClassFile</code> object</a>
 <br><li><a href="#member">Adding and removing a member</a>
@@ -25,7 +25,7 @@
 <p><br>
 
 <a name="intro">
-<h2>6. Bytecode level API</h2>
+<h2>5. Bytecode level API</h2>
 
 <p>
 Javassist also provides lower-level API for directly editing
@@ -35,7 +35,7 @@ while this level of API allows you any kind of modification
 of class files.
 
 <a name="classfile">
-<h3>6.1 Obtaining a <code>ClassFile</code> object</h3>
+<h3>5.1 Obtaining a <code>ClassFile</code> object</h3>
 
 <p>A <code>javassist.bytecode.ClassFile</code> object represents
 a class file.  To obtian this object, <code>getClassFile()</code>
@@ -64,7 +64,7 @@ writes the contents of the class file to a given
 <p><br>
 
 <a name="member">
-<h3>6.2 Adding and removing a member</h3>
+<h3>5.2 Adding and removing a member</h3>
 
 <p>
 <code>ClassFile</code> provides <code>addField()</code> and
@@ -98,7 +98,7 @@ and remove one from the list.
 <p><br>
 
 <a name="traverse">
-<h3>6.3 Traversing a method body</h3>
+<h3>5.3 Traversing a method body</h3>
 
 <p>
 To examine every bytecode instruction in a method body,
@@ -143,7 +143,7 @@ Branch offsets etc. are automatically adjusted.<br>
 <p><br>
 
 <a name="bytecode">
-<h3>6.4 Producing a bytecode sequence</h3>
+<h3>5.4 Producing a bytecode sequence</h3>
 
 <p>
 A <code>Bytecode</code> object represents a sequence of bytecode