KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sleepycat > persist > model > BytecodeEnhancer


1 /*-
2  * See the file LICENSE for redistribution information.
3  *
4  * Copyright (c) 2002,2006 Oracle. All rights reserved.
5  *
6  * $Id: BytecodeEnhancer.java,v 1.11 2006/11/14 23:30:50 mark Exp $
7  */

8
9 package com.sleepycat.persist.model;
10
11 import static com.sleepycat.asm.Opcodes.ACC_ABSTRACT;
12 import static com.sleepycat.asm.Opcodes.ACC_PRIVATE;
13 import static com.sleepycat.asm.Opcodes.ACC_PUBLIC;
14 import static com.sleepycat.asm.Opcodes.ACC_STATIC;
15 import static com.sleepycat.asm.Opcodes.ACC_TRANSIENT;
16 import static com.sleepycat.asm.Opcodes.ACONST_NULL;
17 import static com.sleepycat.asm.Opcodes.ALOAD;
18 import static com.sleepycat.asm.Opcodes.ANEWARRAY;
19 import static com.sleepycat.asm.Opcodes.ARETURN;
20 import static com.sleepycat.asm.Opcodes.BIPUSH;
21 import static com.sleepycat.asm.Opcodes.CHECKCAST;
22 import static com.sleepycat.asm.Opcodes.DCMPL;
23 import static com.sleepycat.asm.Opcodes.DCONST_0;
24 import static com.sleepycat.asm.Opcodes.DUP;
25 import static com.sleepycat.asm.Opcodes.FCMPL;
26 import static com.sleepycat.asm.Opcodes.FCONST_0;
27 import static com.sleepycat.asm.Opcodes.GETFIELD;
28 import static com.sleepycat.asm.Opcodes.GOTO;
29 import static com.sleepycat.asm.Opcodes.ICONST_0;
30 import static com.sleepycat.asm.Opcodes.ICONST_1;
31 import static com.sleepycat.asm.Opcodes.ICONST_2;
32 import static com.sleepycat.asm.Opcodes.ICONST_3;
33 import static com.sleepycat.asm.Opcodes.ICONST_4;
34 import static com.sleepycat.asm.Opcodes.ICONST_5;
35 import static com.sleepycat.asm.Opcodes.IFEQ;
36 import static com.sleepycat.asm.Opcodes.IFGT;
37 import static com.sleepycat.asm.Opcodes.IFLE;
38 import static com.sleepycat.asm.Opcodes.IFNE;
39 import static com.sleepycat.asm.Opcodes.IFNONNULL;
40 import static com.sleepycat.asm.Opcodes.IF_ICMPNE;
41 import static com.sleepycat.asm.Opcodes.ILOAD;
42 import static com.sleepycat.asm.Opcodes.INVOKEINTERFACE;
43 import static com.sleepycat.asm.Opcodes.INVOKESPECIAL;
44 import static com.sleepycat.asm.Opcodes.INVOKESTATIC;
45 import static com.sleepycat.asm.Opcodes.INVOKEVIRTUAL;
46 import static com.sleepycat.asm.Opcodes.IRETURN;
47 import static com.sleepycat.asm.Opcodes.ISUB;
48 import static com.sleepycat.asm.Opcodes.LCMP;
49 import static com.sleepycat.asm.Opcodes.LCONST_0;
50 import static com.sleepycat.asm.Opcodes.NEW;
51 import static com.sleepycat.asm.Opcodes.POP;
52 import static com.sleepycat.asm.Opcodes.PUTFIELD;
53 import static com.sleepycat.asm.Opcodes.RETURN;
54
55 import java.math.BigInteger JavaDoc;
56 import java.util.ArrayList JavaDoc;
57 import java.util.Collections JavaDoc;
58 import java.util.Comparator JavaDoc;
59 import java.util.Date JavaDoc;
60 import java.util.HashMap JavaDoc;
61 import java.util.List JavaDoc;
62 import java.util.Map JavaDoc;
63
64 import com.sleepycat.asm.AnnotationVisitor;
65 import com.sleepycat.asm.Attribute;
66 import com.sleepycat.asm.ClassAdapter;
67 import com.sleepycat.asm.ClassVisitor;
68 import com.sleepycat.asm.FieldVisitor;
69 import com.sleepycat.asm.Label;
70 import com.sleepycat.asm.MethodVisitor;
71 import 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  */

