123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- /*
- * 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 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,
- * 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 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;
-
- 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.
- *
- * @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 identical 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.
- 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;
- }
- }
|