001: /*
002: * Copyright 2003 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package net.sf.cglib.core;
017:
018: import java.io.*;
019: import java.util.*;
020: import org.objectweb.asm.*;
021:
022: /**
023: * @author Juozas Baliuka, Chris Nokleberg
024: */
025: public class ClassEmitter extends ClassAdapter {
026: private ClassInfo classInfo;
027: private Map fieldInfo;
028:
029: private static int hookCounter;
030: private MethodVisitor rawStaticInit;
031: private CodeEmitter staticInit;
032: private CodeEmitter staticHook;
033: private Signature staticHookSig;
034:
035: public ClassEmitter(ClassVisitor cv) {
036: super (null);
037: setTarget(cv);
038: }
039:
040: public ClassEmitter() {
041: super (null);
042: }
043:
044: public void setTarget(ClassVisitor cv) {
045: this .cv = cv;
046: fieldInfo = new HashMap();
047:
048: // just to be safe
049: staticInit = staticHook = null;
050: staticHookSig = null;
051: }
052:
053: synchronized private static int getNextHook() {
054: return ++hookCounter;
055: }
056:
057: public ClassInfo getClassInfo() {
058: return classInfo;
059: }
060:
061: public void begin_class(int version, final int access,
062: String className, final Type super Type,
063: final Type[] interfaces, String source) {
064: final Type classType = Type.getType("L"
065: + className.replace('.', '/') + ";");
066: classInfo = new ClassInfo() {
067: public Type getType() {
068: return classType;
069: }
070:
071: public Type getSuperType() {
072: return (super Type != null) ? super Type
073: : Constants.TYPE_OBJECT;
074: }
075:
076: public Type[] getInterfaces() {
077: return interfaces;
078: }
079:
080: public int getModifiers() {
081: return access;
082: }
083: };
084: cv.visit(version, access,
085: classInfo.getType().getInternalName(), null, classInfo
086: .getSuperType().getInternalName(), TypeUtils
087: .toInternalNames(interfaces));
088: if (source != null)
089: cv.visitSource(source, null);
090: init();
091: }
092:
093: public CodeEmitter getStaticHook() {
094: if (TypeUtils.isInterface(getAccess())) {
095: throw new IllegalStateException(
096: "static hook is invalid for this class");
097: }
098: if (staticHook == null) {
099: staticHookSig = new Signature("CGLIB$STATICHOOK"
100: + getNextHook(), "()V");
101: staticHook = begin_method(Constants.ACC_STATIC,
102: staticHookSig, null);
103: if (staticInit != null) {
104: staticInit.invoke_static_this (staticHookSig);
105: }
106: }
107: return staticHook;
108: }
109:
110: protected void init() {
111: }
112:
113: public int getAccess() {
114: return classInfo.getModifiers();
115: }
116:
117: public Type getClassType() {
118: return classInfo.getType();
119: }
120:
121: public Type getSuperType() {
122: return classInfo.getSuperType();
123: }
124:
125: public void end_class() {
126: if (staticHook != null && staticInit == null) {
127: // force creation of static init
128: begin_static();
129: }
130: if (staticInit != null) {
131: staticHook.return_value();
132: staticHook.end_method();
133: rawStaticInit.visitInsn(Constants.RETURN);
134: rawStaticInit.visitMaxs(0, 0);
135: staticInit = staticHook = null;
136: staticHookSig = null;
137: }
138: cv.visitEnd();
139: }
140:
141: public CodeEmitter begin_method(int access, Signature sig,
142: Type[] exceptions) {
143: if (classInfo == null)
144: throw new IllegalStateException("classInfo is null! "
145: + this );
146: MethodVisitor v = cv.visitMethod(access, sig.getName(), sig
147: .getDescriptor(), null, TypeUtils
148: .toInternalNames(exceptions));
149: if (sig.equals(Constants.SIG_STATIC)
150: && !TypeUtils.isInterface(getAccess())) {
151: rawStaticInit = v;
152: MethodVisitor wrapped = new MethodAdapter(v) {
153: public void visitMaxs(int maxStack, int maxLocals) {
154: // ignore
155: }
156:
157: public void visitInsn(int insn) {
158: if (insn != Constants.RETURN) {
159: super .visitInsn(insn);
160: }
161: }
162: };
163: staticInit = new CodeEmitter(this , wrapped, access, sig,
164: exceptions);
165: if (staticHook == null) {
166: // force static hook creation
167: getStaticHook();
168: } else {
169: staticInit.invoke_static_this (staticHookSig);
170: }
171: return staticInit;
172: } else if (sig.equals(staticHookSig)) {
173: return new CodeEmitter(this , v, access, sig, exceptions) {
174: public boolean isStaticHook() {
175: return true;
176: }
177: };
178: } else {
179: return new CodeEmitter(this , v, access, sig, exceptions);
180: }
181: }
182:
183: public CodeEmitter begin_static() {
184: return begin_method(Constants.ACC_STATIC, Constants.SIG_STATIC,
185: null);
186: }
187:
188: public void declare_field(int access, String name, Type type,
189: Object value) {
190: FieldInfo existing = (FieldInfo) fieldInfo.get(name);
191: FieldInfo info = new FieldInfo(access, name, type, value);
192: if (existing != null) {
193: if (!info.equals(existing)) {
194: throw new IllegalArgumentException("Field \"" + name
195: + "\" has been declared differently");
196: }
197: } else {
198: fieldInfo.put(name, info);
199: cv.visitField(access, name, type.getDescriptor(), null,
200: value);
201: }
202: }
203:
204: // TODO: make public?
205: boolean isFieldDeclared(String name) {
206: return fieldInfo.get(name) != null;
207: }
208:
209: FieldInfo getFieldInfo(String name) {
210: FieldInfo field = (FieldInfo) fieldInfo.get(name);
211: if (field == null) {
212: throw new IllegalArgumentException("Field " + name
213: + " is not declared in "
214: + getClassType().getClassName());
215: }
216: return field;
217: }
218:
219: static class FieldInfo {
220: int access;
221: String name;
222: Type type;
223: Object value;
224:
225: public FieldInfo(int access, String name, Type type,
226: Object value) {
227: this .access = access;
228: this .name = name;
229: this .type = type;
230: this .value = value;
231: }
232:
233: public boolean equals(Object o) {
234: if (o == null)
235: return false;
236: if (!(o instanceof FieldInfo))
237: return false;
238: FieldInfo other = (FieldInfo) o;
239: if (access != other.access || !name.equals(other.name)
240: || !type.equals(other.type)) {
241: return false;
242: }
243: if ((value == null) ^ (other.value == null))
244: return false;
245: if (value != null && !value.equals(other.value))
246: return false;
247: return true;
248: }
249:
250: public int hashCode() {
251: return access ^ name.hashCode() ^ type.hashCode()
252: ^ ((value == null) ? 0 : value.hashCode());
253: }
254: }
255:
256: public void visit(int version, int access, String name,
257: String signature, String super Name, String[] interfaces) {
258: begin_class(version, access, name.replace('/', '.'), TypeUtils
259: .fromInternalName(super Name), TypeUtils
260: .fromInternalNames(interfaces), null); // TODO
261: }
262:
263: public void visitEnd() {
264: end_class();
265: }
266:
267: public FieldVisitor visitField(int access, String name,
268: String desc, String signature, Object value) {
269: declare_field(access, name, Type.getType(desc), value);
270: return null; // TODO
271: }
272:
273: public MethodVisitor visitMethod(int access, String name,
274: String desc, String signature, String[] exceptions) {
275: return begin_method(access, new Signature(name, desc),
276: TypeUtils.fromInternalNames(exceptions));
277: }
278: }
|