1/*- 2 * See the file LICENSE for redistribution information. 3 * 4 * Copyright (c) 2002-2009 Oracle. All rights reserved. 5 * 6 * $Id$ 7 */ 8 9package com.sleepycat.persist.model; 10 11import static com.sleepycat.asm.Opcodes.AALOAD; 12import static com.sleepycat.asm.Opcodes.ACC_ABSTRACT; 13import static com.sleepycat.asm.Opcodes.ACC_PRIVATE; 14import static com.sleepycat.asm.Opcodes.ACC_PUBLIC; 15import static com.sleepycat.asm.Opcodes.ACC_STATIC; 16import static com.sleepycat.asm.Opcodes.ACC_TRANSIENT; 17import static com.sleepycat.asm.Opcodes.ACONST_NULL; 18import static com.sleepycat.asm.Opcodes.ALOAD; 19import static com.sleepycat.asm.Opcodes.ANEWARRAY; 20import static com.sleepycat.asm.Opcodes.ARETURN; 21import static com.sleepycat.asm.Opcodes.BIPUSH; 22import static com.sleepycat.asm.Opcodes.CHECKCAST; 23import static com.sleepycat.asm.Opcodes.DCMPL; 24import static com.sleepycat.asm.Opcodes.DCONST_0; 25import static com.sleepycat.asm.Opcodes.DUP; 26import static com.sleepycat.asm.Opcodes.FCMPL; 27import static com.sleepycat.asm.Opcodes.FCONST_0; 28import static com.sleepycat.asm.Opcodes.GETFIELD; 29import static com.sleepycat.asm.Opcodes.GOTO; 30import static com.sleepycat.asm.Opcodes.ICONST_0; 31import static com.sleepycat.asm.Opcodes.ICONST_1; 32import static com.sleepycat.asm.Opcodes.ICONST_2; 33import static com.sleepycat.asm.Opcodes.ICONST_3; 34import static com.sleepycat.asm.Opcodes.ICONST_4; 35import static com.sleepycat.asm.Opcodes.ICONST_5; 36import static com.sleepycat.asm.Opcodes.IFEQ; 37import static com.sleepycat.asm.Opcodes.IFGT; 38import static com.sleepycat.asm.Opcodes.IFLE; 39import static com.sleepycat.asm.Opcodes.IFNE; 40import static com.sleepycat.asm.Opcodes.IFNONNULL; 41import static com.sleepycat.asm.Opcodes.IF_ICMPNE; 42import static com.sleepycat.asm.Opcodes.ILOAD; 43import static com.sleepycat.asm.Opcodes.INVOKEINTERFACE; 44import static com.sleepycat.asm.Opcodes.INVOKESPECIAL; 45import static com.sleepycat.asm.Opcodes.INVOKESTATIC; 46import static com.sleepycat.asm.Opcodes.INVOKEVIRTUAL; 47import static com.sleepycat.asm.Opcodes.IRETURN; 48import static com.sleepycat.asm.Opcodes.ISUB; 49import static com.sleepycat.asm.Opcodes.LCMP; 50import static com.sleepycat.asm.Opcodes.LCONST_0; 51import static com.sleepycat.asm.Opcodes.NEW; 52import static com.sleepycat.asm.Opcodes.POP; 53import static com.sleepycat.asm.Opcodes.PUTFIELD; 54import static com.sleepycat.asm.Opcodes.RETURN; 55 56import java.math.BigInteger; 57import java.util.ArrayList; 58import java.util.Collections; 59import java.util.Comparator; 60import java.util.Date; 61import java.util.HashMap; 62import java.util.List; 63import java.util.Map; 64 65import com.sleepycat.asm.AnnotationVisitor; 66import com.sleepycat.asm.Attribute; 67import com.sleepycat.asm.ClassAdapter; 68import com.sleepycat.asm.ClassVisitor; 69import com.sleepycat.asm.FieldVisitor; 70import com.sleepycat.asm.Label; 71import com.sleepycat.asm.MethodVisitor; 72import com.sleepycat.asm.Type; 73 74/** 75 * An ASM ClassVisitor that examines a class, throws NotPersistentException if 76 * it is not persistent, or enhances it if it is persistent. A class is 77 * persistent if it contains the @Entity or @Persistent annotations. A 78 * resulting enhanced class implements the com.sleepycat.persist.impl.Enhanced 79 * interface. 80 * 81 * <p>NotPersistentException is thrown to abort the transformation in order to 82 * avoid making two passes over the class file (one to look for the annotations 83 * and another to enhance the bytecode) or outputing a class that isn't 84 * enhanced. By aborting the transformation as soon as we detect that the 85 * annotations are missing, we make only one partial pass for a non-persistent 86 * class.</p> 87 * 88 * @author Mark Hayes 89 */ 90class BytecodeEnhancer extends ClassAdapter { 91 92 /** Thrown when we determine that a class is not persistent. */ 93 @SuppressWarnings("serial") 94 static class NotPersistentException extends RuntimeException {} 95 96 /** A static instance is used to avoid fillInStaceTrace overhead. */ 97 private static final NotPersistentException NOT_PERSISTENT = 98 new NotPersistentException(); 99 100 private static final Map<String,Integer> PRIMITIVE_WRAPPERS = 101 new HashMap<String,Integer>(); 102 static { 103 PRIMITIVE_WRAPPERS.put(Boolean.class.getName(), Type.BOOLEAN); 104 PRIMITIVE_WRAPPERS.put(Character.class.getName(), Type.CHAR); 105 PRIMITIVE_WRAPPERS.put(Byte.class.getName(), Type.BYTE); 106 PRIMITIVE_WRAPPERS.put(Short.class.getName(), Type.SHORT); 107 PRIMITIVE_WRAPPERS.put(Integer.class.getName(), Type.INT); 108 PRIMITIVE_WRAPPERS.put(Long.class.getName(), Type.LONG); 109 PRIMITIVE_WRAPPERS.put(Float.class.getName(), Type.FLOAT); 110 PRIMITIVE_WRAPPERS.put(Double.class.getName(), Type.DOUBLE); 111 } 112 113 private String className; 114 private String superclassName; 115 private boolean isPersistent; 116 private boolean isAbstract; 117 private boolean hasDefaultConstructor; 118 private boolean hasPersistentSuperclass; 119 private boolean isCompositeKey; 120 private FieldInfo priKeyField; 121 private List<FieldInfo> secKeyFields; 122 private List<FieldInfo> nonKeyFields; 123 private String staticBlockMethod; 124 125 BytecodeEnhancer(ClassVisitor parentVisitor) { 126 super(parentVisitor); 127 secKeyFields = new ArrayList<FieldInfo>(); 128 nonKeyFields = new ArrayList<FieldInfo>(); 129 } 130 131 @Override 132 public void visit(int version, 133 int access, 134 String name, 135 String sig, 136 String superName, 137 String[] interfaces) { 138 className = name; 139 superclassName = superName; 140 final String ENHANCED = "com/sleepycat/persist/impl/Enhanced"; 141 if (containsString(interfaces, ENHANCED)) { 142 throw abort(); 143 } 144 interfaces = appendString(interfaces, ENHANCED); 145 isAbstract = ((access & ACC_ABSTRACT) != 0); 146 hasPersistentSuperclass = 147 (superName != null && !superName.equals("java/lang/Object")); 148 super.visit(version, access, name, sig, superName, interfaces); 149 } 150 151 @Override 152 public void visitSource(String source, String debug) { 153 super.visitSource(source, debug); 154 } 155 156 @Override 157 public AnnotationVisitor visitAnnotation(String desc, boolean visible) { 158 if (desc.equals("Lcom/sleepycat/persist/model/Entity;") || 159 desc.equals("Lcom/sleepycat/persist/model/Persistent;")) { 160 isPersistent = true; 161 } 162 return super.visitAnnotation(desc, visible); 163 } 164 165 @Override 166 public FieldVisitor visitField(int access, 167 String name, 168 String desc, 169 String sig, 170 Object value) { 171 if (!isPersistent) { 172 throw abort(); 173 } 174 FieldVisitor ret = super.visitField(access, name, desc, sig, value); 175 if ((access & ACC_STATIC) == 0) { 176 FieldInfo info = new FieldInfo(ret, name, desc, 177 (access & ACC_TRANSIENT) != 0); 178 nonKeyFields.add(info); 179 ret = info; 180 } 181 return ret; 182 } 183 184 @Override 185 public MethodVisitor visitMethod(int access, 186 String name, 187 String desc, 188 String sig, 189 String[] exceptions) { 190 if (!isPersistent) { 191 throw abort(); 192 } 193 if ("<init>".equals(name) && "()V".equals(desc)) { 194 hasDefaultConstructor = true; 195 } 196 if ("<clinit>".equals(name)) { 197 if (staticBlockMethod != null) { 198 throw new IllegalStateException(); 199 } 200 staticBlockMethod = "bdbExistingStaticBlock"; 201 return cv.visitMethod 202 (ACC_PRIVATE + ACC_STATIC, staticBlockMethod, "()V", null, 203 null); 204 } 205 return super.visitMethod(access, name, desc, sig, exceptions); 206 } 207 208 @Override 209 public void visitEnd() { 210 if (!isPersistent || !hasDefaultConstructor) { 211 throw abort(); 212 } 213 /* Generate new code at the end of the class. */ 214 sortFields(); 215 genBdbNewInstance(); 216 genBdbNewArray(); 217 genBdbIsPriKeyFieldNullOrZero(); 218 genBdbWritePriKeyField(); 219 genBdbReadPriKeyField(); 220 genBdbWriteSecKeyFields(); 221 genBdbReadSecKeyFields(); 222 genBdbWriteNonKeyFields(); 223 genBdbReadNonKeyFields(); 224 genBdbWriteCompositeKeyFields(); 225 genBdbReadCompositeKeyFields(); 226 genBdbGetField(); 227 genBdbSetField(); 228 genStaticBlock(); 229 super.visitEnd(); 230 } 231 232 private void sortFields() { 233 /* 234 System.out.println("AllFields: " + nonKeyFields); 235 //*/ 236 if (nonKeyFields.size() == 0) { 237 return; 238 } 239 isCompositeKey = true; 240 for (FieldInfo field : nonKeyFields) { 241 if (field.order == null) { 242 isCompositeKey = false; 243 } 244 } 245 if (isCompositeKey) { 246 Collections.sort(nonKeyFields, new Comparator<FieldInfo>() { 247 public int compare(FieldInfo f1, FieldInfo f2) { 248 return f1.order.value - f2.order.value; 249 } 250 }); 251 } else { 252 for (int i = 0; i < nonKeyFields.size();) { 253 FieldInfo field = nonKeyFields.get(i); 254 if (field.isTransient) { 255 nonKeyFields.remove(i); 256 } else if (field.isPriKey) { 257 if (priKeyField == null) { 258 priKeyField = field; 259 nonKeyFields.remove(i); 260 } 261 } else if (field.isSecKey) { 262 secKeyFields.add(field); 263 nonKeyFields.remove(i); 264 } else { 265 i += 1; 266 } 267 } 268 Comparator<FieldInfo> cmp = new Comparator<FieldInfo>() { 269 public int compare(FieldInfo f1, FieldInfo f2) { 270 return f1.name.compareTo(f2.name); 271 } 272 }; 273 Collections.sort(secKeyFields, cmp); 274 Collections.sort(nonKeyFields, cmp); 275 } 276 /* 277 System.out.println("PriKey: " + priKeyField); 278 System.out.println("SecKeys: " + secKeyFields); 279 System.out.println("NonKeys: " + nonKeyFields); 280 //*/ 281 } 282 283 /** 284 * Outputs code in a static block to register the prototype instance: 285 * 286 * static { 287 * EnhancedAccessor.registerClass(TheClassName, new TheClass()); 288 * // or for an abstract class: 289 * EnhancedAccessor.registerClass(TheClassName, null); 290 * } 291 */ 292 private void genStaticBlock() { 293 MethodVisitor mv = 294 cv.visitMethod(ACC_STATIC, "<clinit>", "()V", null, null); 295 mv.visitCode(); 296 if (staticBlockMethod != null) { 297 mv.visitMethodInsn 298 (INVOKESTATIC, className, staticBlockMethod, "()V"); 299 } 300 mv.visitLdcInsn(className.replace('/', '.')); 301 if (isAbstract) { 302 mv.visitInsn(ACONST_NULL); 303 } else { 304 mv.visitTypeInsn(NEW, className); 305 mv.visitInsn(DUP); 306 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V"); 307 } 308 mv.visitMethodInsn 309 (INVOKESTATIC, "com/sleepycat/persist/impl/EnhancedAccessor", 310 "registerClass", 311 "(Ljava/lang/String;Lcom/sleepycat/persist/impl/Enhanced;)V"); 312 mv.visitInsn(RETURN); 313 mv.visitMaxs(3, 0); 314 mv.visitEnd(); 315 } 316 317 /** 318 * public Object bdbNewInstance() { 319 * return new TheClass(); 320 * // or if abstract: 321 * return null; 322 * } 323 */ 324 private void genBdbNewInstance() { 325 MethodVisitor mv = cv.visitMethod 326 (ACC_PUBLIC, "bdbNewInstance", "()Ljava/lang/Object;", null, null); 327 mv.visitCode(); 328 if (isAbstract) { 329 mv.visitInsn(ACONST_NULL); 330 mv.visitInsn(ARETURN); 331 mv.visitMaxs(1, 1); 332 } else { 333 mv.visitTypeInsn(NEW, className); 334 mv.visitInsn(DUP); 335 mv.visitMethodInsn(INVOKESPECIAL, className, "<init>", "()V"); 336 mv.visitInsn(ARETURN); 337 mv.visitMaxs(2, 1); 338 } 339 mv.visitEnd(); 340 } 341 342 /** 343 * public Object bdbNewArray(int len) { 344 * return new TheClass[len]; 345 * // or if abstract: 346 * return null; 347 * } 348 */ 349 private void genBdbNewArray() { 350 MethodVisitor mv = cv.visitMethod 351 (ACC_PUBLIC, "bdbNewArray", "(I)Ljava/lang/Object;", null, null); 352 mv.visitCode(); 353 if (isAbstract) { 354 mv.visitInsn(ACONST_NULL); 355 mv.visitInsn(ARETURN); 356 mv.visitMaxs(1, 2); 357 } else { 358 mv.visitVarInsn(ILOAD, 1); 359 mv.visitTypeInsn(ANEWARRAY, className); 360 mv.visitInsn(ARETURN); 361 mv.visitMaxs(1, 2); 362 mv.visitEnd(); 363 } 364 } 365 366 /** 367 * public boolean bdbIsPriKeyFieldNullOrZero() { 368 * return theField == null; // or zero or false, as appropriate 369 * // or if no primary key but has superclass: 370 * return super.bdbIsPriKeyFieldNullOrZero(); 371 * } 372 */ 373 private void genBdbIsPriKeyFieldNullOrZero() { 374 MethodVisitor mv = cv.visitMethod 375 (ACC_PUBLIC, "bdbIsPriKeyFieldNullOrZero", "()Z", null, null); 376 mv.visitCode(); 377 if (priKeyField != null) { 378 mv.visitVarInsn(ALOAD, 0); 379 mv.visitFieldInsn 380 (GETFIELD, className, priKeyField.name, 381 priKeyField.type.getDescriptor()); 382 Label l0 = new Label(); 383 if (isRefType(priKeyField.type)) { 384 mv.visitJumpInsn(IFNONNULL, l0); 385 } else { 386 genBeforeCompareToZero(mv, priKeyField.type); 387 mv.visitJumpInsn(IFNE, l0); 388 } 389 mv.visitInsn(ICONST_1); 390 Label l1 = new Label(); 391 mv.visitJumpInsn(GOTO, l1); 392 mv.visitLabel(l0); 393 mv.visitInsn(ICONST_0); 394 mv.visitLabel(l1); 395 } else if (hasPersistentSuperclass) { 396 mv.visitVarInsn(ALOAD, 0); 397 mv.visitMethodInsn 398 (INVOKESPECIAL, superclassName, "bdbIsPriKeyFieldNullOrZero", 399 "()Z"); 400 } else { 401 mv.visitInsn(ICONST_0); 402 } 403 mv.visitInsn(IRETURN); 404 mv.visitMaxs(1, 1); 405 mv.visitEnd(); 406 } 407 408 /** 409 * public void bdbWritePriKeyField(EntityOutput output, Format format) { 410 * output.writeKeyObject(theField, format); 411 * // or 412 * output.writeInt(theField); // and other simple types 413 * // or if no primary key but has superclass: 414 * return super.bdbWritePriKeyField(output, format); 415 * } 416 */ 417 private void genBdbWritePriKeyField() { 418 MethodVisitor mv = cv.visitMethod 419 (ACC_PUBLIC, "bdbWritePriKeyField", 420 "(Lcom/sleepycat/persist/impl/EntityOutput;" + 421 "Lcom/sleepycat/persist/impl/Format;)V", 422 null, null); 423 mv.visitCode(); 424 if (priKeyField != null) { 425 if (!genWriteSimpleKeyField(mv, priKeyField)) { 426 /* For a non-simple type, call EntityOutput.writeKeyObject. */ 427 mv.visitVarInsn(ALOAD, 1); 428 mv.visitVarInsn(ALOAD, 0); 429 mv.visitFieldInsn 430 (GETFIELD, className, priKeyField.name, 431 priKeyField.type.getDescriptor()); 432 mv.visitVarInsn(ALOAD, 2); 433 mv.visitMethodInsn 434 (INVOKEINTERFACE, 435 "com/sleepycat/persist/impl/EntityOutput", 436 "writeKeyObject", 437 "(Ljava/lang/Object;" + 438 "Lcom/sleepycat/persist/impl/Format;)V"); 439 } 440 } else if (hasPersistentSuperclass) { 441 mv.visitVarInsn(ALOAD, 0); 442 mv.visitVarInsn(ALOAD, 1); 443 mv.visitVarInsn(ALOAD, 2); 444 mv.visitMethodInsn 445 (INVOKESPECIAL, superclassName, "bdbWritePriKeyField", 446 "(Lcom/sleepycat/persist/impl/EntityOutput;" + 447 "Lcom/sleepycat/persist/impl/Format;)V"); 448 } 449 mv.visitInsn(RETURN); 450 mv.visitMaxs(3, 3); 451 mv.visitEnd(); 452 } 453 454 /** 455 * public void bdbReadPriKeyField(EntityInput input, Format format) { 456 * theField = (TheFieldClass) input.readKeyObject(format); 457 * // or 458 * theField = input.readInt(); // and other simple types 459 * // or if no primary key but has superclass: 460 * super.bdbReadPriKeyField(input, format); 461 * } 462 */ 463 private void genBdbReadPriKeyField() { 464 MethodVisitor mv = cv.visitMethod 465 (ACC_PUBLIC, "bdbReadPriKeyField", 466 "(Lcom/sleepycat/persist/impl/EntityInput;" + 467 "Lcom/sleepycat/persist/impl/Format;)V", 468 null, null); 469 mv.visitCode(); 470 if (priKeyField != null) { 471 if (!genReadSimpleKeyField(mv, priKeyField)) { 472 /* For a non-simple type, call EntityInput.readKeyObject. */ 473 mv.visitVarInsn(ALOAD, 0); 474 mv.visitVarInsn(ALOAD, 1); 475 mv.visitVarInsn(ALOAD, 2); 476 mv.visitMethodInsn 477 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 478 "readKeyObject", 479 "(Lcom/sleepycat/persist/impl/Format;)" + 480 "Ljava/lang/Object;"); 481 mv.visitTypeInsn(CHECKCAST, getTypeInstName(priKeyField.type)); 482 mv.visitFieldInsn 483 (PUTFIELD, className, priKeyField.name, 484 priKeyField.type.getDescriptor()); 485 } 486 } else if (hasPersistentSuperclass) { 487 mv.visitVarInsn(ALOAD, 0); 488 mv.visitVarInsn(ALOAD, 1); 489 mv.visitVarInsn(ALOAD, 2); 490 mv.visitMethodInsn 491 (INVOKESPECIAL, superclassName, "bdbReadPriKeyField", 492 "(Lcom/sleepycat/persist/impl/EntityInput;" + 493 "Lcom/sleepycat/persist/impl/Format;)V"); 494 } 495 mv.visitInsn(RETURN); 496 mv.visitMaxs(3, 3); 497 mv.visitEnd(); 498 } 499 500 /** 501 * public void bdbWriteSecKeyFields(EntityOutput output) { 502 * output.registerPriKeyObject(priKeyField); // if an object 503 * super.bdbWriteSecKeyFields(EntityOutput output); // if has super 504 * output.writeInt(secKeyField1); 505 * output.writeObject(secKeyField2, null); 506 * // etc 507 * } 508 */ 509 private void genBdbWriteSecKeyFields() { 510 MethodVisitor mv = cv.visitMethod 511 (ACC_PUBLIC, "bdbWriteSecKeyFields", 512 "(Lcom/sleepycat/persist/impl/EntityOutput;)V", null, null); 513 mv.visitCode(); 514 if (priKeyField != null && isRefType(priKeyField.type)) { 515 genRegisterPrimaryKey(mv, false); 516 } 517 if (hasPersistentSuperclass) { 518 mv.visitVarInsn(ALOAD, 0); 519 mv.visitVarInsn(ALOAD, 1); 520 mv.visitMethodInsn 521 (INVOKESPECIAL, superclassName, "bdbWriteSecKeyFields", 522 "(Lcom/sleepycat/persist/impl/EntityOutput;)V"); 523 } 524 for (FieldInfo field : secKeyFields) { 525 genWriteField(mv, field); 526 } 527 mv.visitInsn(RETURN); 528 mv.visitMaxs(2, 2); 529 mv.visitEnd(); 530 } 531 532 /** 533 * public void bdbReadSecKeyFields(EntityInput input, 534 * int startField, 535 * int endField, 536 * int superLevel) { 537 * input.registerPriKeyObject(priKeyField); // if an object 538 * // if has super: 539 * if (superLevel != 0) { 540 * super.bdbReadSecKeyFields(..., superLevel - 1); 541 * } 542 * if (superLevel <= 0) { 543 * switch (startField) { 544 * case 0: 545 * secKeyField1 = input.readInt(); 546 * if (endField == 0) break; 547 * case 1: 548 * secKeyField2 = (String) input.readObject(); 549 * if (endField == 1) break; 550 * case 2: 551 * secKeyField3 = input.readInt(); 552 * } 553 * } 554 * } 555 */ 556 private void genBdbReadSecKeyFields() { 557 MethodVisitor mv = cv.visitMethod 558 (ACC_PUBLIC, "bdbReadSecKeyFields", 559 "(Lcom/sleepycat/persist/impl/EntityInput;III)V", null, null); 560 mv.visitCode(); 561 if (priKeyField != null && isRefType(priKeyField.type)) { 562 genRegisterPrimaryKey(mv, true); 563 } 564 genReadSuperKeyFields(mv, true); 565 genReadFieldSwitch(mv, secKeyFields); 566 mv.visitInsn(RETURN); 567 mv.visitMaxs(5, 5); 568 mv.visitEnd(); 569 } 570 571 /** 572 * output.registerPriKeyObject(priKeyField); 573 * // or 574 * input.registerPriKeyObject(priKeyField); 575 */ 576 private void genRegisterPrimaryKey(MethodVisitor mv, boolean input) { 577 String entityInputOrOutputClass = 578 input ? "com/sleepycat/persist/impl/EntityInput" 579 : "com/sleepycat/persist/impl/EntityOutput"; 580 mv.visitVarInsn(ALOAD, 1); 581 mv.visitVarInsn(ALOAD, 0); 582 mv.visitFieldInsn 583 (GETFIELD, className, priKeyField.name, 584 priKeyField.type.getDescriptor()); 585 mv.visitMethodInsn 586 (INVOKEINTERFACE, entityInputOrOutputClass, "registerPriKeyObject", 587 "(Ljava/lang/Object;)V"); 588 } 589 590 /** 591 * public void bdbWriteNonKeyFields(EntityOutput output) { 592 * // like bdbWriteSecKeyFields but does not call registerPriKeyObject 593 * } 594 */ 595 private void genBdbWriteNonKeyFields() { 596 MethodVisitor mv = cv.visitMethod 597 (ACC_PUBLIC, "bdbWriteNonKeyFields", 598 "(Lcom/sleepycat/persist/impl/EntityOutput;)V", null, null); 599 mv.visitCode(); 600 if (!isCompositeKey) { 601 if (hasPersistentSuperclass) { 602 mv.visitVarInsn(ALOAD, 0); 603 mv.visitVarInsn(ALOAD, 1); 604 mv.visitMethodInsn 605 (INVOKESPECIAL, superclassName, "bdbWriteNonKeyFields", 606 "(Lcom/sleepycat/persist/impl/EntityOutput;)V"); 607 } 608 for (FieldInfo field : nonKeyFields) { 609 genWriteField(mv, field); 610 } 611 } 612 mv.visitInsn(RETURN); 613 mv.visitMaxs(2, 2); 614 mv.visitEnd(); 615 } 616 617 /** 618 * public void bdbReadNonKeyFields(EntityInput input, 619 * int startField, 620 * int endField, 621 * int superLevel) { 622 * // like bdbReadSecKeyFields but does not call registerPriKeyObject 623 * } 624 */ 625 private void genBdbReadNonKeyFields() { 626 MethodVisitor mv = cv.visitMethod 627 (ACC_PUBLIC, "bdbReadNonKeyFields", 628 "(Lcom/sleepycat/persist/impl/EntityInput;III)V", null, null); 629 mv.visitCode(); 630 if (!isCompositeKey) { 631 genReadSuperKeyFields(mv, false); 632 genReadFieldSwitch(mv, nonKeyFields); 633 } 634 mv.visitInsn(RETURN); 635 mv.visitMaxs(5, 5); 636 mv.visitEnd(); 637 } 638 639 /** 640 * public void bdbWriteCompositeKeyFields(EntityOutput output, 641 * Format[] formats) { 642 * output.writeInt(compositeKeyField1); 643 * output.writeKeyObject(compositeKeyField2, formats[1]); 644 * // etc 645 * } 646 */ 647 private void genBdbWriteCompositeKeyFields() { 648 MethodVisitor mv = cv.visitMethod 649 (ACC_PUBLIC, "bdbWriteCompositeKeyFields", 650 "(Lcom/sleepycat/persist/impl/EntityOutput;" + 651 "[Lcom/sleepycat/persist/impl/Format;)V", 652 null, null); 653 mv.visitCode(); 654 if (isCompositeKey) { 655 for (int i = 0; i < nonKeyFields.size(); i += 1) { 656 FieldInfo field = nonKeyFields.get(i); 657 if (!genWriteSimpleKeyField(mv, field)) { 658 /* For a non-simple type, call writeKeyObject. */ 659 mv.visitVarInsn(ALOAD, 1); 660 mv.visitVarInsn(ALOAD, 0); 661 mv.visitFieldInsn 662 (GETFIELD, className, field.name, 663 field.type.getDescriptor()); 664 mv.visitVarInsn(ALOAD, 2); 665 if (i <= Byte.MAX_VALUE) { 666 mv.visitIntInsn(BIPUSH, i); 667 } else { 668 mv.visitLdcInsn(new Integer(i)); 669 } 670 mv.visitInsn(AALOAD); 671 mv.visitMethodInsn 672 (INVOKEINTERFACE, 673 "com/sleepycat/persist/impl/EntityOutput", 674 "writeKeyObject", 675 "(Ljava/lang/Object;" + 676 "Lcom/sleepycat/persist/impl/Format;)V"); 677 } 678 } 679 } 680 mv.visitInsn(RETURN); 681 mv.visitMaxs(3, 3); 682 mv.visitEnd(); 683 } 684 685 /** 686 * public void bdbReadCompositeKeyFields(EntityInput input, 687 * Format[] formats) { 688 * compositeKeyField1 = input.readInt(); 689 * compositeKeyField2 = input.readKeyObject(formats[1]); 690 * } 691 */ 692 private void genBdbReadCompositeKeyFields() { 693 MethodVisitor mv = cv.visitMethod 694 (ACC_PUBLIC, "bdbReadCompositeKeyFields", 695 "(Lcom/sleepycat/persist/impl/EntityInput;" + 696 "[Lcom/sleepycat/persist/impl/Format;)V", 697 null, null); 698 mv.visitCode(); 699 if (isCompositeKey) { 700 for (int i = 0; i < nonKeyFields.size(); i += 1) { 701 FieldInfo field = nonKeyFields.get(i); 702 /* Ignore non-simple (illegal) types for composite key. */ 703 if (!genReadSimpleKeyField(mv, field)) { 704 /* For a non-simple type, call readKeyObject. */ 705 mv.visitVarInsn(ALOAD, 0); 706 mv.visitVarInsn(ALOAD, 1); 707 mv.visitVarInsn(ALOAD, 2); 708 if (i <= Byte.MAX_VALUE) { 709 mv.visitIntInsn(BIPUSH, i); 710 } else { 711 mv.visitLdcInsn(new Integer(i)); 712 } 713 mv.visitInsn(AALOAD); 714 mv.visitMethodInsn 715 (INVOKEINTERFACE, 716 "com/sleepycat/persist/impl/EntityInput", 717 "readKeyObject", 718 "(Lcom/sleepycat/persist/impl/Format;)" + 719 "Ljava/lang/Object;"); 720 mv.visitTypeInsn(CHECKCAST, getTypeInstName(field.type)); 721 mv.visitFieldInsn 722 (PUTFIELD, className, field.name, 723 field.type.getDescriptor()); 724 } 725 } 726 } 727 mv.visitInsn(RETURN); 728 mv.visitMaxs(5, 5); 729 mv.visitEnd(); 730 } 731 732 /** 733 * output.writeInt(field); // and other primitives 734 * // or 735 * output.writeObject(field, null); 736 */ 737 private void genWriteField(MethodVisitor mv, FieldInfo field) { 738 mv.visitVarInsn(ALOAD, 1); 739 mv.visitVarInsn(ALOAD, 0); 740 mv.visitFieldInsn 741 (GETFIELD, className, field.name, field.type.getDescriptor()); 742 int sort = field.type.getSort(); 743 if (sort == Type.OBJECT || sort == Type.ARRAY) { 744 mv.visitInsn(ACONST_NULL); 745 mv.visitMethodInsn 746 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 747 "writeObject", 748 "(Ljava/lang/Object;Lcom/sleepycat/persist/impl/Format;)V"); 749 } else { 750 genWritePrimitive(mv, sort); 751 } 752 } 753 754 /** 755 * Generates writing of a simple type key field, or returns false if the 756 * key field is not a simple type (i.e., it is a composite key type). 757 * 758 * output.writeInt(theField); // and other primitives 759 * // or 760 * output.writeInt(theField.intValue()); // and other simple types 761 * // or returns false 762 */ 763 private boolean genWriteSimpleKeyField(MethodVisitor mv, FieldInfo field) { 764 if (genWritePrimitiveField(mv, field)) { 765 return true; 766 } 767 String fieldClassName = field.type.getClassName(); 768 if (!isSimpleRefType(fieldClassName)) { 769 return false; 770 } 771 mv.visitVarInsn(ALOAD, 1); 772 mv.visitVarInsn(ALOAD, 0); 773 mv.visitFieldInsn 774 (GETFIELD, className, field.name, field.type.getDescriptor()); 775 Integer sort = PRIMITIVE_WRAPPERS.get(fieldClassName); 776 if (sort != null) { 777 genUnwrapPrimitive(mv, sort); 778 genWritePrimitive(mv, sort); 779 } else if (fieldClassName.equals(Date.class.getName())) { 780 mv.visitMethodInsn 781 (INVOKEVIRTUAL, "java/util/Date", "getTime", "()J"); 782 genWritePrimitive(mv, Type.LONG); 783 } else if (fieldClassName.equals(String.class.getName())) { 784 mv.visitMethodInsn 785 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 786 "writeString", 787 "(Ljava/lang/String;)Lcom/sleepycat/bind/tuple/TupleOutput;"); 788 mv.visitInsn(POP); 789 } else if (fieldClassName.equals(BigInteger.class.getName())) { 790 mv.visitMethodInsn 791 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 792 "writeBigInteger", 793 "(Ljava/math/BigInteger;)Lcom/sleepycat/bind/tuple/TupleOutput;"); 794 mv.visitInsn(POP); 795 } else { 796 throw new IllegalStateException(fieldClassName); 797 } 798 return true; 799 } 800 801 private boolean genWritePrimitiveField(MethodVisitor mv, FieldInfo field) { 802 int sort = field.type.getSort(); 803 if (sort == Type.OBJECT || sort == Type.ARRAY) { 804 return false; 805 } 806 mv.visitVarInsn(ALOAD, 1); 807 mv.visitVarInsn(ALOAD, 0); 808 mv.visitFieldInsn 809 (GETFIELD, className, field.name, field.type.getDescriptor()); 810 genWritePrimitive(mv, sort); 811 return true; 812 } 813 814 /** 815 * // if has super: 816 * if (superLevel != 0) { 817 * super.bdbReadXxxKeyFields(..., superLevel - 1); 818 * } 819 */ 820 private void genReadSuperKeyFields(MethodVisitor mv, 821 boolean areSecKeyFields) { 822 if (hasPersistentSuperclass) { 823 Label next = new Label(); 824 mv.visitVarInsn(ILOAD, 4); 825 mv.visitJumpInsn(IFEQ, next); 826 mv.visitVarInsn(ALOAD, 0); 827 mv.visitVarInsn(ALOAD, 1); 828 mv.visitVarInsn(ILOAD, 2); 829 mv.visitVarInsn(ILOAD, 3); 830 mv.visitVarInsn(ILOAD, 4); 831 mv.visitInsn(ICONST_1); 832 mv.visitInsn(ISUB); 833 String name = areSecKeyFields ? "bdbReadSecKeyFields" 834 : "bdbReadNonKeyFields"; 835 mv.visitMethodInsn 836 (INVOKESPECIAL, superclassName, name, 837 "(Lcom/sleepycat/persist/impl/EntityInput;III)V"); 838 mv.visitLabel(next); 839 } 840 } 841 842 /** 843 * public void bdbReadXxxKeyFields(EntityInput input, 844 * int startField, 845 * int endField, 846 * int superLevel) { 847 * // ... 848 * if (superLevel <= 0) { 849 * switch (startField) { 850 * case 0: 851 * keyField1 = input.readInt(); 852 * if (endField == 0) break; 853 * case 1: 854 * keyField2 = (String) input.readObject(); 855 * if (endField == 1) break; 856 * case 2: 857 * keyField3 = input.readInt(); 858 * } 859 * } 860 */ 861 private void genReadFieldSwitch(MethodVisitor mv, List<FieldInfo> fields) { 862 int nFields = fields.size(); 863 if (nFields > 0) { 864 mv.visitVarInsn(ILOAD, 4); 865 Label pastSwitch = new Label(); 866 mv.visitJumpInsn(IFGT, pastSwitch); 867 Label[] labels = new Label[nFields]; 868 for (int i = 0; i < nFields; i += 1) { 869 labels[i] = new Label(); 870 } 871 mv.visitVarInsn(ILOAD, 2); 872 mv.visitTableSwitchInsn(0, nFields - 1, pastSwitch, labels); 873 for (int i = 0; i < nFields; i += 1) { 874 FieldInfo field = fields.get(i); 875 mv.visitLabel(labels[i]); 876 genReadField(mv, field); 877 if (i < nFields - 1) { 878 Label nextCase = labels[i + 1]; 879 mv.visitVarInsn(ILOAD, 3); 880 if (i == 0) { 881 mv.visitJumpInsn(IFNE, nextCase); 882 } else { 883 switch (i) { 884 case 1: 885 mv.visitInsn(ICONST_1); 886 break; 887 case 2: 888 mv.visitInsn(ICONST_2); 889 break; 890 case 3: 891 mv.visitInsn(ICONST_3); 892 break; 893 case 4: 894 mv.visitInsn(ICONST_4); 895 break; 896 case 5: 897 mv.visitInsn(ICONST_5); 898 break; 899 default: 900 mv.visitIntInsn(BIPUSH, i); 901 } 902 mv.visitJumpInsn(IF_ICMPNE, nextCase); 903 } 904 mv.visitJumpInsn(GOTO, pastSwitch); 905 } 906 } 907 mv.visitLabel(pastSwitch); 908 } 909 } 910 911 /** 912 * field = input.readInt(); // and other primitives 913 * // or 914 * field = (FieldClass) input.readObject(); 915 */ 916 private void genReadField(MethodVisitor mv, FieldInfo field) { 917 mv.visitVarInsn(ALOAD, 0); 918 mv.visitVarInsn(ALOAD, 1); 919 if (isRefType(field.type)) { 920 mv.visitMethodInsn 921 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 922 "readObject", "()Ljava/lang/Object;"); 923 mv.visitTypeInsn(CHECKCAST, getTypeInstName(field.type)); 924 } else { 925 genReadPrimitive(mv, field.type.getSort()); 926 } 927 mv.visitFieldInsn 928 (PUTFIELD, className, field.name, field.type.getDescriptor()); 929 } 930 931 /** 932 * Generates reading of a simple type key field, or returns false if the 933 * key field is not a simple type (i.e., it is a composite key type). 934 * 935 * field = input.readInt(); // and other primitives 936 * // or 937 * field = Integer.valueOf(input.readInt()); // and other simple types 938 * // or returns false 939 */ 940 private boolean genReadSimpleKeyField(MethodVisitor mv, FieldInfo field) { 941 if (genReadPrimitiveField(mv, field)) { 942 return true; 943 } 944 String fieldClassName = field.type.getClassName(); 945 if (!isSimpleRefType(fieldClassName)) { 946 return false; 947 } 948 Integer sort = PRIMITIVE_WRAPPERS.get(fieldClassName); 949 if (sort != null) { 950 mv.visitVarInsn(ALOAD, 0); 951 mv.visitVarInsn(ALOAD, 1); 952 genReadPrimitive(mv, sort); 953 genWrapPrimitive(mv, sort); 954 } else if (fieldClassName.equals(Date.class.getName())) { 955 /* Date is a special case because we use NEW instead of valueOf. */ 956 mv.visitVarInsn(ALOAD, 0); 957 mv.visitTypeInsn(NEW, "java/util/Date"); 958 mv.visitInsn(DUP); 959 mv.visitVarInsn(ALOAD, 1); 960 genReadPrimitive(mv, Type.LONG); 961 mv.visitMethodInsn 962 (INVOKESPECIAL, "java/util/Date", "<init>", "(J)V"); 963 } else if (fieldClassName.equals(String.class.getName())) { 964 mv.visitVarInsn(ALOAD, 0); 965 mv.visitVarInsn(ALOAD, 1); 966 mv.visitMethodInsn 967 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 968 "readString", "()Ljava/lang/String;"); 969 } else if (fieldClassName.equals(BigInteger.class.getName())) { 970 mv.visitVarInsn(ALOAD, 0); 971 mv.visitVarInsn(ALOAD, 1); 972 mv.visitMethodInsn 973 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 974 "readBigInteger", "()Ljava/math/BigInteger;"); 975 } else { 976 throw new IllegalStateException(fieldClassName); 977 } 978 mv.visitFieldInsn 979 (PUTFIELD, className, field.name, field.type.getDescriptor()); 980 return true; 981 } 982 983 private boolean genReadPrimitiveField(MethodVisitor mv, FieldInfo field) { 984 int sort = field.type.getSort(); 985 if (sort == Type.OBJECT || sort == Type.ARRAY) { 986 return false; 987 } 988 mv.visitVarInsn(ALOAD, 0); 989 mv.visitVarInsn(ALOAD, 1); 990 genReadPrimitive(mv, sort); 991 mv.visitFieldInsn 992 (PUTFIELD, className, field.name, field.type.getDescriptor()); 993 return true; 994 } 995 996 /** 997 * public Object bdbGetField(Object o, 998 * int field, 999 * int superLevel, 1000 * boolean isSecField) { 1001 * if (superLevel > 0) { 1002 * // if has superclass: 1003 * return super.bdbGetField 1004 * (o, field, superLevel - 1, isSecField); 1005 * } else if (isSecField) { 1006 * switch (field) { 1007 * case 0: 1008 * return Integer.valueOf(f2); 1009 * case 1: 1010 * return f3; 1011 * case 2: 1012 * return f4; 1013 * } 1014 * } else { 1015 * switch (field) { 1016 * case 0: 1017 * return Integer.valueOf(f5); 1018 * case 1: 1019 * return f6; 1020 * case 2: 1021 * return f7; 1022 * } 1023 * } 1024 * return null; 1025 * } 1026 */ 1027 private void genBdbGetField() { 1028 MethodVisitor mv = cv.visitMethod 1029 (ACC_PUBLIC, "bdbGetField", 1030 "(Ljava/lang/Object;IIZ)Ljava/lang/Object;", null, null); 1031 mv.visitCode(); 1032 mv.visitVarInsn(ILOAD, 3); 1033 Label l0 = new Label(); 1034 mv.visitJumpInsn(IFLE, l0); 1035 Label l1 = new Label(); 1036 if (hasPersistentSuperclass) { 1037 mv.visitVarInsn(ALOAD, 0); 1038 mv.visitVarInsn(ALOAD, 1); 1039 mv.visitVarInsn(ILOAD, 2); 1040 mv.visitVarInsn(ILOAD, 3); 1041 mv.visitInsn(ICONST_1); 1042 mv.visitInsn(ISUB); 1043 mv.visitVarInsn(ILOAD, 4); 1044 mv.visitMethodInsn 1045 (INVOKESPECIAL, className, "bdbGetField", 1046 "(Ljava/lang/Object;IIZ)Ljava/lang/Object;"); 1047 mv.visitInsn(ARETURN); 1048 } else { 1049 mv.visitJumpInsn(GOTO, l1); 1050 } 1051 mv.visitLabel(l0); 1052 mv.visitVarInsn(ILOAD, 4); 1053 Label l2 = new Label(); 1054 mv.visitJumpInsn(IFEQ, l2); 1055 genGetFieldSwitch(mv, secKeyFields, l1); 1056 mv.visitLabel(l2); 1057 genGetFieldSwitch(mv, nonKeyFields, l1); 1058 mv.visitLabel(l1); 1059 mv.visitInsn(ACONST_NULL); 1060 mv.visitInsn(ARETURN); 1061 mv.visitMaxs(1, 5); 1062 mv.visitEnd(); 1063 } 1064 1065 /** 1066 * mv.visitVarInsn(ILOAD, 2); 1067 * Label l0 = new Label(); 1068 * Label l1 = new Label(); 1069 * Label l2 = new Label(); 1070 * mv.visitTableSwitchInsn(0, 2, TheDefLabel, new Label[] { l0, l1, l2 }); 1071 * mv.visitLabel(l0); 1072 * mv.visitVarInsn(ALOAD, 0); 1073 * mv.visitFieldInsn(GETFIELD, TheClassName, "f2", "I"); 1074 * mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", 1075 * "(I)Ljava/lang/Integer;"); 1076 * mv.visitInsn(ARETURN); 1077 * mv.visitLabel(l1); 1078 * mv.visitVarInsn(ALOAD, 0); 1079 * mv.visitFieldInsn(GETFIELD, TheClassName, "f3", "Ljava/lang/String;"); 1080 * mv.visitInsn(ARETURN); 1081 * mv.visitLabel(l2); 1082 * mv.visitVarInsn(ALOAD, 0); 1083 * mv.visitFieldInsn(GETFIELD, TheClassName, "f4", "Ljava/lang/String;"); 1084 * mv.visitInsn(ARETURN); 1085 */ 1086 private void genGetFieldSwitch(MethodVisitor mv, 1087 List<FieldInfo> fields, 1088 Label defaultLabel) { 1089 int nFields = fields.size(); 1090 if (nFields == 0) { 1091 mv.visitJumpInsn(GOTO, defaultLabel); 1092 return; 1093 } 1094 Label[] labels = new Label[nFields]; 1095 for (int i = 0; i < nFields; i += 1) { 1096 labels[i] = new Label(); 1097 } 1098 mv.visitVarInsn(ILOAD, 2); 1099 mv.visitTableSwitchInsn(0, nFields - 1, defaultLabel, labels); 1100 for (int i = 0; i < nFields; i += 1) { 1101 FieldInfo field = fields.get(i); 1102 mv.visitLabel(labels[i]); 1103 mv.visitVarInsn(ALOAD, 0); 1104 mv.visitFieldInsn 1105 (GETFIELD, className, field.name, field.type.getDescriptor()); 1106 if (!isRefType(field.type)) { 1107 genWrapPrimitive(mv, field.type.getSort()); 1108 } 1109 mv.visitInsn(ARETURN); 1110 } 1111 } 1112 1113 /** 1114 * public void bdbSetField(Object o, 1115 * int field, 1116 * int superLevel, 1117 * boolean isSecField, 1118 * Object value) { 1119 * if (superLevel > 0) { 1120 * // if has superclass: 1121 * super.bdbSetField 1122 * (o, field, superLevel - 1, isSecField, value); 1123 * } else if (isSecField) { 1124 * switch (field) { 1125 * case 0: 1126 * f2 = ((Integer) value).intValue(); 1127 * case 1: 1128 * f3 = (String) value; 1129 * case 2: 1130 * f4 = (String) value; 1131 * } 1132 * } else { 1133 * switch (field) { 1134 * case 0: 1135 * f5 = ((Integer) value).intValue(); 1136 * case 1: 1137 * f6 = (String) value; 1138 * case 2: 1139 * f7 = (String) value; 1140 * } 1141 * } 1142 * } 1143 */ 1144 private void genBdbSetField() { 1145 MethodVisitor mv = cv.visitMethod 1146 (ACC_PUBLIC, "bdbSetField", 1147 "(Ljava/lang/Object;IIZLjava/lang/Object;)V", null, null); 1148 mv.visitCode(); 1149 mv.visitVarInsn(ILOAD, 3); 1150 Label l0 = new Label(); 1151 mv.visitJumpInsn(IFLE, l0); 1152 if (hasPersistentSuperclass) { 1153 mv.visitVarInsn(ALOAD, 0); 1154 mv.visitVarInsn(ALOAD, 1); 1155 mv.visitVarInsn(ILOAD, 2); 1156 mv.visitVarInsn(ILOAD, 3); 1157 mv.visitInsn(ICONST_1); 1158 mv.visitInsn(ISUB); 1159 mv.visitVarInsn(ILOAD, 4); 1160 mv.visitVarInsn(ALOAD, 5); 1161 mv.visitMethodInsn 1162 (INVOKESPECIAL, className, "bdbSetField", 1163 "(Ljava/lang/Object;IIZLjava/lang/Object;)V"); 1164 } 1165 mv.visitInsn(RETURN); 1166 mv.visitLabel(l0); 1167 mv.visitVarInsn(ILOAD, 4); 1168 Label l2 = new Label(); 1169 mv.visitJumpInsn(IFEQ, l2); 1170 Label l1 = new Label(); 1171 genSetFieldSwitch(mv, secKeyFields, l1); 1172 mv.visitLabel(l2); 1173 genSetFieldSwitch(mv, nonKeyFields, l1); 1174 mv.visitLabel(l1); 1175 mv.visitInsn(RETURN); 1176 mv.visitMaxs(2, 6); 1177 mv.visitEnd(); 1178 } 1179 1180 /** 1181 * mv.visitVarInsn(ILOAD, 2); 1182 * Label l0 = new Label(); 1183 * Label l1 = new Label(); 1184 * Label l2 = new Label(); 1185 * mv.visitTableSwitchInsn(0, 2, TheDefLabel, new Label[] { l0, l1, l2 }); 1186 * mv.visitLabel(l0); 1187 * mv.visitVarInsn(ALOAD, 0); 1188 * mv.visitVarInsn(ALOAD, 5); 1189 * mv.visitTypeInsn(CHECKCAST, "java/lang/Integer"); 1190 * mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", 1191 * "()I"); 1192 * mv.visitFieldInsn(PUTFIELD, TheClassName, "f2", "I"); 1193 * mv.visitLabel(l1); 1194 * mv.visitVarInsn(ALOAD, 0); 1195 * mv.visitVarInsn(ALOAD, 5); 1196 * mv.visitTypeInsn(CHECKCAST, "java/lang/String"); 1197 * mv.visitFieldInsn(PUTFIELD, TheClassName, "f3", "Ljava/lang/String;"); 1198 * mv.visitLabel(l2); 1199 * mv.visitVarInsn(ALOAD, 0); 1200 * mv.visitVarInsn(ALOAD, 5); 1201 * mv.visitTypeInsn(CHECKCAST, "java/lang/String"); 1202 * mv.visitFieldInsn(PUTFIELD, TheClassName, "f4", "Ljava/lang/String;"); 1203 */ 1204 private void genSetFieldSwitch(MethodVisitor mv, 1205 List<FieldInfo> fields, 1206 Label defaultLabel) { 1207 int nFields = fields.size(); 1208 if (nFields == 0) { 1209 mv.visitJumpInsn(GOTO, defaultLabel); 1210 return; 1211 } 1212 Label[] labels = new Label[nFields]; 1213 for (int i = 0; i < nFields; i += 1) { 1214 labels[i] = new Label(); 1215 } 1216 mv.visitVarInsn(ILOAD, 2); 1217 mv.visitTableSwitchInsn(0, nFields - 1, defaultLabel, labels); 1218 for (int i = 0; i < nFields; i += 1) { 1219 FieldInfo field = fields.get(i); 1220 mv.visitLabel(labels[i]); 1221 mv.visitVarInsn(ALOAD, 0); 1222 mv.visitVarInsn(ALOAD, 5); 1223 if (isRefType(field.type)) { 1224 mv.visitTypeInsn(CHECKCAST, getTypeInstName(field.type)); 1225 } else { 1226 int sort = field.type.getSort(); 1227 mv.visitTypeInsn 1228 (CHECKCAST, 1229 getPrimitiveWrapperClass(sort).replace('.', '/')); 1230 genUnwrapPrimitive(mv, sort); 1231 } 1232 mv.visitFieldInsn 1233 (PUTFIELD, className, field.name, field.type.getDescriptor()); 1234 mv.visitInsn(RETURN); 1235 } 1236 } 1237 1238 private void genWritePrimitive(MethodVisitor mv, int sort) { 1239 switch (sort) { 1240 case Type.BOOLEAN: 1241 mv.visitMethodInsn 1242 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1243 "writeBoolean", "(Z)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1244 break; 1245 case Type.CHAR: 1246 mv.visitMethodInsn 1247 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1248 "writeChar", "(I)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1249 break; 1250 case Type.BYTE: 1251 mv.visitMethodInsn 1252 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1253 "writeByte", "(I)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1254 break; 1255 case Type.SHORT: 1256 mv.visitMethodInsn 1257 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1258 "writeShort", "(I)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1259 break; 1260 case Type.INT: 1261 mv.visitMethodInsn 1262 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1263 "writeInt", "(I)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1264 break; 1265 case Type.LONG: 1266 mv.visitMethodInsn 1267 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1268 "writeLong", "(J)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1269 break; 1270 case Type.FLOAT: 1271 mv.visitMethodInsn 1272 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1273 "writeSortedFloat", 1274 "(F)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1275 break; 1276 case Type.DOUBLE: 1277 mv.visitMethodInsn 1278 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityOutput", 1279 "writeSortedDouble", 1280 "(D)Lcom/sleepycat/bind/tuple/TupleOutput;"); 1281 break; 1282 default: 1283 throw new IllegalStateException(String.valueOf(sort)); 1284 } 1285 /* The write methods always return 'this' and we always discard it. */ 1286 mv.visitInsn(POP); 1287 } 1288 1289 private void genReadPrimitive(MethodVisitor mv, int sort) { 1290 switch (sort) { 1291 case Type.BOOLEAN: 1292 mv.visitMethodInsn 1293 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1294 "readBoolean", "()Z"); 1295 break; 1296 case Type.CHAR: 1297 mv.visitMethodInsn 1298 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1299 "readChar", "()C"); 1300 break; 1301 case Type.BYTE: 1302 mv.visitMethodInsn 1303 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1304 "readByte", "()B"); 1305 break; 1306 case Type.SHORT: 1307 mv.visitMethodInsn 1308 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1309 "readShort", "()S"); 1310 break; 1311 case Type.INT: 1312 mv.visitMethodInsn 1313 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1314 "readInt", "()I"); 1315 break; 1316 case Type.LONG: 1317 mv.visitMethodInsn 1318 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1319 "readLong", "()J"); 1320 break; 1321 case Type.FLOAT: 1322 mv.visitMethodInsn 1323 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1324 "readSortedFloat", "()F"); 1325 break; 1326 case Type.DOUBLE: 1327 mv.visitMethodInsn 1328 (INVOKEINTERFACE, "com/sleepycat/persist/impl/EntityInput", 1329 "readSortedDouble", "()D"); 1330 break; 1331 default: 1332 throw new IllegalStateException(String.valueOf(sort)); 1333 } 1334 } 1335 1336 private void genWrapPrimitive(MethodVisitor mv, int sort) { 1337 switch (sort) { 1338 case Type.BOOLEAN: 1339 mv.visitMethodInsn 1340 (INVOKESTATIC, "java/lang/Boolean", "valueOf", 1341 "(Z)Ljava/lang/Boolean;"); 1342 break; 1343 case Type.CHAR: 1344 mv.visitMethodInsn 1345 (INVOKESTATIC, "java/lang/Character", "valueOf", 1346 "(C)Ljava/lang/Character;"); 1347 break; 1348 case Type.BYTE: 1349 mv.visitMethodInsn 1350 (INVOKESTATIC, "java/lang/Byte", "valueOf", 1351 "(B)Ljava/lang/Byte;"); 1352 break; 1353 case Type.SHORT: 1354 mv.visitMethodInsn 1355 (INVOKESTATIC, "java/lang/Short", "valueOf", 1356 "(S)Ljava/lang/Short;"); 1357 break; 1358 case Type.INT: 1359 mv.visitMethodInsn 1360 (INVOKESTATIC, "java/lang/Integer", "valueOf", 1361 "(I)Ljava/lang/Integer;"); 1362 break; 1363 case Type.LONG: 1364 mv.visitMethodInsn 1365 (INVOKESTATIC, "java/lang/Long", "valueOf", 1366 "(J)Ljava/lang/Long;"); 1367 break; 1368 case Type.FLOAT: 1369 mv.visitMethodInsn 1370 (INVOKESTATIC, "java/lang/Float", "valueOf", 1371 "(F)Ljava/lang/Float;"); 1372 break; 1373 case Type.DOUBLE: 1374 mv.visitMethodInsn 1375 (INVOKESTATIC, "java/lang/Double", "valueOf", 1376 "(D)Ljava/lang/Double;"); 1377 break; 1378 default: 1379 throw new IllegalStateException(String.valueOf(sort)); 1380 } 1381 } 1382 1383 private void genUnwrapPrimitive(MethodVisitor mv, int sort) { 1384 switch (sort) { 1385 case Type.BOOLEAN: 1386 mv.visitMethodInsn 1387 (INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z"); 1388 break; 1389 case Type.CHAR: 1390 mv.visitMethodInsn 1391 (INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C"); 1392 break; 1393 case Type.BYTE: 1394 mv.visitMethodInsn 1395 (INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B"); 1396 break; 1397 case Type.SHORT: 1398 mv.visitMethodInsn 1399 (INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S"); 1400 break; 1401 case Type.INT: 1402 mv.visitMethodInsn 1403 (INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I"); 1404 break; 1405 case Type.LONG: 1406 mv.visitMethodInsn 1407 (INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J"); 1408 break; 1409 case Type.FLOAT: 1410 mv.visitMethodInsn 1411 (INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F"); 1412 break; 1413 case Type.DOUBLE: 1414 mv.visitMethodInsn 1415 (INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D"); 1416 break; 1417 default: 1418 throw new IllegalStateException(String.valueOf(sort)); 1419 } 1420 } 1421 1422 /** 1423 * Returns the type name for a visitTypeInsn operand, which is the internal 1424 * name for an object type and the descriptor for an array type. Must not 1425 * be called for a non-reference type. 1426 */ 1427 private static String getTypeInstName(Type type) { 1428 if (type.getSort() == Type.OBJECT) { 1429 return type.getInternalName(); 1430 } else if (type.getSort() == Type.ARRAY) { 1431 return type.getDescriptor(); 1432 } else { 1433 throw new IllegalStateException(); 1434 } 1435 } 1436 1437 /** 1438 * Call this method before comparing a non-reference operand to zero as an 1439 * int, for example, with IFNE, IFEQ, IFLT, etc. If the operand is a long, 1440 * float or double, this method will compare it to zero and leave the 1441 * result as an int operand. 1442 */ 1443 private static void genBeforeCompareToZero(MethodVisitor mv, Type type) { 1444 switch (type.getSort()) { 1445 case Type.LONG: 1446 mv.visitInsn(LCONST_0); 1447 mv.visitInsn(LCMP); 1448 break; 1449 case Type.FLOAT: 1450 mv.visitInsn(FCONST_0); 1451 mv.visitInsn(FCMPL); 1452 break; 1453 case Type.DOUBLE: 1454 mv.visitInsn(DCONST_0); 1455 mv.visitInsn(DCMPL); 1456 break; 1457 } 1458 } 1459 1460 /** 1461 * Returns true if the given class is a primitive wrapper, Date or String. 1462 */ 1463 static boolean isSimpleRefType(String className) { 1464 return (PRIMITIVE_WRAPPERS.containsKey(className) || 1465 className.equals(BigInteger.class.getName()) || 1466 className.equals(Date.class.getName()) || 1467 className.equals(String.class.getName())); 1468 } 1469 1470 /** 1471 * Returns the wrapper class for a primitive. 1472 */ 1473 static String getPrimitiveWrapperClass(int primitiveSort) { 1474 for (Map.Entry<String,Integer> entry : PRIMITIVE_WRAPPERS.entrySet()) { 1475 if (entry.getValue() == primitiveSort) { 1476 return entry.getKey(); 1477 } 1478 } 1479 throw new IllegalStateException(String.valueOf(primitiveSort)); 1480 } 1481 1482 /** 1483 * Returns true if the given type is an object or array. 1484 */ 1485 private static boolean isRefType(Type type) { 1486 int sort = type.getSort(); 1487 return (sort == Type.OBJECT || sort == Type.ARRAY); 1488 } 1489 1490 /** 1491 * Returns whether a string array contains a given string. 1492 */ 1493 private static boolean containsString(String[] a, String s) { 1494 if (a != null) { 1495 for (String t : a) { 1496 if (s.equals(t)) { 1497 return true; 1498 } 1499 } 1500 } 1501 return false; 1502 } 1503 1504 /** 1505 * Appends a string to a string array. 1506 */ 1507 private static String[] appendString(String[] a, String s) { 1508 if (a != null) { 1509 int len = a.length; 1510 String[] a2 = new String[len + 1]; 1511 System.arraycopy(a, 0, a2, 0, len); 1512 a2[len] = s; 1513 return a2; 1514 } else { 1515 return new String[] { s }; 1516 } 1517 } 1518 1519 /** 1520 * Aborts the enhancement process when we determine that enhancement is 1521 * unnecessary or not possible. 1522 */ 1523 private NotPersistentException abort() { 1524 return NOT_PERSISTENT; 1525 } 1526 1527 private static class FieldInfo implements FieldVisitor { 1528 1529 FieldVisitor parent; 1530 String name; 1531 Type type; 1532 OrderInfo order; 1533 boolean isPriKey; 1534 boolean isSecKey; 1535 boolean isTransient; 1536 1537 FieldInfo(FieldVisitor parent, 1538 String name, 1539 String desc, 1540 boolean isTransient) { 1541 this.parent = parent; 1542 this.name = name; 1543 this.isTransient = isTransient; 1544 type = Type.getType(desc); 1545 } 1546 1547 public AnnotationVisitor visitAnnotation(String desc, 1548 boolean visible) { 1549 AnnotationVisitor ret = parent.visitAnnotation(desc, visible); 1550 if (desc.equals 1551 ("Lcom/sleepycat/persist/model/KeyField;")) { 1552 order = new OrderInfo(ret); 1553 ret = order; 1554 } else if (desc.equals 1555 ("Lcom/sleepycat/persist/model/PrimaryKey;")) { 1556 isPriKey = true; 1557 } else if (desc.equals 1558 ("Lcom/sleepycat/persist/model/SecondaryKey;")) { 1559 isSecKey = true; 1560 } else if (desc.equals 1561 ("Lcom/sleepycat/persist/model/NotPersistent;")) { 1562 isTransient = true; 1563 } else if (desc.equals 1564 ("Lcom/sleepycat/persist/model/NotTransient;")) { 1565 isTransient = false; 1566 } 1567 return ret; 1568 } 1569 1570 public void visitAttribute(Attribute attr) { 1571 parent.visitAttribute(attr); 1572 } 1573 1574 public void visitEnd() { 1575 parent.visitEnd(); 1576 } 1577 1578 @Override 1579 public String toString() { 1580 String label; 1581 if (isPriKey) { 1582 label = "PrimaryKey"; 1583 } else if (isSecKey) { 1584 label = "SecondaryKey"; 1585 } else if (order != null) { 1586 label = "CompositeKeyField " + order.value; 1587 } else { 1588 label = "NonKeyField"; 1589 } 1590 return "[" + label + ' ' + name + ' ' + type + ']'; 1591 } 1592 } 1593 1594 private static class OrderInfo extends AnnotationInfo { 1595 1596 int value; 1597 1598 OrderInfo(AnnotationVisitor parent) { 1599 super(parent); 1600 } 1601 1602 @Override 1603 public void visit(String name, Object value) { 1604 if (name.equals("value")) { 1605 this.value = (Integer) value; 1606 } 1607 parent.visit(name, value); 1608 } 1609 } 1610 1611 private static abstract class AnnotationInfo implements AnnotationVisitor { 1612 1613 AnnotationVisitor parent; 1614 1615 AnnotationInfo(AnnotationVisitor parent) { 1616 this.parent = parent; 1617 } 1618 1619 public void visit(String name, Object value) { 1620 parent.visit(name, value); 1621 } 1622 1623 public AnnotationVisitor visitAnnotation(String name, String desc) { 1624 return parent.visitAnnotation(name, desc); 1625 } 1626 1627 public AnnotationVisitor visitArray(String name) { 1628 return parent.visitArray(name); 1629 } 1630 1631 public void visitEnum(String name, String desc, String value) { 1632 parent.visitEnum(name, desc, value); 1633 } 1634 1635 public void visitEnd() { 1636 parent.visitEnd(); 1637 } 1638 } 1639} 1640