1 54 package org.logicalcobwebs.cglib.core; 55 56 import java.io.*; 57 import java.util.*; 58 import org.logicalcobwebs.asm.*; 59 60 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 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 className, Type superType, Type[] interfaces, String 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 ("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(); } 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 name, Type type, Object 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 ("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 boolean isFieldDeclared(String name) { 218 return fieldInfo.get(name) != null; 219 } 220 221 FieldInfo getFieldInfo(String name) { 222 FieldInfo field = (FieldInfo)fieldInfo.get(name); 223 if (field == null) { 224 throw new IllegalArgumentException ("Field " + name + " is not declared in " + classType.getClassName()); 225 } 226 return field; 227 } 228 229 static class FieldInfo { 230 int access; 231 String name; 232 Type type; 233 Object value; 234 235 public FieldInfo(int access, String name, Type type, Object value) { 236 this.access = access; 237 this.name = name; 238 this.type = type; 239 this.value = value; 240 } 241 242 public boolean equals(Object 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 name, String superName, String [] interfaces, String 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 name, String desc, Object value, Attribute attrs) { 278 declare_field(access, name, Type.getType(desc), value, attrs); 279 } 280 281 283 public CodeVisitor visitMethod(int access, String name, String desc, String [] 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 |