diff options
-rw-r--r-- | src/main/javassist/CtClass.java | 2 | ||||
-rw-r--r-- | src/main/javassist/bytecode/MethodInfo.java | 1 | ||||
-rw-r--r-- | src/main/javassist/compiler/AccessorMaker.java | 47 | ||||
-rw-r--r-- | src/main/javassist/compiler/MemberCodeGen.java | 42 | ||||
-rw-r--r-- | src/main/javassist/runtime/Inner.java | 24 |
5 files changed, 106 insertions, 10 deletions
diff --git a/src/main/javassist/CtClass.java b/src/main/javassist/CtClass.java index 8641f970..68f63031 100644 --- a/src/main/javassist/CtClass.java +++ b/src/main/javassist/CtClass.java @@ -35,7 +35,7 @@ public abstract class CtClass { /** * The version number of this release. */ - public static final String version = "3.0 RC1"; + public static final String version = "3.0 RC0"; /** * Prints the version number and the copyright notice. diff --git a/src/main/javassist/bytecode/MethodInfo.java b/src/main/javassist/bytecode/MethodInfo.java index ffe42438..56ef8036 100644 --- a/src/main/javassist/bytecode/MethodInfo.java +++ b/src/main/javassist/bytecode/MethodInfo.java @@ -57,6 +57,7 @@ public final class MethodInfo { /** * Constructs a <code>method_info</code> structure. + * The initial value of <code>access_flags</code> is zero. * * @param cp a constant pool table * @param methodname method name diff --git a/src/main/javassist/compiler/AccessorMaker.java b/src/main/javassist/compiler/AccessorMaker.java index bfe59f51..14f46194 100644 --- a/src/main/javassist/compiler/AccessorMaker.java +++ b/src/main/javassist/compiler/AccessorMaker.java @@ -28,12 +28,59 @@ public class AccessorMaker { private int uniqueNumber; private HashMap accessors; + static final String lastParamType = "javassist.runtime.Inner"; + public AccessorMaker(CtClass c) { clazz = c; uniqueNumber = 1; accessors = new HashMap(); } + public String getConstructor(CtClass c, String desc, MethodInfo orig) + throws CompileError + { + String key = "<init>:" + desc; + String consDesc = (String)accessors.get(key); + if (consDesc != null) + return consDesc; // already exists. + + consDesc = Descriptor.appendParameter(lastParamType, desc); + ClassFile cf = clazz.getClassFile(); // turn on the modified flag. + try { + ConstPool cp = cf.getConstPool(); + ClassPool pool = clazz.getClassPool(); + MethodInfo minfo + = new MethodInfo(cp, MethodInfo.nameInit, consDesc); + minfo.setAccessFlags(0); + minfo.addAttribute(new SyntheticAttribute(cp)); + ExceptionsAttribute ea = orig.getExceptionsAttribute(); + if (ea != null) + minfo.addAttribute(ea.copy(cp, null)); + + CtClass[] params = Descriptor.getParameterTypes(desc, pool); + Bytecode code = new Bytecode(cp); + code.addAload(0); + int regno = 1; + for (int i = 0; i < params.length; ++i) + regno += code.addLoad(regno, params[i]); + code.setMaxLocals(regno + 1); // the last parameter is added. + code.addInvokespecial(clazz, MethodInfo.nameInit, desc); + + code.addReturn(null); + minfo.setCodeAttribute(code.toCodeAttribute()); + cf.addMethod(minfo); + } + catch (CannotCompileException e) { + throw new CompileError(e); + } + catch (NotFoundException e) { + throw new CompileError(e); + } + + accessors.put(key, consDesc); + return consDesc; + } + /** * Returns the name of the method for accessing a private method. * diff --git a/src/main/javassist/compiler/MemberCodeGen.java b/src/main/javassist/compiler/MemberCodeGen.java index 0a58dc97..a70acf84 100644 --- a/src/main/javassist/compiler/MemberCodeGen.java +++ b/src/main/javassist/compiler/MemberCodeGen.java @@ -331,6 +331,7 @@ public class MemberCodeGen extends CodeGen { int stack = bytecode.getStackDepth(); + // generate code for evaluating arguments. atMethodArgs(args, types, dims, cnames); // used by invokeinterface @@ -370,12 +371,16 @@ public class MemberCodeGen extends CodeGen { isSpecial = true; if (declClass != targetClass) throw new CompileError("no such a constructor"); + + if (declClass != thisClass && AccessFlag.isPrivate(acc)) { + desc = getAccessibleConstructor(desc, declClass, minfo); + bytecode.addOpcode(Opcode.ACONST_NULL); // the last parameter + } } else if (AccessFlag.isPrivate(acc)) if (declClass == thisClass) isSpecial = true; else { - String orgName = mname; isSpecial = false; isStatic = true; String origDesc = desc; @@ -386,9 +391,6 @@ public class MemberCodeGen extends CodeGen { acc = AccessFlag.setPackage(acc) | AccessFlag.STATIC; mname = getAccessiblePrivate(mname, origDesc, desc, minfo, declClass); - if (mname == null) - throw new CompileError("Method " + orgName - + " is private"); } boolean popTarget = false; @@ -435,14 +437,36 @@ public class MemberCodeGen extends CodeGen { { if (isEnclosing(declClass, thisClass)) { AccessorMaker maker = declClass.getAccessorMaker(); - if (maker == null) - return null; - else + if (maker != null) return maker.getMethodAccessor(methodName, desc, newDesc, minfo); } - else - return null; // cannot access this private method. + + throw new CompileError("Method " + methodName + + " is private"); + } + + /* + * Finds (or adds if necessary) a hidden constructor if the given + * constructor is in an enclosing class. + * + * @param desc the descriptor of the constructor. + * @param declClass the class declaring the constructor. + * @param minfo the method info of the constructor. + * @return the descriptor of the hidden constructor. + */ + protected String getAccessibleConstructor(String desc, CtClass declClass, + MethodInfo minfo) + throws CompileError + { + if (isEnclosing(declClass, thisClass)) { + AccessorMaker maker = declClass.getAccessorMaker(); + if (maker != null) + return maker.getConstructor(declClass, desc, minfo); + } + + throw new CompileError("the called constructor is private in " + + declClass.getName()); } private boolean isEnclosing(CtClass outer, CtClass inner) { diff --git a/src/main/javassist/runtime/Inner.java b/src/main/javassist/runtime/Inner.java new file mode 100644 index 00000000..2aadf19b --- /dev/null +++ b/src/main/javassist/runtime/Inner.java @@ -0,0 +1,24 @@ +/* + * 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.runtime; + +/** + * A support class for compiling a method declared in an inner class. + * This support class is required at runtime + * only if the method calls a private constructor in the enclosing class. + */ +public class Inner { +} |