KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > logicalcobwebs > cglib > core > ClassEmitter


1 /*
2  * The Apache Software License, Version 1.1
3  *
4  * Copyright (c) 2002 The Apache Software Foundation. All rights
5  * reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  * notice, this list of conditions and the following disclaimer.
13  *
14  * 2. Redistributions in binary form must reproduce the above copyright
15  * notice, this list of conditions and the following disclaimer in
16  * the documentation and/or other materials provided with the
17  * distribution.
18  *
19  * 3. The end-user documentation included with the redistribution,
20  * if any, must include the following acknowledgment:
21  * "This product includes software developed by the
22  * Apache Software Foundation (http://www.apache.org/)."
23  * Alternately, this acknowledgment may appear in the software itself,
24  * if and wherever such third-party acknowledgments normally appear.
25  *
26  * 4. The names "Apache" and "Apache Software Foundation" must
27  * not be used to endorse or promote products derived from this
28  * software without prior written permission. For written
29  * permission, please contact apache@apache.org.
30  *
31  * 5. Products derived from this software may not be called "Apache",
32  * nor may "Apache" appear in their name, without prior written
33  * permission of the Apache Software Foundation.
34  *
35  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
36  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
37  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
38  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
39  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
40  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
41  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
42  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
43  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
44  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
45  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
46  * SUCH DAMAGE.
47  * ====================================================================
48  *
49  * This software consists of voluntary contributions made by many
50  * individuals on behalf of the Apache Software Foundation. For more
51  * information on the Apache Software Foundation, please see
52  * <http://www.apache.org/>.
53  */

54 package org.logicalcobwebs.cglib.core;
55
56 import java.io.*;
57 import java.util.*;
58 import org.logicalcobwebs.asm.*;
59
60 /**
61  * @author Juozas Baliuka, Chris Nokleberg
62  */