89 class BytecodeEnhancer extends ClassAdapter {
90
91     /** Thrown when we determine that a class is not persistent. */
92     static class NotPersistentException extends RuntimeException JavaDoc {}
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 JavaDoc<String JavaDoc,Integer JavaDoc> PRIMITIVE_WRAPPERS =
99         new HashMap JavaDoc<String JavaDoc,Integer JavaDoc>();
100     static {
101         PRIMITIVE_WRAPPERS.put(Boolean JavaDoc.class.getName(), Type.BOOLEAN);
102         PRIMITIVE_WRAPPERS.put(Character JavaDoc.class.getName(), Type.CHAR);
103         PRIMITIVE_WRAPPERS.put(Byte JavaDoc.class.getName(), Type.BYTE);
104         PRIMITIVE_WRAPPERS.put(Short JavaDoc.class.getName(), Type.SHORT);
105         PRIMITIVE_WRAPPERS.put(Integer JavaDoc.class.getName(), Type.INT);
106         PRIMITIVE_WRAPPERS.put(Long JavaDoc.class.getName(), Type.LONG);
107         PRIMITIVE_WRAPPERS.put(Float JavaDoc.class.getName(), Type.FLOAT);
108         PRIMITIVE_WRAPPERS.put(Double JavaDoc.class.getName(), Type.DOUBLE);
109     }
110
111     private String JavaDoc className;
112     private String JavaDoc 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 JavaDoc<FieldInfo> secKeyFields;
120     private List JavaDoc<FieldInfo> nonKeyFields;
121     private String JavaDoc staticBlockMethod;
122
123     BytecodeEnhancer(ClassVisitor parentVisitor) {
124         super(parentVisitor);
125         secKeyFields = new ArrayList JavaDoc<FieldInfo>();
126         nonKeyFields = new ArrayList JavaDoc<FieldInfo>();
127     }
128
129     @Override JavaDoc
130     public void visit(int version,
131                       int access,
132                       String JavaDoc name,
133                       String JavaDoc sig,
134                       String JavaDoc superName,
135                       String JavaDoc[] interfaces) {
136         className = name;
137         superclassName = superName;
138         final String JavaDoc 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 JavaDoc
150     public void visitSource(String JavaDoc source, String JavaDoc debug) {
151         super.visitSource(source, debug);
152     }
153
154     @Override JavaDoc
155     public AnnotationVisitor visitAnnotation(String JavaDoc 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 JavaDoc
164     public FieldVisitor visitField(int access,
165                                    String JavaDoc name,
166                                    String JavaDoc desc,
167                                    String JavaDoc sig,
168                                    Object JavaDoc 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 JavaDoc
182     public MethodVisitor visitMethod(int access,
183                                      String JavaDoc name,
184                                      String JavaDoc desc,
185                                      String JavaDoc sig,
186                                      String JavaDoc[] 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 JavaDoc();
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 JavaDoc
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 JavaDoc<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 JavaDoc<FieldInfo> cmp = new Comparator JavaDoc<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 JavaDoc 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 JavaDoc 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 JavaDoc sort = PRIMITIVE_WRAPPERS.get(fieldClassName);
696         if (sort != null) {
697             genUnwrapPrimitive(mv, sort);
698             genWritePrimitive(mv, sort);
699         } else if (fieldClassName.equals(Date JavaDoc.class.getName())) {
700             mv.visitMethodInsn
701                 (INVOKEVIRTUAL, "java/util/Date", "getTime", "()J");
702             genWritePrimitive(mv, Type.LONG);
703         } else if (fieldClassName.equals(String JavaDoc.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 JavaDoc.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 JavaDoc(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 JavaDoc 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 JavaDoc<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 JavaDoc fieldClassName = field.type.getClassName();
865         if (!isSimpleRefType(fieldClassName)) {
866             return false;
867         }
868         Integer JavaDoc 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 JavaDoc.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 JavaDoc.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 JavaDoc.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 JavaDoc(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 JavaDoc<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 JavaDoc<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 JavaDoc(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 JavaDoc(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 JavaDoc(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 JavaDoc(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 JavaDoc 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 JavaDoc();
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 JavaDoc className) {
1384        return (PRIMITIVE_WRAPPERS.containsKey(className) ||
1385                className.equals(BigInteger JavaDoc.class.getName()) ||
1386                className.equals(Date JavaDoc.class.getName()) ||
1387                className.equals(String JavaDoc.class.getName()));
1388    }
1389
1390    /**
1391     * Returns the wrapper class for a primitive.
1392     */

1393    static String JavaDoc getPrimitiveWrapperClass(int primitiveSort) {
1394        for (Map.Entry JavaDoc<String JavaDoc,Integer JavaDoc> entry : PRIMITIVE_WRAPPERS.entrySet()) {
1395            if (entry.getValue() == primitiveSort) {
1396                return entry.getKey();
1397            }
1398        }
1399        throw new IllegalStateException JavaDoc(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 JavaDoc[] a, String JavaDoc s) {
1414        if (a != null) {
1415            for (String JavaDoc 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 JavaDoc[] appendString(String JavaDoc[] a, String JavaDoc s) {
1428        if (a != null) {
1429            int len = a.length;
1430            String JavaDoc[] a2 = new String JavaDoc[len + 1];
1431            System.arraycopy(a, 0, a2, 0, len);
1432            a2[len] = s;
1433            return a2;
1434        } else {
1435            return new String JavaDoc[] { 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 JavaDoc name;
1451        Type type;
1452        OrderInfo order;
1453        boolean isPriKey;
1454        boolean isSecKey;
1455
1456        FieldInfo(FieldVisitor parent, String JavaDoc name, String JavaDoc desc) {
1457            this.parent = parent;
1458            this.name = name;
1459            type = Type.getType(desc);
1460        }
1461        
1462        public AnnotationVisitor visitAnnotation(String JavaDoc 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 JavaDoc
1488        public String JavaDoc toString() {
1489            String JavaDoc 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 JavaDoc
1512        public void visit(String JavaDoc name, Object JavaDoc value) {
1513            if (name.equals("value")) {
1514                this.value = (Integer JavaDoc) 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 JavaDoc name, Object JavaDoc value) {
1529            parent.visit(name, value);
1530        }
1531
1532        public AnnotationVisitor visitAnnotation(String JavaDoc name, String JavaDoc desc) {
1533            return parent.visitAnnotation(name, desc);
1534        }
1535
1536        public AnnotationVisitor visitArray(String JavaDoc name) {
1537            return parent.visitArray(name);
1538        }
1539
1540        public void visitEnum(String JavaDoc name, String JavaDoc desc, String JavaDoc value) {
1541            parent.visitEnum(name, desc, value);
1542        }
1543
1544        public void visitEnd() {
1545            parent.visitEnd();
1546        }
1547    }
1548}
1549
Popular Tags