1 23 24 package org.objectweb.fractal.adl; 25 26 import java.io.ByteArrayInputStream ; 27 import java.io.InputStream ; 28 import java.lang.reflect.Method ; 29 import java.util.HashMap ; 30 import java.util.HashSet ; 31 import java.util.Map ; 32 import java.util.Set ; 33 34 import org.objectweb.asm.ClassWriter; 35 import org.objectweb.asm.CodeVisitor; 36 import org.objectweb.asm.Constants; 37 import org.objectweb.asm.Label; 38 import org.objectweb.asm.Type; 39 40 43 44 public abstract class NodeClassLoader extends ClassLoader implements Constants { 45 46 49 50 private Map bytecodes = new HashMap (); 51 52 public NodeClassLoader (final ClassLoader parent) { 53 super(parent); 54 } 55 56 public ClassWriter generateClass ( 57 final String className, 58 final String astNodeName, 59 final String superClass, 60 final String [] itfs) throws ClassNotFoundException 61 { 62 String owner = className.replace('.', '/'); 63 String node = Type.getInternalName(Node.class); 64 65 ClassWriter cw = new ClassWriter(true); 66 cw.visit(V1_1, ACC_PUBLIC, owner, superClass, itfs, null); 67 68 CodeVisitor icv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null); 69 icv.visitVarInsn(ALOAD, 0); 70 icv.visitLdcInsn(astNodeName); 71 icv.visitMethodInsn(INVOKESPECIAL, superClass, "<init>", "(Ljava/lang/String;)V"); 72 73 CodeVisitor ani = cw.visitMethod( 74 ACC_PUBLIC, "astNewInstance", "()L" + node + ";", null, null); 75 ani.visitTypeInsn(NEW, owner); 76 ani.visitInsn(DUP); 77 ani.visitMethodInsn(INVOKESPECIAL, owner, "<init>", "()V"); 78 ani.visitInsn(ARETURN); 79 ani.visitMaxs(0, 0); 80 81 CodeVisitor aga = cw.visitMethod( 82 ACC_PUBLIC, "astGetAttributes", "()Ljava/util/Map;", null, null); 83 aga.visitTypeInsn(NEW, "java/util/HashMap"); 84 aga.visitInsn(DUP); 85 aga.visitMethodInsn(INVOKESPECIAL, "java/util/HashMap", "<init>", "()V"); 86 aga.visitVarInsn(ASTORE, 1); 87 88 CodeVisitor asa = cw.visitMethod( 89 ACC_PUBLIC, "astSetAttributes", "(Ljava/util/Map;)V", null, null); 90 91 CodeVisitor agn = cw.visitMethod( 92 ACC_PUBLIC, "astGetNodeTypes", "()[Ljava/lang/String;", null, null); 93 agn.visitIntInsn(SIPUSH, getNodeCount(itfs)); 94 agn.visitTypeInsn(ANEWARRAY, "java/lang/String"); 95 96 CodeVisitor agns = cw.visitMethod( 97 ACC_PUBLIC, "astGetNodes", "(Ljava/lang/String;)[L" + node + ";", null, null); 98 Label agnsEnd = new Label(); 99 agns.visitInsn(ACONST_NULL); 100 agns.visitVarInsn(ASTORE, 2); 101 102 CodeVisitor aan = cw.visitMethod( 103 ACC_PUBLIC, "astAddNode", "(L" + node + ";)V", null, null); 104 aan.visitVarInsn(ALOAD, 1); 105 aan.visitMethodInsn( 106 INVOKEINTERFACE, 107 "org/objectweb/fractal/adl/Node", 108 "astGetType", 109 "()Ljava/lang/String;"); 110 aan.visitVarInsn(ASTORE, 2); 111 Label aanEnd = new Label(); 112 113 CodeVisitor arn = cw.visitMethod( 114 ACC_PUBLIC, "astRemoveNode", "(L" + node + ";)V", null, null); 115 arn.visitVarInsn(ALOAD, 1); 116 arn.visitMethodInsn( 117 INVOKEINTERFACE, 118 "org/objectweb/fractal/adl/Node", 119 "astGetType", 120 "()Ljava/lang/String;"); 121 arn.visitVarInsn(ASTORE, 2); 122 Label arnEnd = new Label(); 123 124 int count = 0; 125 Set methods = new HashSet (); 126 for (int i = 0; i < itfs.length; ++i) { 127 Method [] meths = loadClass(itfs[i].replace('/', '.')).getMethods(); 128 for (int j = 0; j < meths.length; ++j) { 129 Method meth = meths[j]; 130 String name = meth.getName(); 131 String desc = Type.getMethodDescriptor(meth); 132 133 if (methods.contains(name + desc)) { 134 continue; 135 } 136 methods.add(name + desc); 137 138 CodeVisitor cv = cw.visitMethod(ACC_PUBLIC, name, desc, null, null); 139 140 if (name.startsWith("get")) { 141 String field = getFieldName(name, 3); 142 143 if (!desc.endsWith(")Ljava/lang/String;")) { 144 boolean single = desc.indexOf(")[") == -1; 145 agn.visitInsn(DUP); 147 agn.visitIntInsn(SIPUSH, count++); 148 agn.visitLdcInsn(getASTName(name, single)); 149 agn.visitInsn(AASTORE); 150 151 if (single) { 153 generateGetNodeMethod(agns, owner, name, field, desc.substring(2), agnsEnd); 154 } else { 155 generateGetNodesMethod(agns, owner, name, field, agnsEnd); 156 } 157 } 158 159 if (desc.startsWith("()[")) { 160 String fieldDesc = "Ljava/util/List;"; 162 String elemDesc = desc.substring(3); 163 164 cw.visitField(ACC_PRIVATE, field, fieldDesc, null, null); 166 167 cv.visitVarInsn(ALOAD, 0); 169 cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc); 170 cv.visitVarInsn(ALOAD, 0); 171 cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc); 172 cv.visitMethodInsn( 173 INVOKEINTERFACE, "java/util/List", "size", "()I"); 174 cv.visitTypeInsn( 175 ANEWARRAY, elemDesc.substring(1, elemDesc.length() - 1)); 176 cv.visitMethodInsn( 177 INVOKEINTERFACE, 178 "java/util/List", 179 "toArray", 180 "([Ljava/lang/Object;)[Ljava/lang/Object;"); 181 cv.visitTypeInsn(CHECKCAST, "[" + elemDesc); 182 cv.visitInsn(ARETURN); 183 cv.visitMaxs(0, 0); 184 185 icv.visitVarInsn(ALOAD, 0); 187 icv.visitTypeInsn(NEW, "java/util/ArrayList"); 188 icv.visitInsn(DUP); 189 icv.visitMethodInsn( 190 INVOKESPECIAL, "java/util/ArrayList", "<init>", "()V"); 191 icv.visitFieldInsn(PUTFIELD, owner, field, fieldDesc); 192 193 generateAddNodesMethod( 194 aan, owner, name, field, fieldDesc, aanEnd, true); 195 generateAddNodesMethod( 196 arn, owner, name, field, fieldDesc, arnEnd, false); 197 } else { 198 String fieldDesc = desc.substring(2); 200 201 cw.visitField(ACC_PRIVATE, field, fieldDesc, null, null); 203 204 cv.visitVarInsn(ALOAD, 0); 206 cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc); 207 cv.visitInsn(ARETURN); 208 cv.visitMaxs(0, 0); 209 210 if (fieldDesc.equals("Ljava/lang/String;")) { 211 213 aga.visitVarInsn(ALOAD, 1); 215 aga.visitLdcInsn(getASTName(name, true)); 216 aga.visitVarInsn(ALOAD, 0); 217 aga.visitFieldInsn(GETFIELD, owner, field, fieldDesc); 218 aga.visitMethodInsn( 219 INVOKEVIRTUAL, 220 "java/util/HashMap", 221 "put", 222 "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); 223 aga.visitInsn(POP); 224 225 asa.visitVarInsn(ALOAD, 0); 227 asa.visitVarInsn(ALOAD, 1); 228 asa.visitLdcInsn(getASTName(name, true)); 229 asa.visitMethodInsn( 230 INVOKEINTERFACE, 231 "java/util/Map", 232 "get", 233 "(Ljava/lang/Object;)Ljava/lang/Object;"); 234 asa.visitTypeInsn(CHECKCAST, "java/lang/String"); 235 asa.visitFieldInsn(PUTFIELD, owner, field, fieldDesc); 236 } else { 237 generateAddNodeMethod( 239 aan, owner, name, field, fieldDesc, aanEnd, true); 240 generateAddNodeMethod( 241 arn, owner, name, field, fieldDesc, arnEnd, false); 242 } 243 } 244 } else if (name.startsWith("set")) { 245 String field = getFieldName(name, 3); 246 String fieldDesc = desc.substring(1, desc.length() - 2); 247 cv.visitVarInsn(ALOAD, 0); 248 cv.visitVarInsn(ALOAD, 1); 249 cv.visitFieldInsn(PUTFIELD, owner, field, fieldDesc); 250 cv.visitInsn(RETURN); 251 cv.visitMaxs(0, 0); 252 } else if (name.startsWith("add")) { 253 String field = getFieldName(name, 3) + "s"; 254 String fieldDesc = "Ljava/util/List;"; 255 cv.visitVarInsn(ALOAD, 0); 256 cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc); 257 cv.visitVarInsn(ALOAD, 1); 258 cv.visitMethodInsn( 259 INVOKEINTERFACE, "java/util/List", "add", "(Ljava/lang/Object;)Z"); 260 cv.visitInsn(POP); 261 cv.visitInsn(RETURN); 262 cv.visitMaxs(0, 0); 263 } else if (name.startsWith("remove")) { 264 String field = getFieldName(name, 6) + "s"; 265 String fieldDesc = "Ljava/util/List;"; 266 cv.visitVarInsn(ALOAD, 0); 267 cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc); 268 cv.visitVarInsn(ALOAD, 1); 269 cv.visitMethodInsn( 270 INVOKEINTERFACE, "java/util/List", "remove", "(Ljava/lang/Object;)Z"); 271 cv.visitInsn(POP); 272 cv.visitInsn(RETURN); 273 cv.visitMaxs(0, 0); 274 } 275 } 276 } 277 278 icv.visitInsn(RETURN); 279 icv.visitMaxs(0, 0); 280 281 aga.visitVarInsn(ALOAD, 1); 282 aga.visitInsn(ARETURN); 283 aga.visitMaxs(0, 0); 284 285 asa.visitInsn(RETURN); 286 asa.visitMaxs(0, 0); 287 288 agn.visitInsn(ARETURN); 289 agn.visitMaxs(0, 0); 290 291 agns.visitLabel(agnsEnd); 292 agns.visitVarInsn(ALOAD, 2); 293 agns.visitInsn(ARETURN); 294 agns.visitMaxs(0, 0); 295 296 aan.visitLabel(aanEnd); 297 aan.visitInsn(RETURN); 298 aan.visitMaxs(0, 0); 299 300 arn.visitLabel(arnEnd); 301 arn.visitInsn(RETURN); 302 arn.visitMaxs(0, 0); 303 304 return cw; 305 } 306 307 protected Class defineClass (final String name, final byte[] b) { 308 bytecodes.put(name.replace('.', '/') + ".class", b); 309 return defineClass(name, b, 0, b.length); 310 } 311 312 public InputStream getResourceAsStream (final String name) { 313 InputStream is = super.getResourceAsStream(name); 314 if (is == null) { 315 byte[] b = (byte[])bytecodes.get(name); 316 if (b != null) { 317 is = new ByteArrayInputStream (b); 318 } 319 } 320 return is; 321 } 322 323 private int getNodeCount (final String [] itfs) throws ClassNotFoundException { 324 int count = 0; 325 Set methods = new HashSet (); 326 for (int i = 0; i < itfs.length; ++i) { 327 Method [] meths = loadClass(itfs[i].replace('/', '.')).getMethods(); 328 for (int j = 0; j < meths.length; ++j) { 329 Method meth = meths[j]; 330 String name = meth.getName(); 331 String desc = Type.getMethodDescriptor(meth); 332 if (methods.contains(name + desc)) { 333 continue; 334 } 335 methods.add(name + desc); 336 if (name.startsWith("get") && !desc.endsWith(")Ljava/lang/String;")) { 337 ++count; 338 } 339 } 340 } 341 return count; 342 } 343 344 private void generateGetNodeMethod ( 345 final CodeVisitor cv, 346 final String owner, final String name, 347 final String field, final String fieldDesc, final Label end) 348 { 349 Label l = generateIf(cv, 1, getASTName(name, true)); 350 cv.visitInsn(ICONST_1); 351 cv.visitTypeInsn(ANEWARRAY, Type.getInternalName(Node.class)); 352 cv.visitInsn(DUP); 353 cv.visitInsn(ICONST_0); 354 cv.visitVarInsn(ALOAD, 0); 355 cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc); 356 cv.visitInsn(AASTORE); 357 cv.visitVarInsn(ASTORE, 2); 358 cv.visitJumpInsn(GOTO, end); 359 cv.visitLabel(l); 360 } 361 362 private void generateGetNodesMethod ( 363 final CodeVisitor cv, 364 final String owner, final String name, 365 final String field, final Label end) 366 { 367 Label l = generateIf(cv, 1, getASTName(name, false)); 368 cv.visitVarInsn(ALOAD, 0); 369 cv.visitFieldInsn(GETFIELD, owner, field, "Ljava/util/List;"); 370 cv.visitVarInsn(ALOAD, 0); 371 cv.visitFieldInsn(GETFIELD, owner, field, "Ljava/util/List;"); 372 cv.visitMethodInsn( 373 INVOKEINTERFACE, "java/util/List", "size", "()I"); 374 cv.visitTypeInsn( 375 ANEWARRAY, Type.getInternalName(Node.class)); 376 cv.visitMethodInsn( 377 INVOKEINTERFACE, 378 "java/util/List", 379 "toArray", 380 "([Ljava/lang/Object;)[Ljava/lang/Object;"); 381 cv.visitTypeInsn(CHECKCAST, "[" + Type.getDescriptor(Node.class)); 382 cv.visitVarInsn(ASTORE, 2); 383 cv.visitJumpInsn(GOTO, end); 384 cv.visitLabel(l); 385 } 386 387 private void generateAddNodeMethod ( 388 final CodeVisitor cv, 389 final String owner, final String name, 390 final String field, final String fieldDesc, 391 final Label end, final boolean add) 392 { 393 String s = getASTName(name, true); 394 Label l = generateIf(cv, 2, s); 395 cv.visitVarInsn(ALOAD, 0); 396 if (add) { 397 cv.visitVarInsn(ALOAD, 1); 398 cv.visitTypeInsn( 399 CHECKCAST, fieldDesc.substring(1, fieldDesc.length() - 1)); 400 } else { 401 cv.visitInsn(ACONST_NULL); 402 } 403 cv.visitFieldInsn(PUTFIELD, owner, field, fieldDesc); 404 cv.visitJumpInsn(GOTO, end); 405 cv.visitLabel(l); 406 } 407 408 private void generateAddNodesMethod ( 409 final CodeVisitor cv, 410 final String owner, final String name, 411 final String field, final String fieldDesc, 412 final Label end, final boolean add) 413 { 414 String s = getASTName(name, false); 415 Label l = generateIf(cv, 2, s); 416 cv.visitVarInsn(ALOAD, 0); 417 cv.visitFieldInsn(GETFIELD, owner, field, fieldDesc); 418 cv.visitVarInsn(ALOAD, 1); 419 cv.visitMethodInsn( 420 INVOKEINTERFACE, 421 "java/util/List", 422 add ? "add" : "remove", 423 add ? "(Ljava/lang/Object;)Z" : "(Ljava/lang/Object;)Z"); 424 cv.visitInsn(POP); 425 cv.visitJumpInsn(GOTO, end); 426 cv.visitLabel(l); 427 } 428 429 private Label generateIf (final CodeVisitor cv, final int var, final String name) { 430 Label l = new Label(); 431 cv.visitVarInsn(ALOAD, var); 432 cv.visitLdcInsn(name); 433 cv.visitMethodInsn( 434 INVOKEVIRTUAL, 435 "java/lang/Object", 436 "equals", 437 "(Ljava/lang/Object;)Z"); 438 cv.visitJumpInsn(IFEQ, l); 439 return l; 440 } 441 442 public static String getASTName (final String name, final boolean single) { 443 char c = Character.toLowerCase(name.charAt(3)); 444 if (single) { 445 return c + name.substring(4); 446 } else { 447 return c + name.substring(4, name.length() - 1); 448 } 449 } 450 451 public static String getFieldName (final String name, final int prefix) { 452 char c = Character.toLowerCase(name.charAt(prefix)); 453 return "_" + c + name.substring(prefix + 1); 454 } 455 } 456 | Popular Tags |