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