Browse Source

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 20 years ago
parent
commit
94ddad2e3f

+ 8
- 1
src/main/javassist/CtClass.java View File

*/ */
public ClassFile getClassFile2() { return null; } 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. * Returns the uniform resource locator (URL) of the class file.
*/ */


void checkModify() throws RuntimeException { void checkModify() throws RuntimeException {
if (isFrozen()) 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. // isModified() must return true after this method is invoked.
} }

+ 11
- 0
src/main/javassist/CtClassType.java View File

import javassist.bytecode.*; import javassist.bytecode.*;
import javassist.compiler.Javac; import javassist.compiler.Javac;
import javassist.compiler.CompileError; import javassist.compiler.CompileError;
import javassist.compiler.AccessorMaker;
import javassist.expr.ExprEditor; import javassist.expr.ExprEditor;
import java.io.InputStream; import java.io.InputStream;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
private CtConstructor classInitializerCache; private CtConstructor classInitializerCache;
private CtMethod methodsCache; private CtMethod methodsCache;


private AccessorMaker accessors;

private FieldInitLink fieldInitializers; private FieldInitLink fieldInitializers;
private Hashtable hiddenMethods; // must be synchronous private Hashtable hiddenMethods; // must be synchronous
private int uniqueNumberSeed; private int uniqueNumberSeed;
classPool = cp; classPool = cp;
wasChanged = wasFrozen = false; wasChanged = wasFrozen = false;
classfile = null; classfile = null;
accessors = null;
fieldInitializers = null; fieldInitializers = null;
hiddenMethods = null; hiddenMethods = null;
uniqueNumberSeed = 0; uniqueNumberSeed = 0;
methodsCache = null; methodsCache = null;
} }


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

return accessors;
}

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

+ 13
- 0
src/main/javassist/bytecode/Bytecode.java View File

stackDepth = 0; 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(). /* used in add().
*/ */
private Bytecode() { private Bytecode() {

+ 1
- 1
src/main/javassist/bytecode/ExceptionsAttribute.java View File

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

+ 101
- 0
src/main/javassist/compiler/AccessorMaker.java View File

/*
* 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 View File



package javassist.compiler; package javassist.compiler;


import javassist.CannotCompileException;
import javassist.NotFoundException;

public class CompileError extends Exception { public class CompileError extends Exception {
private Lex lex; private Lex lex;
private String reason; private String reason;
lex = null; lex = null;
} }


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

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

public String getMessage() { public String getMessage() {
return reason; return reason;
} }

+ 49
- 12
src/main/javassist/compiler/MemberCodeGen.java View File

throw new CompileError(msg); 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; CtClass declClass = found.declaring;
MethodInfo minfo = found.info; MethodInfo minfo = found.info;
String desc = minfo.getDescriptor(); String desc = minfo.getDescriptor();
throw new CompileError("no such a constructor"); throw new CompileError("no such a constructor");
} }
else if ((acc & AccessFlag.PRIVATE) != 0) { 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; boolean popTarget = false;


bytecode.addInvokestatic(declClass, mname, desc); bytecode.addInvokestatic(declClass, mname, desc);
} }
else if (isSpecial)
else if (isSpecial) // if (isSpecial && notStatic(acc))
bytecode.addInvokespecial(declClass, mname, desc); bytecode.addInvokespecial(declClass, mname, desc);
else if (declClass.isInterface()) else if (declClass.isInterface())
bytecode.addInvokeinterface(declClass, mname, desc, count); bytecode.addInvokeinterface(declClass, mname, desc, count);
setReturnType(desc, isStatic, popTarget); 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 else
return null; // cannot access this private method. return null; // cannot access this private method.
} }

Loading…
Cancel
Save