63 public class ClassEmitter extends ClassAdapter {
64     private static final Signature STATIC_HOOK =
65       TypeUtils.parseSignature("void CGLIB$STATIC_HOOK()");
66     private static final String JavaDoc STATIC_HOOK_FLAG = "CGLIB$STATIC_HOOK_FLAG";
67
68     private int access;
69     private Type classType;
70     private Type superType;
71     private Map fieldInfo;
72     private boolean seenStatic;
73     private CodeEmitter hook;
74     private boolean ended;
75     private ClassVisitor outer;
76
77     public ClassEmitter(ClassVisitor cv) {
78         super(null);
79         setTarget(cv, this);
80     }
81
82     public ClassEmitter() {
83         super(null);
84     }
85
86     public void setTarget(ClassVisitor cv, ClassVisitor outer) {
87         this.cv = cv;
88         this.outer = outer;
89         fieldInfo = new HashMap();
90         seenStatic = false;
91         hook = null;
92         ended = false;
93     }
94
95     public void begin_class(int access, String JavaDoc className, Type superType, Type[] interfaces, String JavaDoc sourceFile) {
96         this.access = access;
97         this.classType = Type.getType("L" + className.replace('.', '/') + ";");
98         this.superType = (superType != null) ? superType : Constants.TYPE_OBJECT;
99         cv.visit(access,
100                  this.classType.getInternalName(),
101                  this.superType.getInternalName(),
102                  TypeUtils.toInternalNames(interfaces),
103                  sourceFile);
104         init();
105     }
106
107     public CodeEmitter getStaticHook() {
108          if (TypeUtils.isInterface(access)) {
109              throw new IllegalStateException JavaDoc("static hook is invalid for this class");
110          }
111          if (hook == null) {
112              ClassEmitter oe = new ClassEmitter(outer);
113              oe.declare_field(Constants.PRIVATE_FINAL_STATIC, STATIC_HOOK_FLAG, Type.BOOLEAN_TYPE, null, null);
114              CodeEmitter e = oe.begin_method(Constants.ACC_STATIC, STATIC_HOOK, null, null);
115              Label ok = e.make_label();
116              e.getstatic(classType, STATIC_HOOK_FLAG, Type.BOOLEAN_TYPE);
117              e.if_jump(e.EQ, ok);
118              e.return_value();
119              e.mark(ok);
120              e.push(true);
121              e.putstatic(classType, STATIC_HOOK_FLAG, Type.BOOLEAN_TYPE);
122          }
123          return hook;
124     }
125
126     protected void init() {
127     }
128
129     public int getAccess() {
130         return access;
131     }
132
133     public Type getClassType() {
134         return classType;
135     }
136
137     public Type getSuperType() {
138         return superType;
139     }
140
141     public void end_class() {
142         if (seenStatic && hook == null) {
143             getStaticHook(); // force hook method creation
144
}
145         if (hook != null) {
146             if (!seenStatic) {
147                 CodeVisitor v = outer.visitMethod(Constants.ACC_STATIC,
148                                                   Constants.SIG_STATIC.getName(),
149                                                   Constants.SIG_STATIC.getDescriptor(),
150                                                   null,
151                                                   null);
152                 v.visitInsn(Constants.RETURN);
153                 v.visitMaxs(0, 0);
154             }
155             ended = true;
156             hook.return_value();
157             hook.end_method();
158         }
159         cv.visitEnd();
160     }
161
162     public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions, Attribute attrs) {
163         CodeVisitor v = cv.visitMethod(access,
164                                        sig.getName(),
165                                        sig.getDescriptor(),
166                                        TypeUtils.toInternalNames(exceptions),
167                                        attrs);
168         if (sig.equals(STATIC_HOOK)) {
169             hook = new CodeEmitter(this, v, access, sig, exceptions) {
170                 public boolean isStaticHook() {
171                     return true;
172                 }
173                 public void visitMaxs(int maxStack, int maxLocals) {
174                     if (ended) {
175                         super.visitMaxs(maxStack, maxLocals);
176                     }
177                 }
178                 public void visitInsn(int insn) {
179                     if (insn != Constants.RETURN || ended) {
180                         super.visitInsn(insn);
181                     }
182                 }
183             };
184             return hook;
185         } else {
186             CodeEmitter e = new CodeEmitter(this, v, access, sig, exceptions);
187             if (sig.equals(Constants.SIG_STATIC) && !TypeUtils.isInterface(this.access)) {
188                 seenStatic = true;
189                 e.invoke_static_this(STATIC_HOOK);
190             }
191             return e;
192         }
193     }
194
195     public CodeEmitter begin_static() {
196         return begin_method(Constants.ACC_STATIC, Constants.SIG_STATIC, null, null);
197     }
198
199     public void declare_field(int access, String JavaDoc name, Type type, Object JavaDoc value, Attribute attrs) {
200         FieldInfo existing = (FieldInfo)fieldInfo.get(name);
201         FieldInfo info = new FieldInfo(access, name, type, value);
202         if (existing != null) {
203             if (!info.equals(existing)) {
204                 throw new IllegalArgumentException JavaDoc("Field \"" + name + "\" has been declared differently");
205             }
206         } else {
207             fieldInfo.put(name, info);
208             cv.visitField(access, name, type.getDescriptor(), value, attrs);
209         }
210     }
211
212     public void define_attribute(Attribute attrs) {
213         cv.visitAttribute(attrs);
214     }
215
216     // TODO: make public?
217
boolean isFieldDeclared(String JavaDoc name) {
218         return fieldInfo.get(name) != null;
219     }
220
221     FieldInfo getFieldInfo(String JavaDoc name) {
222         FieldInfo field = (FieldInfo)fieldInfo.get(name);
223         if (field == null) {
224             throw new IllegalArgumentException JavaDoc("Field " + name + " is not declared in " + classType.getClassName());
225         }
226         return field;
227     }
228     
229     static class FieldInfo {
230         int access;
231         String JavaDoc name;
232         Type type;
233         Object JavaDoc value;
234         
235         public FieldInfo(int access, String JavaDoc name, Type type, Object JavaDoc value) {
236             this.access = access;
237             this.name = name;
238             this.type = type;
239             this.value = value;
240         }
241
242         public boolean equals(Object JavaDoc o) {
243             if (o == null)
244                 return false;
245             if (!(o instanceof FieldInfo))
246                 return false;
247             FieldInfo other = (FieldInfo)o;
248             if (access != other.access ||
249                 !name.equals(other.name) ||
250                 !type.equals(other.type)) {
251                 return false;
252             }
253             if ((value == null) ^ (other.value == null))
254                 return false;
255             if (value != null && !value.equals(other.value))
256                 return false;
257             return true;
258         }
259
260         public int hashCode() {
261             return access ^ name.hashCode() ^ type.hashCode() ^ ((value == null) ? 0 : value.hashCode());
262         }
263     }
264
265     public void visit(int access, String JavaDoc name, String JavaDoc superName, String JavaDoc[] interfaces, String JavaDoc sourceFile) {
266         begin_class(access,
267                     name.replace('/', '.'),
268                     TypeUtils.fromInternalName(superName),
269                     TypeUtils.fromInternalNames(interfaces),
270                     sourceFile);
271     }
272     
273     public void visitEnd() {
274         end_class();
275     }
276     
277     public void visitField(int access, String JavaDoc name, String JavaDoc desc, Object JavaDoc value, Attribute attrs) {
278         declare_field(access, name, Type.getType(desc), value, attrs);
279     }
280
281     // TODO: handle visitInnerClass?
282

283     public CodeVisitor visitMethod(int access, String JavaDoc name, String JavaDoc desc, String JavaDoc[] exceptions, Attribute attrs) {
284         return begin_method(access,
285                             new Signature(name, desc),
286                             TypeUtils.fromInternalNames(exceptions),
287                             attrs);
288     }
289
290     public void visitAttribute(Attribute attrs) {
291         define_attribute(attrs);
292     }
293 }
294
Popular Tags