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 net.sf.cglib.core;
55
56 import java.io.*;
57 import java.util.*;
58 import org.objectweb.asm.*;
59
60 /***
61 * @author Juozas Baliuka, Chris Nokleberg
62 */
63 public class ClassEmitter extends ClassAdapter {
64 private int access;
65 private Type classType;
66 private Type superType;
67 private Map fieldInfo;
68
69 private static int hookCounter;
70 private CodeVisitor rawStaticInit;
71 private CodeEmitter staticInit;
72 private CodeEmitter staticHook;
73 private Signature staticHookSig;
74
75 public ClassEmitter(ClassVisitor cv) {
76 super(null);
77 setTarget(cv);
78 }
79
80 public ClassEmitter() {
81 super(null);
82 }
83
84 public void setTarget(ClassVisitor cv) {
85 this.cv = cv;
86 fieldInfo = new HashMap();
87
88 // just to be safe
89 staticInit = staticHook = null;
90 staticHookSig = null;
91 }
92
93 synchronized private static int getNextHook() {
94 return ++hookCounter;
95 }
96
97 public void begin_class(int access, String className, Type superType, Type[] interfaces, String sourceFile) {
98 this.access = access;
99 this.classType = Type.getType("L" + className.replace('.', '/') + ";");
100 this.superType = (superType != null) ? superType : Constants.TYPE_OBJECT;
101 cv.visit(access,
102 this.classType.getInternalName(),
103 this.superType.getInternalName(),
104 TypeUtils.toInternalNames(interfaces),
105 sourceFile);
106 init();
107 }
108
109 public CodeEmitter getStaticHook() {
110 if (TypeUtils.isInterface(access)) {
111 throw new IllegalStateException("static hook is invalid for this class");
112 }
113 if (staticHook == null) {
114 staticHookSig = new Signature("CGLIB$STATICHOOK" + getNextHook(), "()V");
115 staticHook = begin_method(Constants.ACC_STATIC,
116 staticHookSig,
117 null,
118 null);
119 if (staticInit != null) {
120 staticInit.invoke_static_this(staticHookSig);
121 }
122 }
123 return staticHook;
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 (staticHook != null && staticInit == null) {
143 // force creation of static init
144 begin_static();
145 }
146 if (staticInit != null) {
147 staticHook.return_value();
148 staticHook.end_method();
149 rawStaticInit.visitInsn(Constants.RETURN);
150 rawStaticInit.visitMaxs(0, 0);
151 staticInit = staticHook = null;
152 staticHookSig = null;
153 }
154 cv.visitEnd();
155 }
156
157 public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions, Attribute attrs) {
158 if (classType == null)
159 throw new IllegalStateException("classtype is null! " + this);
160 CodeVisitor v = cv.visitMethod(access,
161 sig.getName(),
162 sig.getDescriptor(),
163 TypeUtils.toInternalNames(exceptions),
164 attrs);
165 if (sig.equals(Constants.SIG_STATIC) && !TypeUtils.isInterface(this.access)) {
166 rawStaticInit = v;
167 CodeVisitor wrapped = new CodeAdapter(v) {
168 public void visitMaxs(int maxStack, int maxLocals) {
169 // ignore
170 }
171 public void visitInsn(int insn) {
172 if (insn != Constants.RETURN) {
173 super.visitInsn(insn);
174 }
175 }
176 };
177 staticInit = new CodeEmitter(this, wrapped, access, sig, exceptions);
178 if (staticHook == null) {
179 // force static hook creation
180 getStaticHook();
181 } else {
182 staticInit.invoke_static_this(staticHookSig);
183 }
184 return staticInit;
185 } else if (sig.equals(staticHookSig)) {
186 return new CodeEmitter(this, v, access, sig, exceptions) {
187 public boolean isStaticHook() {
188 return true;
189 }
190 };
191 } else {
192 return new CodeEmitter(this, v, access, sig, exceptions);
193 }
194 }
195
196 public CodeEmitter begin_static() {
197 return begin_method(Constants.ACC_STATIC, Constants.SIG_STATIC, null, null);
198 }
199
200 public void declare_field(int access, String name, Type type, Object value, Attribute attrs) {
201 FieldInfo existing = (FieldInfo)fieldInfo.get(name);
202 FieldInfo info = new FieldInfo(access, name, type, value);
203 if (existing != null) {
204 if (!info.equals(existing)) {
205 throw new IllegalArgumentException("Field \"" + name + "\" has been declared differently");
206 }
207 } else {
208 fieldInfo.put(name, info);
209 cv.visitField(access, name, type.getDescriptor(), value, attrs);
210 }
211 }
212
213 public void define_attribute(Attribute attrs) {
214 cv.visitAttribute(attrs);
215 }
216
217 // TODO: make public?
218 boolean isFieldDeclared(String name) {
219 return fieldInfo.get(name) != null;
220 }
221
222 FieldInfo getFieldInfo(String name) {
223 FieldInfo field = (FieldInfo)fieldInfo.get(name);
224 if (field == null) {
225 throw new IllegalArgumentException("Field " + name + " is not declared in " + classType.getClassName());
226 }
227 return field;
228 }
229
230 static class FieldInfo {
231 int access;
232 String name;
233 Type type;
234 Object value;
235
236 public FieldInfo(int access, String name, Type type, Object value) {
237 this.access = access;
238 this.name = name;
239 this.type = type;
240 this.value = value;
241 }
242
243 public boolean equals(Object o) {
244 if (o == null)
245 return false;
246 if (!(o instanceof FieldInfo))
247 return false;
248 FieldInfo other = (FieldInfo)o;
249 if (access != other.access ||
250 !name.equals(other.name) ||
251 !type.equals(other.type)) {
252 return false;
253 }
254 if ((value == null) ^ (other.value == null))
255 return false;
256 if (value != null && !value.equals(other.value))
257 return false;
258 return true;
259 }
260
261 public int hashCode() {
262 return access ^ name.hashCode() ^ type.hashCode() ^ ((value == null) ? 0 : value.hashCode());
263 }
264 }
265
266 public void visit(int access, String name, String superName, String[] interfaces, String sourceFile) {
267 begin_class(access,
268 name.replace('/', '.'),
269 TypeUtils.fromInternalName(superName),
270 TypeUtils.fromInternalNames(interfaces),
271 sourceFile);
272 }
273
274 public void visitEnd() {
275 end_class();
276 }
277
278 public void visitField(int access, String name, String desc, Object value, Attribute attrs) {
279 declare_field(access, name, Type.getType(desc), value, attrs);
280 }
281
282 // TODO: handle visitInnerClass?
283
284 public CodeVisitor visitMethod(int access, String name, String desc, String[] exceptions, Attribute attrs) {
285 return begin_method(access,
286 new Signature(name, desc),
287 TypeUtils.fromInternalNames(exceptions),
288 attrs);
289 }
290
291 public void visitAttribute(Attribute attrs) {
292 define_attribute(attrs);
293 }
294 }
This page was automatically generated by Maven