org.testifyproject.compiler.AccessorMaker Maven / Gradle / Ivy
The newest version!
/*
* Javassist, a Java-bytecode translator toolkit.
* Copyright (C) 1999- 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 org.testifyproject.testifyprojectpliance 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,
* or the Apache License Version 2.0.
*
* 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 org.testifyproject.org.testifyproject.testifyprojectpiler;
import org.testifyproject.*;
import org.testifyproject.bytecode.*;
import java.util.HashMap;
/**
* AccessorMaker maintains accessors to private members of an enclosing
* class. It is necessary for org.testifyproject.testifyprojectpiling a method in an inner class.
*/
public class AccessorMaker {
private CtClass clazz;
private int uniqueNumber;
private HashMap accessors;
static final String lastParamType = "org.testifyproject.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 = ":" + 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.
*
* @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 clazz
.
* If the private method is static,
* accDesc
must be identical to desc
.
*
* @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.
accName = findAccessorName(cf);
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;
}
/**
* Returns the method_info representing the added getter.
*/
public MethodInfo getFieldGetter(FieldInfo finfo, boolean is_static)
throws CompileError
{
String fieldName = finfo.getName();
String key = fieldName + ":getter";
Object res = accessors.get(key);
if (res != null)
return (MethodInfo)res; // already exists.
ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
String accName = findAccessorName(cf);
try {
ConstPool cp = cf.getConstPool();
ClassPool pool = clazz.getClassPool();
String fieldType = finfo.getDescriptor();
String accDesc;
if (is_static)
accDesc = "()" + fieldType;
else
accDesc = "(" + Descriptor.of(clazz) + ")" + fieldType;
MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
minfo.setAccessFlags(AccessFlag.STATIC);
minfo.addAttribute(new SyntheticAttribute(cp));
Bytecode code = new Bytecode(cp);
if (is_static) {
code.addGetstatic(Bytecode.THIS, fieldName, fieldType);
}
else {
code.addAload(0);
code.addGetfield(Bytecode.THIS, fieldName, fieldType);
code.setMaxLocals(1);
}
code.addReturn(Descriptor.toCtClass(fieldType, pool));
minfo.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(minfo);
accessors.put(key, minfo);
return minfo;
}
catch (CannotCompileException e) {
throw new CompileError(e);
}
catch (NotFoundException e) {
throw new CompileError(e);
}
}
/**
* Returns the method_info representing the added setter.
*/
public MethodInfo getFieldSetter(FieldInfo finfo, boolean is_static)
throws CompileError
{
String fieldName = finfo.getName();
String key = fieldName + ":setter";
Object res = accessors.get(key);
if (res != null)
return (MethodInfo)res; // already exists.
ClassFile cf = clazz.getClassFile(); // turn on the modified flag.
String accName = findAccessorName(cf);
try {
ConstPool cp = cf.getConstPool();
ClassPool pool = clazz.getClassPool();
String fieldType = finfo.getDescriptor();
String accDesc;
if (is_static)
accDesc = "(" + fieldType + ")V";
else
accDesc = "(" + Descriptor.of(clazz) + fieldType + ")V";
MethodInfo minfo = new MethodInfo(cp, accName, accDesc);
minfo.setAccessFlags(AccessFlag.STATIC);
minfo.addAttribute(new SyntheticAttribute(cp));
Bytecode code = new Bytecode(cp);
int reg;
if (is_static) {
reg = code.addLoad(0, Descriptor.toCtClass(fieldType, pool));
code.addPutstatic(Bytecode.THIS, fieldName, fieldType);
}
else {
code.addAload(0);
reg = code.addLoad(1, Descriptor.toCtClass(fieldType, pool))
+ 1;
code.addPutfield(Bytecode.THIS, fieldName, fieldType);
}
code.addReturn(null);
code.setMaxLocals(reg);
minfo.setCodeAttribute(code.toCodeAttribute());
cf.addMethod(minfo);
accessors.put(key, minfo);
return minfo;
}
catch (CannotCompileException e) {
throw new CompileError(e);
}
catch (NotFoundException e) {
throw new CompileError(e);
}
}
private String findAccessorName(ClassFile cf) {
String accName;
do {
accName = "access$" + uniqueNumber++;
} while (cf.getMethod(accName) != null);
return accName;
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy