Procházet zdrojové kódy

Now, the compiler accepts a method that calls a private method

declared in an enclosing class.


git-svn-id: http://anonsvn.jboss.org/repos/javassist/trunk@97 30ef5769-5b8d-40dd-aea6-55b5d6557bb3
tags/rel_3_17_1_ga
chiba před 20 roky
rodič
revize
94ddad2e3f

+ 8
- 1
src/main/javassist/CtClass.java Zobrazit soubor

@@ -203,6 +203,13 @@ public abstract class CtClass {
*/
public ClassFile getClassFile2() { return null; }

/**
* Undocumented method. Do not use; internal-use only.
*/
public javassist.compiler.AccessorMaker getAccessorMaker() {
return null;
}

/**
* Returns the uniform resource locator (URL) of the class file.
*/
@@ -227,7 +234,7 @@ public abstract class CtClass {

void checkModify() throws RuntimeException {
if (isFrozen())
throw new RuntimeException("the class is frozen");
throw new RuntimeException(getName() + " class is frozen");

// isModified() must return true after this method is invoked.
}

+ 11
- 0
src/main/javassist/CtClassType.java Zobrazit soubor

@@ -18,6 +18,7 @@ package javassist;
import javassist.bytecode.*;
import javassist.compiler.Javac;
import javassist.compiler.CompileError;
import javassist.compiler.AccessorMaker;
import javassist.expr.ExprEditor;
import java.io.InputStream;
import java.io.BufferedInputStream;
@@ -44,6 +45,8 @@ class CtClassType extends CtClass {
private CtConstructor classInitializerCache;
private CtMethod methodsCache;

private AccessorMaker accessors;

private FieldInitLink fieldInitializers;
private Hashtable hiddenMethods; // must be synchronous
private int uniqueNumberSeed;
@@ -53,6 +56,7 @@ class CtClassType extends CtClass {
classPool = cp;
wasChanged = wasFrozen = false;
classfile = null;
accessors = null;
fieldInitializers = null;
hiddenMethods = null;
uniqueNumberSeed = 0;
@@ -104,6 +108,13 @@ class CtClassType extends CtClass {
methodsCache = null;
}

public AccessorMaker getAccessorMaker() {
if (accessors == null)
accessors = new AccessorMaker(this);

return accessors;
}

public ClassFile getClassFile2() {
if (classfile != null)
return classfile;

+ 13
- 0
src/main/javassist/bytecode/Bytecode.java Zobrazit soubor

@@ -78,6 +78,19 @@ public class Bytecode implements Opcode {
stackDepth = 0;
}

/**
* Constructs a <code>Bytecode</code> object with an empty bytecode
* sequence. The initial values of <code>max_stack</code> and
* <code>max_locals</code> are zero.
*
* @param cp constant pool table.
* @see Bytecode#setMaxStack(int)
* @see Bytecode#setMaxLocals(int)
*/
public Bytecode(ConstPool cp) {
this(cp, 0, 0);
}

/* used in add().
*/
private Bytecode() {

+ 1
- 1
src/main/javassist/bytecode/ExceptionsAttribute.java Zobrazit soubor

@@ -64,7 +64,7 @@ public class ExceptionsAttribute extends AttributeInfo {
*
* @param newCp the constant pool table used by the new copy.
* @param classnames pairs of replaced and substituted
* class names.
* class names. It can be <code>null</code>.
*/
public AttributeInfo copy(ConstPool newCp, Map classnames) {
return new ExceptionsAttribute(newCp, this, classnames);

+ 101
- 0
src/main/javassist/compiler/AccessorMaker.java Zobrazit soubor

@@ -0,0 +1,101 @@
/*
* 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.compiler;

import javassist.*;
import javassist.bytecode.*;
import java.util.HashMap;

/**
* AccessorMaker maintains accessors to private members of an enclosing
* class. It is necessary for compiling a method in an inner class.
*/
public class AccessorMaker {
private CtClass clazz;
private int uniqueNumber;
private HashMap accessors;

public AccessorMaker(CtClass c) {
clazz = c;
uniqueNumber = 1;
accessors = new HashMap();
}

/**
* Returns the name of the method for accessing a private method.
*
* @param name the name of the private method.
* @param desc the descriptor of the private method.
* @param accDesc the descriptor of the accessor method. The first
* parameter type is <code>clazz</code>.
* If the private method is static,
* <code>accDesc<code> must be equal to <code>desc</code>.
*
* @param orig the method info of the private method.
* @return
*/
public String getMethodAccessor(String name, String desc, String accDesc,
MethodInfo orig)
throws CompileError
{
String key = name + ":" + desc;
String accName = (String)accessors.get(key);
if (accName != null)
return accName; // already exists.

ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
do {
accName = "access$" + uniqueNumber++;
} while (cf.getMethod(accName) != null);

try {
ConstPool cp = cf.getConstPool();
ClassPool pool = clazz.getClassPool();
MethodInfo minfo
= new MethodInfo(cp, accName, accDesc);
minfo.setAccessFlags(AccessFlag.STATIC);
minfo.addAttribute(new SyntheticAttribute(cp));
ExceptionsAttribute ea = orig.getExceptionsAttribute();
if (ea != null)
minfo.addAttribute(ea.copy(cp, null));

CtClass[] params = Descriptor.getParameterTypes(accDesc, pool);
int regno = 0;
Bytecode code = new Bytecode(cp);
for (int i = 0; i < params.length; ++i)
regno += code.addLoad(regno, params[i]);

code.setMaxLocals(regno);
if (desc == accDesc)
code.addInvokestatic(clazz, name, desc);
else
code.addInvokevirtual(clazz, name, desc);

code.addReturn(Descriptor.getReturnType(desc, pool));
minfo.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(minfo);
}
catch (CannotCompileException e) {
throw new CompileError(e);
}
catch (NotFoundException e) {
throw new CompileError(e);
}

accessors.put(key, accName);
return accName;
}
}

+ 11
- 0
src/main/javassist/compiler/CompileError.java Zobrazit soubor

@@ -15,6 +15,9 @@

package javassist.compiler;

import javassist.CannotCompileException;
import javassist.NotFoundException;

public class CompileError extends Exception {
private Lex lex;
private String reason;
@@ -29,6 +32,14 @@ public class CompileError extends Exception {
lex = null;
}

public CompileError(CannotCompileException e) {
this(e.getReason());
}

public CompileError(NotFoundException e) {
this("cannot find " + e.getMessage());
}

public String getMessage() {
return reason;
}

+ 49
- 12
src/main/javassist/compiler/MemberCodeGen.java Zobrazit soubor

@@ -351,6 +351,16 @@ public class MemberCodeGen extends CodeGen {
throw new CompileError(msg);
}

atMethodCallCore2(targetClass, mname, isStatic, isSpecial,
aload0pos, count, found);
}

private void atMethodCallCore2(CtClass targetClass, String mname,
boolean isStatic, boolean isSpecial,
int aload0pos, int count,
MemberResolver.Method found)
throws CompileError
{
CtClass declClass = found.declaring;
MethodInfo minfo = found.info;
String desc = minfo.getDescriptor();
@@ -362,11 +372,24 @@ public class MemberCodeGen extends CodeGen {
throw new CompileError("no such a constructor");
}
else if ((acc & AccessFlag.PRIVATE) != 0) {
isSpecial = true;
String orgName = mname;
mname = getAccessiblePrivate(mname, declClass);
if (mname == null)
throw new CompileError("Method " + orgName + " is private");
if (declClass == thisClass)
isSpecial = true;
else {
String orgName = mname;
isSpecial = false;
isStatic = true;
String origDesc = desc;
if ((acc & AccessFlag.STATIC) == 0)
desc = Descriptor.insertParameter(declClass.getName(),
origDesc);

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;
@@ -386,7 +409,7 @@ public class MemberCodeGen extends CodeGen {

bytecode.addInvokestatic(declClass, mname, desc);
}
else if (isSpecial)
else if (isSpecial) // if (isSpecial && notStatic(acc))
bytecode.addInvokespecial(declClass, mname, desc);
else if (declClass.isInterface())
bytecode.addInvokeinterface(declClass, mname, desc, count);
@@ -399,12 +422,26 @@ public class MemberCodeGen extends CodeGen {
setReturnType(desc, isStatic, popTarget);
}

protected String getAccessiblePrivate(String methodName,
CtClass declClass) {
if (declClass == thisClass)
return methodName;
else if (isEnclosing(declClass, thisClass))
return null;
/*
* Finds (or adds if necessary) a hidden accessor if the method
* is in an enclosing class.
*
* @param desc the descriptor of the method.
* @param declClass the class declaring the method.
*/
protected String getAccessiblePrivate(String methodName, String desc,
String newDesc, MethodInfo minfo,
CtClass declClass)
throws CompileError
{
if (isEnclosing(declClass, thisClass)) {
AccessorMaker maker = declClass.getAccessorMaker();
if (maker == null)
return null;
else
return maker.getMethodAccessor(methodName, desc, newDesc,
minfo);
}
else
return null; // cannot access this private method.
}

Načítá se…
Zrušit
Uložit