0001: /*-
0002: * See the file LICENSE for redistribution information.
0003: *
0004: * Copyright (c) 2002,2008 Oracle. All rights reserved.
0005: *
0006: * $Id: BytecodeEnhancer.java,v 1.11.2.3 2008/01/07 15:14:20 cwl Exp $
0007: */
0008:
0009: package com.sleepycat.persist.model;
0010:
0011: import static com.sleepycat.asm.Opcodes.ACC_ABSTRACT;
0012: import static com.sleepycat.asm.Opcodes.ACC_PRIVATE;
0013: import static com.sleepycat.asm.Opcodes.ACC_PUBLIC;
0014: import static com.sleepycat.asm.Opcodes.ACC_STATIC;
0015: import static com.sleepycat.asm.Opcodes.ACC_TRANSIENT;
0016: import static com.sleepycat.asm.Opcodes.ACONST_NULL;
0017: import static com.sleepycat.asm.Opcodes.ALOAD;
0018: import static com.sleepycat.asm.Opcodes.ANEWARRAY;
0019: import static com.sleepycat.asm.Opcodes.ARETURN;
0020: import static com.sleepycat.asm.Opcodes.BIPUSH;
0021: import static com.sleepycat.asm.Opcodes.CHECKCAST;
0022: import static com.sleepycat.asm.Opcodes.DCMPL;
0023: import static com.sleepycat.asm.Opcodes.DCONST_0;
0024: import static com.sleepycat.asm.Opcodes.DUP;
0025: import static com.sleepycat.asm.Opcodes.FCMPL;
0026: import static com.sleepycat.asm.Opcodes.FCONST_0;
0027: import static com.sleepycat.asm.Opcodes.GETFIELD;
0028: import static com.sleepycat.asm.Opcodes.GOTO;
0029: import static com.sleepycat.asm.Opcodes.ICONST_0;
0030: import static com.sleepycat.asm.Opcodes.ICONST_1;
0031: import static com.sleepycat.asm.Opcodes.ICONST_2;
0032: import static com.sleepycat.asm.Opcodes.ICONST_3;
0033: import static com.sleepycat.asm.Opcodes.ICONST_4;
0034: import static com.sleepycat.asm.Opcodes.ICONST_5;
0035: import static com.sleepycat.asm.Opcodes.IFEQ;
0036: import static com.sleepycat.asm.Opcodes.IFGT;
0037: import static com.sleepycat.asm.Opcodes.IFLE;
0038: import static com.sleepycat.asm.Opcodes.IFNE;
0039: import static com.sleepycat.asm.Opcodes.IFNONNULL;
0040: import static com.sleepycat.asm.Opcodes.IF_ICMPNE;
0041: import static com.sleepycat.asm.Opcodes.ILOAD;
0042: import static com.sleepycat.asm.Opcodes.INVOKEINTERFACE;
0043: import static com.sleepycat.asm.Opcodes.INVOKESPECIAL;
0044: import static com.sleepycat.asm.Opcodes.INVOKESTATIC;
0045: import static com.sleepycat.asm.Opcodes.INVOKEVIRTUAL;
0046: import static com.sleepycat.asm.Opcodes.IRETURN;
0047: import static com.sleepycat.asm.Opcodes.ISUB;
0048: import static com.sleepycat.asm.Opcodes.LCMP;
0049: import static com.sleepycat.asm.Opcodes.LCONST_0;
0050: import static com.sleepycat.asm.Opcodes.NEW;
0051: import static com.sleepycat.asm.Opcodes.POP;
0052: import static com.sleepycat.asm.Opcodes.PUTFIELD;
0053: import static com.sleepycat.asm.Opcodes.RETURN;
0054:
0055: import java.math.BigInteger;
0056: import java.util.ArrayList;
0057: import java.util.Collections;
0058: import java.util.Comparator;
0059: import java.util.Date;
0060: import java.util.HashMap;
0061: import java.util.List;
0062: import java.util.Map;
0063:
0064: import com.sleepycat.asm.AnnotationVisitor;
0065: import com.sleepycat.asm.Attribute;
0066: import com.sleepycat.asm.ClassAdapter;
0067: import com.sleepycat.asm.ClassVisitor;
0068: import com.sleepycat.asm.FieldVisitor;
0069: import com.sleepycat.asm.Label;
0070: import com.sleepycat.asm.MethodVisitor;
0071: import com.sleepycat.asm.Type;
0072:
0073: /**
0074: * An ASM ClassVisitor that examines a class, throws NotPersistentException if
0075: * it is not persistent, or enhances it if it is persistent. A class is
0076: * persistent if it contains the @Entity or @Persistent annotations. A
0077: * resulting enhanced class implements the com.sleepycat.persist.impl.Enhanced
0078: * interface.
0079: *
0080: * <p>NotPersistentException is thrown to abort the transformation in order to
0081: * avoid making two passes over the class file (one to look for the annotations
0082: * and another to enhance the bytecode) or outputing a class that isn't
0083: * enhanced. By aborting the transformation as soon as we detect that the
0084: * annotations are missing, we make only one partial pass for a non-persistent
0085: * class.</p>
0086: *
0087: * @author Mark Hayes
0088: */
0089: class BytecodeEnhancer extends ClassAdapter {
0090:
0091: /** Thrown when we determine that a class is not persistent. */
0092: static class NotPersistentException extends RuntimeException {
0093: }
0094:
0095: /** A static instance is used to avoid fillInStaceTrace overhead. */
0096: private static final NotPersistentException NOT_PERSISTENT = new NotPersistentException();
0097:
0098: private static final Map<String, Integer> PRIMITIVE_WRAPPERS = new HashMap<String, Integer>();
0099: static {
0100: PRIMITIVE_WRAPPERS.put(Boolean.class.getName(), Type.BOOLEAN);
0101: PRIMITIVE_WRAPPERS.put(Character.class.getName(), Type.CHAR);
0102: PRIMITIVE_WRAPPERS.put(Byte.class.getName(), Type.BYTE);
0103: PRIMITIVE_WRAPPERS.put(Short.class.getName(), Type.SHORT);
0104: PRIMITIVE_WRAPPERS.put(Integer.class.getName(), Type.INT);
0105: PRIMITIVE_WRAPPERS.put(Long.class.getName(), Type.LONG);
0106: PRIMITIVE_WRAPPERS.put(Float.class.getName(), Type.FLOAT);
0107: PRIMITIVE_WRAPPERS.put(Double.class.getName(), Type.DOUBLE);
0108: }
0109:
0110: private String className;
0111: private String super className;
0112: private boolean isPersistent;
0113: private boolean isAbstract;
0114: private boolean hasDefaultConstructor;
0115: private boolean hasPersistentSuperclass;
0116: private boolean isCompositeKey;
0117: private FieldInfo priKeyField;
0118: private List<FieldInfo> secKeyFields;
0119: private List<FieldInfo> nonKeyFields;
0120: private String staticBlockMethod;
0121:
0122: BytecodeEnhancer(ClassVisitor parentVisitor) {
0123: super (parentVisitor);
0124: secKeyFields = new ArrayList<FieldInfo>();
0125: nonKeyFields = new ArrayList<FieldInfo>();
0126: }
0127:
0128: @Override
0129: public void visit(int version, int access, String name, String sig,
0130: String super Name, String[] interfaces) {
0131: className = name;
0132: super className = super Name;
0133: final String ENHANCED = "com/sleepycat/persist/impl/Enhanced";
0134: if (containsString(interfaces, ENHANCED)) {
0135: throw abort();
0136: }
0137: interfaces = appendString(interfaces, ENHANCED);
0138: isAbstract = ((access & ACC_ABSTRACT) != 0);
0139: hasPersistentSuperclass = (super Name != null && !super Name
0140: .equals("java/lang/Object"));
0141: super .visit(version, access, name, sig, super Name, interfaces);
0142: }
0143:
0144: @Override
0145: public void visitSource(String source, String debug) {
0146: super .visitSource(source, debug);
0147: }
0148:
0149: @Override
0150: public AnnotationVisitor visitAnnotation(String desc,
0151: boolean visible) {
0152: if (desc.equals("Lcom/sleepycat/persist/model/Entity;")
0153: || desc
0154: .equals("Lcom/sleepycat/persist/model/Persistent;")) {
0155: isPersistent = true;
0156: }
0157: return super .visitAnnotation(desc, visible);
0158: }
0159:
0160: @Override
0161: public FieldVisitor visitField(int access, String name,
0162: String desc, String sig, Object value) {
0163: if (!isPersistent) {
0164: throw abort();
0165: }
0166: FieldVisitor ret = super .visitField(access, name, desc, sig,
0167: value);
0168: if ((access & (ACC_STATIC | ACC_TRANSIENT)) == 0) {
0169: FieldInfo info = new FieldInfo(ret, name, desc);
0170: nonKeyFields.add(info);
0171: ret = info;
0172: }
0173: return ret;
0174: }
0175:
0176: @Override
0177: public MethodVisitor visitMethod(int access, String name,
0178: String desc, String sig, String[] exceptions) {
0179: if (!isPersistent) {
0180: throw abort();
0181: }
0182: if ("<init>".equals(name) && "()V".equals(desc)) {
0183: hasDefaultConstructor = true;
0184: }
0185: if ("<clinit>".equals(name)) {
0186: if (staticBlockMethod != null) {
0187: throw new IllegalStateException();
0188: }
0189: staticBlockMethod = "bdbExistingStaticBlock";
0190: return cv.visitMethod(ACC_PRIVATE + ACC_STATIC,
0191: staticBlockMethod, "()V", null, null);
0192: }
0193: return super .visitMethod(access, name, desc, sig, exceptions);
0194: }
0195:
0196: @Override
0197: public void visitEnd() {
0198: if (!isPersistent || !hasDefaultConstructor) {
0199: throw abort();
0200: }
0201: /* Generate new code at the end of the class. */
0202: sortFields();
0203: genBdbNewInstance();
0204: genBdbNewArray();
0205: genBdbIsPriKeyFieldNullOrZero();
0206: genBdbWritePriKeyField();
0207: genBdbReadPriKeyField();
0208: genBdbWriteSecKeyFields();
0209: genBdbReadSecKeyFields();
0210: genBdbWriteNonKeyFields();
0211: genBdbReadNonKeyFields();
0212: genBdbGetField();
0213: genBdbSetField();
0214: genStaticBlock();
0215: super .visitEnd();
0216: }
0217:
0218: private void sortFields() {
0219: /*
0220: System.out.println("AllFields: " + nonKeyFields);
0221: //*/
0222: if (nonKeyFields.size() == 0) {
0223: return;
0224: }
0225: isCompositeKey = true;
0226: for (FieldInfo field : nonKeyFields) {
0227: if (field.order == null) {
0228: isCompositeKey = false;
0229: }
0230: }
0231: if (isCompositeKey) {
0232: Collections.sort(nonKeyFields, new Comparator<FieldInfo>() {
0233: public int compare(FieldInfo f1, FieldInfo f2) {
0234: return f1.order.value - f2.order.value;
0235: }
0236: });
0237: } else {
0238: for (int i = 0; i < nonKeyFields.size();) {
0239: FieldInfo field = nonKeyFields.get(i);
0240: if (field.isPriKey) {
0241: if (priKeyField == null) {
0242: priKeyField = field;
0243: nonKeyFields.remove(i);
0244: }
0245: } else if (field.isSecKey) {
0246: secKeyFields.add(field);
0247: nonKeyFields.remove(i);
0248: } else {
0249: i += 1;
0250: }
0251: }
0252: Comparator<FieldInfo> cmp = new Comparator<FieldInfo>() {
0253: public int compare(FieldInfo f1, FieldInfo f2) {
0254: return f1.name.compareTo(f2.name);
0255: }
0256: };
0257: Collections.sort(secKeyFields, cmp);
0258: Collections.sort(nonKeyFields, cmp);
0259: }
0260: /*
0261: System.out.println("PriKey: " + priKeyField);
0262: System.out.println("SecKeys: " + secKeyFields);
0263: System.out.println("NonKeys: " + nonKeyFields);
0264: //*/
0265: }
0266:
0267: /**
0268: * Outputs code in a static block to register the prototype instance:
0269: *
0270: * static {
0271: * EnhancedAccessor.registerClass(TheClassName, new TheClass());
0272: * // or for an abstract class:
0273: * EnhancedAccessor.registerClass(TheClassName, null);
0274: * }
0275: */
0276: private void genStaticBlock() {
0277: MethodVisitor mv = cv.visitMethod(ACC_STATIC, "<clinit>",
0278: "()V", null, null);
0279: mv.visitCode();
0280: if (staticBlockMethod != null) {
0281: mv.visitMethodInsn(INVOKESTATIC, className,
0282: staticBlockMethod, "()V");
0283: }
0284: mv.visitLdcInsn(className.replace('/', '.'));
0285: if (isAbstract) {
0286: mv.visitInsn(ACONST_NULL);
0287: } else {
0288: mv.visitTypeInsn(NEW, className);
0289: mv.visitInsn(DUP);
0290: mv.visitMethodInsn(INVOKESPECIAL, className, "<init>",
0291: "()V");
0292: }
0293: mv
0294: .visitMethodInsn(INVOKESTATIC,
0295: "com/sleepycat/persist/impl/EnhancedAccessor",
0296: "registerClass",
0297: "(Ljava/lang/String;Lcom/sleepycat/persist/impl/Enhanced;)V");
0298: mv.visitInsn(RETURN);
0299: mv.visitMaxs(3, 0);
0300: mv.visitEnd();
0301: }
0302:
0303: /**
0304: * public Object bdbNewInstance() {
0305: * return new TheClass();
0306: * // or if abstract:
0307: * return null;
0308: * }
0309: */
0310: private void genBdbNewInstance() {
0311: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "bdbNewInstance",
0312: "()Ljava/lang/Object;", null, null);
0313: mv.visitCode();
0314: if (isAbstract) {
0315: mv.visitInsn(ACONST_NULL);
0316: mv.visitInsn(ARETURN);
0317: mv.visitMaxs(1, 1);
0318: } else {
0319: mv.visitTypeInsn(NEW, className);
0320: mv.visitInsn(DUP);
0321: mv.visitMethodInsn(INVOKESPECIAL, className, "<init>",
0322: "()V");
0323: mv.visitInsn(ARETURN);
0324: mv.visitMaxs(2, 1);
0325: }
0326: mv.visitEnd();
0327: }
0328:
0329: /**
0330: * public Object bdbNewArray(int len) {
0331: * return new TheClass[len];
0332: * // or if abstract:
0333: * return null;
0334: * }
0335: */
0336: private void genBdbNewArray() {
0337: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "bdbNewArray",
0338: "(I)Ljava/lang/Object;", null, null);
0339: mv.visitCode();
0340: if (isAbstract) {
0341: mv.visitInsn(ACONST_NULL);
0342: mv.visitInsn(ARETURN);
0343: mv.visitMaxs(1, 2);
0344: } else {
0345: mv.visitVarInsn(ILOAD, 1);
0346: mv.visitTypeInsn(ANEWARRAY, className);
0347: mv.visitInsn(ARETURN);
0348: mv.visitMaxs(1, 2);
0349: mv.visitEnd();
0350: }
0351: }
0352:
0353: /**
0354: * public boolean bdbIsPriKeyFieldNullOrZero() {
0355: * return theField == null; // or zero or false, as appropriate
0356: * // or if no primary key but has superclass:
0357: * return super.bdbIsPriKeyFieldNullOrZero();
0358: * }
0359: */
0360: private void genBdbIsPriKeyFieldNullOrZero() {
0361: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
0362: "bdbIsPriKeyFieldNullOrZero", "()Z", null, null);
0363: mv.visitCode();
0364: if (priKeyField != null) {
0365: mv.visitVarInsn(ALOAD, 0);
0366: mv.visitFieldInsn(GETFIELD, className, priKeyField.name,
0367: priKeyField.type.getDescriptor());
0368: Label l0 = new Label();
0369: if (isRefType(priKeyField.type)) {
0370: mv.visitJumpInsn(IFNONNULL, l0);
0371: } else {
0372: genBeforeCompareToZero(mv, priKeyField.type);
0373: mv.visitJumpInsn(IFNE, l0);
0374: }
0375: mv.visitInsn(ICONST_1);
0376: Label l1 = new Label();
0377: mv.visitJumpInsn(GOTO, l1);
0378: mv.visitLabel(l0);
0379: mv.visitInsn(ICONST_0);
0380: mv.visitLabel(l1);
0381: } else if (hasPersistentSuperclass) {
0382: mv.visitVarInsn(ALOAD, 0);
0383: mv.visitMethodInsn(INVOKESPECIAL, super className,
0384: "bdbIsPriKeyFieldNullOrZero", "()Z");
0385: } else {
0386: mv.visitInsn(ICONST_0);
0387: }
0388: mv.visitInsn(IRETURN);
0389: mv.visitMaxs(1, 1);
0390: mv.visitEnd();
0391: }
0392:
0393: /**
0394: * public void bdbWritePriKeyField(EntityOutput output, Format format) {
0395: * output.writeKeyObject(theField, format);
0396: * // or
0397: * output.writeInt(theField); // and other simple types
0398: * // or if no primary key but has superclass:
0399: * return super.bdbWritePriKeyField(output, format);
0400: * }
0401: */
0402: private void genBdbWritePriKeyField() {
0403: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
0404: "bdbWritePriKeyField",
0405: "(Lcom/sleepycat/persist/impl/EntityOutput;"
0406: + "Lcom/sleepycat/persist/impl/Format;)V",
0407: null, null);
0408: mv.visitCode();
0409: if (priKeyField != null) {
0410: if (!genWriteSimpleKeyField(mv, priKeyField)) {
0411: /* For a non-simple type, call EntityOutput.writeKeyObject. */
0412: mv.visitVarInsn(ALOAD, 1);
0413: mv.visitVarInsn(ALOAD, 0);
0414: mv.visitFieldInsn(GETFIELD, className,
0415: priKeyField.name, priKeyField.type
0416: .getDescriptor());
0417: mv.visitVarInsn(ALOAD, 2);
0418: mv
0419: .visitMethodInsn(
0420: INVOKEINTERFACE,
0421: "com/sleepycat/persist/impl/EntityOutput",
0422: "writeKeyObject",
0423: "(Ljava/lang/Object;"
0424: + "Lcom/sleepycat/persist/impl/Format;)V");
0425: }
0426: } else if (hasPersistentSuperclass) {
0427: mv.visitVarInsn(ALOAD, 0);
0428: mv.visitVarInsn(ALOAD, 1);
0429: mv.visitVarInsn(ALOAD, 2);
0430: mv.visitMethodInsn(INVOKESPECIAL, super className,
0431: "bdbWritePriKeyField",
0432: "(Lcom/sleepycat/persist/impl/EntityOutput;"
0433: + "Lcom/sleepycat/persist/impl/Format;)V");
0434: }
0435: mv.visitInsn(RETURN);
0436: mv.visitMaxs(3, 3);
0437: mv.visitEnd();
0438: }
0439:
0440: /**
0441: * public void bdbReadPriKeyField(EntityInput input, Format format) {
0442: * theField = (TheFieldClass) input.readKeyObject(format);
0443: * // or
0444: * theField = input.readInt(); // and other simple types
0445: * // or if no primary key but has superclass:
0446: * super.bdbReadPriKeyField(input, format);
0447: * }
0448: */
0449: private void genBdbReadPriKeyField() {
0450: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
0451: "bdbReadPriKeyField",
0452: "(Lcom/sleepycat/persist/impl/EntityInput;"
0453: + "Lcom/sleepycat/persist/impl/Format;)V",
0454: null, null);
0455: mv.visitCode();
0456: if (priKeyField != null) {
0457: if (!genReadSimpleKeyField(mv, priKeyField)) {
0458: /* For a non-simple type, call EntityInput.readKeyObject. */
0459: mv.visitVarInsn(ALOAD, 0);
0460: mv.visitVarInsn(ALOAD, 1);
0461: mv.visitVarInsn(ALOAD, 2);
0462: mv.visitMethodInsn(INVOKEINTERFACE,
0463: "com/sleepycat/persist/impl/EntityInput",
0464: "readKeyObject",
0465: "(Lcom/sleepycat/persist/impl/Format;)"
0466: + "Ljava/lang/Object;");
0467: mv.visitTypeInsn(CHECKCAST,
0468: getTypeInstName(priKeyField.type));
0469: mv.visitFieldInsn(PUTFIELD, className,
0470: priKeyField.name, priKeyField.type
0471: .getDescriptor());
0472: }
0473: } else if (hasPersistentSuperclass) {
0474: mv.visitVarInsn(ALOAD, 0);
0475: mv.visitVarInsn(ALOAD, 1);
0476: mv.visitVarInsn(ALOAD, 2);
0477: mv.visitMethodInsn(INVOKESPECIAL, super className,
0478: "bdbReadPriKeyField",
0479: "(Lcom/sleepycat/persist/impl/EntityInput;"
0480: + "Lcom/sleepycat/persist/impl/Format;)V");
0481: }
0482: mv.visitInsn(RETURN);
0483: mv.visitMaxs(3, 3);
0484: mv.visitEnd();
0485: }
0486:
0487: /**
0488: * public void bdbWriteSecKeyFields(EntityOutput output) {
0489: * output.registerPriKeyObject(priKeyField); // if an object
0490: * super.bdbWriteSecKeyFields(EntityOutput output); // if has super
0491: * output.writeInt(secKeyField1);
0492: * output.writeObject(secKeyField2, null);
0493: * // etc
0494: * }
0495: */
0496: private void genBdbWriteSecKeyFields() {
0497: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
0498: "bdbWriteSecKeyFields",
0499: "(Lcom/sleepycat/persist/impl/EntityOutput;)V", null,
0500: null);
0501: mv.visitCode();
0502: if (priKeyField != null && isRefType(priKeyField.type)) {
0503: genRegisterPrimaryKey(mv, false);
0504: }
0505: if (hasPersistentSuperclass) {
0506: mv.visitVarInsn(ALOAD, 0);
0507: mv.visitVarInsn(ALOAD, 1);
0508: mv.visitMethodInsn(INVOKESPECIAL, super className,
0509: "bdbWriteSecKeyFields",
0510: "(Lcom/sleepycat/persist/impl/EntityOutput;)V");
0511: }
0512: for (FieldInfo field : secKeyFields) {
0513: genWriteField(mv, field);
0514: }
0515: mv.visitInsn(RETURN);
0516: mv.visitMaxs(2, 2);
0517: mv.visitEnd();
0518: }
0519:
0520: /**
0521: * public void bdbReadSecKeyFields(EntityInput input,
0522: * int startField,
0523: * int endField,
0524: * int superLevel) {
0525: * input.registerPriKeyObject(priKeyField); // if an object
0526: * // if has super:
0527: * if (superLevel != 0) {
0528: * super.bdbReadSecKeyFields(..., superLevel - 1);
0529: * }
0530: * if (superLevel <= 0) {
0531: * switch (startField) {
0532: * case 0:
0533: * secKeyField1 = input.readInt();
0534: * if (endField == 0) break;
0535: * case 1:
0536: * secKeyField2 = (String) input.readObject();
0537: * if (endField == 1) break;
0538: * case 2:
0539: * secKeyField3 = input.readInt();
0540: * }
0541: * }
0542: * }
0543: */
0544: private void genBdbReadSecKeyFields() {
0545: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
0546: "bdbReadSecKeyFields",
0547: "(Lcom/sleepycat/persist/impl/EntityInput;III)V", null,
0548: null);
0549: mv.visitCode();
0550: if (priKeyField != null && isRefType(priKeyField.type)) {
0551: genRegisterPrimaryKey(mv, true);
0552: }
0553: genReadSuperKeyFields(mv, true);
0554: genReadFieldSwitch(mv, secKeyFields);
0555: mv.visitInsn(RETURN);
0556: mv.visitMaxs(5, 5);
0557: mv.visitEnd();
0558: }
0559:
0560: /**
0561: * output.registerPriKeyObject(priKeyField);
0562: * // or
0563: * input.registerPriKeyObject(priKeyField);
0564: */
0565: private void genRegisterPrimaryKey(MethodVisitor mv, boolean input) {
0566: String entityInputOrOutputClass = input ? "com/sleepycat/persist/impl/EntityInput"
0567: : "com/sleepycat/persist/impl/EntityOutput";
0568: mv.visitVarInsn(ALOAD, 1);
0569: mv.visitVarInsn(ALOAD, 0);
0570: mv.visitFieldInsn(GETFIELD, className, priKeyField.name,
0571: priKeyField.type.getDescriptor());
0572: mv.visitMethodInsn(INVOKEINTERFACE, entityInputOrOutputClass,
0573: "registerPriKeyObject", "(Ljava/lang/Object;)V");
0574: }
0575:
0576: /**
0577: * public void bdbWriteNonKeyFields(EntityOutput output) {
0578: * super.bdbWriteNonKeyFields(output); // if has super
0579: * output.writeInt(nonKeyField1);
0580: * output.writeObject(nonKeyField2, null);
0581: * // etc
0582: * }
0583: */
0584: private void genBdbWriteNonKeyFields() {
0585: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
0586: "bdbWriteNonKeyFields",
0587: "(Lcom/sleepycat/persist/impl/EntityOutput;)V", null,
0588: null);
0589: mv.visitCode();
0590: if (hasPersistentSuperclass) {
0591: mv.visitVarInsn(ALOAD, 0);
0592: mv.visitVarInsn(ALOAD, 1);
0593: mv.visitMethodInsn(INVOKESPECIAL, super className,
0594: "bdbWriteNonKeyFields",
0595: "(Lcom/sleepycat/persist/impl/EntityOutput;)V");
0596: }
0597: if (isCompositeKey) {
0598: for (FieldInfo field : nonKeyFields) {
0599: genWriteSimpleKeyField(mv, field);
0600: /* Ignore non-simple (illegal) types for composite key. */
0601: }
0602: } else {
0603: for (FieldInfo field : nonKeyFields) {
0604: genWriteField(mv, field);
0605: }
0606: }
0607: mv.visitInsn(RETURN);
0608: mv.visitMaxs(2, 2);
0609: mv.visitEnd();
0610: }
0611:
0612: /**
0613: * public void bdbReadNonKeyFields(EntityInput input,
0614: * int startField,
0615: * int endField,
0616: * int superLevel) {
0617: * // if has super:
0618: * if (superLevel != 0) {
0619: * super.bdbReadNonKeyFields(..., superLevel - 1);
0620: * }
0621: * nonKeyField1 = input.readInt();
0622: * nonKeyField2 = (String) input.readObject();
0623: * // etc
0624: * // or like bdbReadSecKeyFields if not a composite key class
0625: * }
0626: */
0627: private void genBdbReadNonKeyFields() {
0628: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC,
0629: "bdbReadNonKeyFields",
0630: "(Lcom/sleepycat/persist/impl/EntityInput;III)V", null,
0631: null);
0632: mv.visitCode();
0633: if (isCompositeKey) {
0634: for (FieldInfo field : nonKeyFields) {
0635: genReadSimpleKeyField(mv, field);
0636: /* Ignore non-simple (illegal) types for composite key. */
0637: }
0638: } else {
0639: genReadSuperKeyFields(mv, false);
0640: genReadFieldSwitch(mv, nonKeyFields);
0641: }
0642: mv.visitInsn(RETURN);
0643: mv.visitMaxs(5, 5);
0644: mv.visitEnd();
0645: }
0646:
0647: /**
0648: * output.writeInt(field); // and other primitives
0649: * // or
0650: * output.writeObject(field, null);
0651: */
0652: private void genWriteField(MethodVisitor mv, FieldInfo field) {
0653: mv.visitVarInsn(ALOAD, 1);
0654: mv.visitVarInsn(ALOAD, 0);
0655: mv.visitFieldInsn(GETFIELD, className, field.name, field.type
0656: .getDescriptor());
0657: int sort = field.type.getSort();
0658: if (sort == Type.OBJECT || sort == Type.ARRAY) {
0659: mv.visitInsn(ACONST_NULL);
0660: mv
0661: .visitMethodInsn(INVOKEINTERFACE,
0662: "com/sleepycat/persist/impl/EntityOutput",
0663: "writeObject",
0664: "(Ljava/lang/Object;Lcom/sleepycat/persist/impl/Format;)V");
0665: } else {
0666: genWritePrimitive(mv, sort);
0667: }
0668: }
0669:
0670: /**
0671: * Generates writing of a simple type key field, or returns false if the
0672: * key field is not a simple type (i.e., it is a composite key type).
0673: *
0674: * output.writeInt(theField); // and other primitives
0675: * // or
0676: * output.writeInt(theField.intValue()); // and other simple types
0677: * // or returns false
0678: */
0679: private boolean genWriteSimpleKeyField(MethodVisitor mv,
0680: FieldInfo field) {
0681: if (genWritePrimitiveField(mv, field)) {
0682: return true;
0683: }
0684: String fieldClassName = field.type.getClassName();
0685: if (!isSimpleRefType(fieldClassName)) {
0686: return false;
0687: }
0688: mv.visitVarInsn(ALOAD, 1);
0689: mv.visitVarInsn(ALOAD, 0);
0690: mv.visitFieldInsn(GETFIELD, className, field.name, field.type
0691: .getDescriptor());
0692: Integer sort = PRIMITIVE_WRAPPERS.get(fieldClassName);
0693: if (sort != null) {
0694: genUnwrapPrimitive(mv, sort);
0695: genWritePrimitive(mv, sort);
0696: } else if (fieldClassName.equals(Date.class.getName())) {
0697: mv.visitMethodInsn(INVOKEVIRTUAL, "java/util/Date",
0698: "getTime", "()J");
0699: genWritePrimitive(mv, Type.LONG);
0700: } else if (fieldClassName.equals(String.class.getName())) {
0701: mv
0702: .visitMethodInsn(INVOKEINTERFACE,
0703: "com/sleepycat/persist/impl/EntityOutput",
0704: "writeString",
0705: "(Ljava/lang/String;)Lcom/sleepycat/bind/tuple/TupleOutput;");
0706: mv.visitInsn(POP);
0707: } else if (fieldClassName.equals(BigInteger.class.getName())) {
0708: mv
0709: .visitMethodInsn(INVOKEINTERFACE,
0710: "com/sleepycat/persist/impl/EntityOutput",
0711: "writeBigInteger",
0712: "(Ljava/math/BigInteger;)Lcom/sleepycat/bind/tuple/TupleOutput;");
0713: mv.visitInsn(POP);
0714: } else {
0715: throw new IllegalStateException(fieldClassName);
0716: }
0717: return true;
0718: }
0719:
0720: private boolean genWritePrimitiveField(MethodVisitor mv,
0721: FieldInfo field) {
0722: int sort = field.type.getSort();
0723: if (sort == Type.OBJECT || sort == Type.ARRAY) {
0724: return false;
0725: }
0726: mv.visitVarInsn(ALOAD, 1);
0727: mv.visitVarInsn(ALOAD, 0);
0728: mv.visitFieldInsn(GETFIELD, className, field.name, field.type
0729: .getDescriptor());
0730: genWritePrimitive(mv, sort);
0731: return true;
0732: }
0733:
0734: /**
0735: * // if has super:
0736: * if (superLevel != 0) {
0737: * super.bdbReadXxxKeyFields(..., superLevel - 1);
0738: * }
0739: */
0740: private void genReadSuperKeyFields(MethodVisitor mv,
0741: boolean areSecKeyFields) {
0742: if (hasPersistentSuperclass) {
0743: Label next = new Label();
0744: mv.visitVarInsn(ILOAD, 4);
0745: mv.visitJumpInsn(IFEQ, next);
0746: mv.visitVarInsn(ALOAD, 0);
0747: mv.visitVarInsn(ALOAD, 1);
0748: mv.visitVarInsn(ILOAD, 2);
0749: mv.visitVarInsn(ILOAD, 3);
0750: mv.visitVarInsn(ILOAD, 4);
0751: mv.visitInsn(ICONST_1);
0752: mv.visitInsn(ISUB);
0753: String name = areSecKeyFields ? "bdbReadSecKeyFields"
0754: : "bdbReadNonKeyFields";
0755: mv.visitMethodInsn(INVOKESPECIAL, super className, name,
0756: "(Lcom/sleepycat/persist/impl/EntityInput;III)V");
0757: mv.visitLabel(next);
0758: }
0759: }
0760:
0761: /**
0762: * public void bdbReadXxxKeyFields(EntityInput input,
0763: * int startField,
0764: * int endField,
0765: * int superLevel) {
0766: * // ...
0767: * if (superLevel <= 0) {
0768: * switch (startField) {
0769: * case 0:
0770: * keyField1 = input.readInt();
0771: * if (endField == 0) break;
0772: * case 1:
0773: * keyField2 = (String) input.readObject();
0774: * if (endField == 1) break;
0775: * case 2:
0776: * keyField3 = input.readInt();
0777: * }
0778: * }
0779: */
0780: private void genReadFieldSwitch(MethodVisitor mv,
0781: List<FieldInfo> fields) {
0782: int nFields = fields.size();
0783: if (nFields > 0) {
0784: mv.visitVarInsn(ILOAD, 4);
0785: Label pastSwitch = new Label();
0786: mv.visitJumpInsn(IFGT, pastSwitch);
0787: Label[] labels = new Label[nFields];
0788: for (int i = 0; i < nFields; i += 1) {
0789: labels[i] = new Label();
0790: }
0791: mv.visitVarInsn(ILOAD, 2);
0792: mv.visitTableSwitchInsn(0, nFields - 1, pastSwitch, labels);
0793: for (int i = 0; i < nFields; i += 1) {
0794: FieldInfo field = fields.get(i);
0795: mv.visitLabel(labels[i]);
0796: genReadField(mv, field);
0797: if (i < nFields - 1) {
0798: Label nextCase = labels[i + 1];
0799: mv.visitVarInsn(ILOAD, 3);
0800: if (i == 0) {
0801: mv.visitJumpInsn(IFNE, nextCase);
0802: } else {
0803: switch (i) {
0804: case 1:
0805: mv.visitInsn(ICONST_1);
0806: break;
0807: case 2:
0808: mv.visitInsn(ICONST_2);
0809: break;
0810: case 3:
0811: mv.visitInsn(ICONST_3);
0812: break;
0813: case 4:
0814: mv.visitInsn(ICONST_4);
0815: break;
0816: case 5:
0817: mv.visitInsn(ICONST_5);
0818: break;
0819: default:
0820: mv.visitIntInsn(BIPUSH, i);
0821: }
0822: mv.visitJumpInsn(IF_ICMPNE, nextCase);
0823: }
0824: mv.visitJumpInsn(GOTO, pastSwitch);
0825: }
0826: }
0827: mv.visitLabel(pastSwitch);
0828: }
0829: }
0830:
0831: /**
0832: * field = input.readInt(); // and other primitives
0833: * // or
0834: * field = (FieldClass) input.readObject();
0835: */
0836: private void genReadField(MethodVisitor mv, FieldInfo field) {
0837: mv.visitVarInsn(ALOAD, 0);
0838: mv.visitVarInsn(ALOAD, 1);
0839: if (isRefType(field.type)) {
0840: mv.visitMethodInsn(INVOKEINTERFACE,
0841: "com/sleepycat/persist/impl/EntityInput",
0842: "readObject", "()Ljava/lang/Object;");
0843: mv.visitTypeInsn(CHECKCAST, getTypeInstName(field.type));
0844: } else {
0845: genReadPrimitive(mv, field.type.getSort());
0846: }
0847: mv.visitFieldInsn(PUTFIELD, className, field.name, field.type
0848: .getDescriptor());
0849: }
0850:
0851: /**
0852: * Generates reading of a simple type key field, or returns false if the
0853: * key field is not a simple type (i.e., it is a composite key type).
0854: *
0855: * field = input.readInt(); // and other primitives
0856: * // or
0857: * field = Integer.valueOf(input.readInt()); // and other simple types
0858: * // or returns false
0859: */
0860: private boolean genReadSimpleKeyField(MethodVisitor mv,
0861: FieldInfo field) {
0862: if (genReadPrimitiveField(mv, field)) {
0863: return true;
0864: }
0865: String fieldClassName = field.type.getClassName();
0866: if (!isSimpleRefType(fieldClassName)) {
0867: return false;
0868: }
0869: Integer sort = PRIMITIVE_WRAPPERS.get(fieldClassName);
0870: if (sort != null) {
0871: mv.visitVarInsn(ALOAD, 0);
0872: mv.visitVarInsn(ALOAD, 1);
0873: genReadPrimitive(mv, sort);
0874: genWrapPrimitive(mv, sort);
0875: } else if (fieldClassName.equals(Date.class.getName())) {
0876: /* Date is a special case because we use NEW instead of valueOf. */
0877: mv.visitVarInsn(ALOAD, 0);
0878: mv.visitTypeInsn(NEW, "java/util/Date");
0879: mv.visitInsn(DUP);
0880: mv.visitVarInsn(ALOAD, 1);
0881: genReadPrimitive(mv, Type.LONG);
0882: mv.visitMethodInsn(INVOKESPECIAL, "java/util/Date",
0883: "<init>", "(J)V");
0884: } else if (fieldClassName.equals(String.class.getName())) {
0885: mv.visitVarInsn(ALOAD, 0);
0886: mv.visitVarInsn(ALOAD, 1);
0887: mv.visitMethodInsn(INVOKEINTERFACE,
0888: "com/sleepycat/persist/impl/EntityInput",
0889: "readString", "()Ljava/lang/String;");
0890: } else if (fieldClassName.equals(BigInteger.class.getName())) {
0891: mv.visitVarInsn(ALOAD, 0);
0892: mv.visitVarInsn(ALOAD, 1);
0893: mv.visitMethodInsn(INVOKEINTERFACE,
0894: "com/sleepycat/persist/impl/EntityInput",
0895: "readBigInteger", "()Ljava/math/BigInteger;");
0896: } else {
0897: throw new IllegalStateException(fieldClassName);
0898: }
0899: mv.visitFieldInsn(PUTFIELD, className, field.name, field.type
0900: .getDescriptor());
0901: return true;
0902: }
0903:
0904: private boolean genReadPrimitiveField(MethodVisitor mv,
0905: FieldInfo field) {
0906: int sort = field.type.getSort();
0907: if (sort == Type.OBJECT || sort == Type.ARRAY) {
0908: return false;
0909: }
0910: mv.visitVarInsn(ALOAD, 0);
0911: mv.visitVarInsn(ALOAD, 1);
0912: genReadPrimitive(mv, sort);
0913: mv.visitFieldInsn(PUTFIELD, className, field.name, field.type
0914: .getDescriptor());
0915: return true;
0916: }
0917:
0918: /**
0919: * public Object bdbGetField(Object o,
0920: * int field,
0921: * int superLevel,
0922: * boolean isSecField) {
0923: * if (superLevel > 0) {
0924: * // if has superclass:
0925: * return super.bdbGetField
0926: * (o, field, superLevel - 1, isSecField);
0927: * } else if (isSecField) {
0928: * switch (field) {
0929: * case 0:
0930: * return Integer.valueOf(f2);
0931: * case 1:
0932: * return f3;
0933: * case 2:
0934: * return f4;
0935: * }
0936: * } else {
0937: * switch (field) {
0938: * case 0:
0939: * return Integer.valueOf(f5);
0940: * case 1:
0941: * return f6;
0942: * case 2:
0943: * return f7;
0944: * }
0945: * }
0946: * return null;
0947: * }
0948: */
0949: private void genBdbGetField() {
0950: MethodVisitor mv = cv
0951: .visitMethod(ACC_PUBLIC, "bdbGetField",
0952: "(Ljava/lang/Object;IIZ)Ljava/lang/Object;",
0953: null, null);
0954: mv.visitCode();
0955: mv.visitVarInsn(ILOAD, 3);
0956: Label l0 = new Label();
0957: mv.visitJumpInsn(IFLE, l0);
0958: Label l1 = new Label();
0959: if (hasPersistentSuperclass) {
0960: mv.visitVarInsn(ALOAD, 0);
0961: mv.visitVarInsn(ALOAD, 1);
0962: mv.visitVarInsn(ILOAD, 2);
0963: mv.visitVarInsn(ILOAD, 3);
0964: mv.visitInsn(ICONST_1);
0965: mv.visitInsn(ISUB);
0966: mv.visitVarInsn(ILOAD, 4);
0967: mv.visitMethodInsn(INVOKESPECIAL, className, "bdbGetField",
0968: "(Ljava/lang/Object;IIZ)Ljava/lang/Object;");
0969: mv.visitInsn(ARETURN);
0970: } else {
0971: mv.visitJumpInsn(GOTO, l1);
0972: }
0973: mv.visitLabel(l0);
0974: mv.visitVarInsn(ILOAD, 4);
0975: Label l2 = new Label();
0976: mv.visitJumpInsn(IFEQ, l2);
0977: genGetFieldSwitch(mv, secKeyFields, l1);
0978: mv.visitLabel(l2);
0979: genGetFieldSwitch(mv, nonKeyFields, l1);
0980: mv.visitLabel(l1);
0981: mv.visitInsn(ACONST_NULL);
0982: mv.visitInsn(ARETURN);
0983: mv.visitMaxs(1, 5);
0984: mv.visitEnd();
0985: }
0986:
0987: /**
0988: * mv.visitVarInsn(ILOAD, 2);
0989: * Label l0 = new Label();
0990: * Label l1 = new Label();
0991: * Label l2 = new Label();
0992: * mv.visitTableSwitchInsn(0, 2, TheDefLabel, new Label[] { l0, l1, l2 });
0993: * mv.visitLabel(l0);
0994: * mv.visitVarInsn(ALOAD, 0);
0995: * mv.visitFieldInsn(GETFIELD, TheClassName, "f2", "I");
0996: * mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf",
0997: * "(I)Ljava/lang/Integer;");
0998: * mv.visitInsn(ARETURN);
0999: * mv.visitLabel(l1);
1000: * mv.visitVarInsn(ALOAD, 0);
1001: * mv.visitFieldInsn(GETFIELD, TheClassName, "f3", "Ljava/lang/String;");
1002: * mv.visitInsn(ARETURN);
1003: * mv.visitLabel(l2);
1004: * mv.visitVarInsn(ALOAD, 0);
1005: * mv.visitFieldInsn(GETFIELD, TheClassName, "f4", "Ljava/lang/String;");
1006: * mv.visitInsn(ARETURN);
1007: */
1008: private void genGetFieldSwitch(MethodVisitor mv,
1009: List<FieldInfo> fields, Label defaultLabel) {
1010: int nFields = fields.size();
1011: if (nFields == 0) {
1012: mv.visitJumpInsn(GOTO, defaultLabel);
1013: return;
1014: }
1015: Label[] labels = new Label[nFields];
1016: for (int i = 0; i < nFields; i += 1) {
1017: labels[i] = new Label();
1018: }
1019: mv.visitVarInsn(ILOAD, 2);
1020: mv.visitTableSwitchInsn(0, nFields - 1, defaultLabel, labels);
1021: for (int i = 0; i < nFields; i += 1) {
1022: FieldInfo field = fields.get(i);
1023: mv.visitLabel(labels[i]);
1024: mv.visitVarInsn(ALOAD, 0);
1025: mv.visitFieldInsn(GETFIELD, className, field.name,
1026: field.type.getDescriptor());
1027: if (!isRefType(field.type)) {
1028: genWrapPrimitive(mv, field.type.getSort());
1029: }
1030: mv.visitInsn(ARETURN);
1031: }
1032: }
1033:
1034: /**
1035: * public void bdbSetField(Object o,
1036: * int field,
1037: * int superLevel,
1038: * boolean isSecField,
1039: * Object value) {
1040: * if (superLevel > 0) {
1041: * // if has superclass:
1042: * super.bdbSetField
1043: * (o, field, superLevel - 1, isSecField, value);
1044: * } else if (isSecField) {
1045: * switch (field) {
1046: * case 0:
1047: * f2 = ((Integer) value).intValue();
1048: * case 1:
1049: * f3 = (String) value;
1050: * case 2:
1051: * f4 = (String) value;
1052: * }
1053: * } else {
1054: * switch (field) {
1055: * case 0:
1056: * f5 = ((Integer) value).intValue();
1057: * case 1:
1058: * f6 = (String) value;
1059: * case 2:
1060: * f7 = (String) value;
1061: * }
1062: * }
1063: * }
1064: */
1065: private void genBdbSetField() {
1066: MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "bdbSetField",
1067: "(Ljava/lang/Object;IIZLjava/lang/Object;)V", null,
1068: null);
1069: mv.visitCode();
1070: mv.visitVarInsn(ILOAD, 3);
1071: Label l0 = new Label();
1072: mv.visitJumpInsn(IFLE, l0);
1073: if (hasPersistentSuperclass) {
1074: mv.visitVarInsn(ALOAD, 0);
1075: mv.visitVarInsn(ALOAD, 1);
1076: mv.visitVarInsn(ILOAD, 2);
1077: mv.visitVarInsn(ILOAD, 3);
1078: mv.visitInsn(ICONST_1);
1079: mv.visitInsn(ISUB);
1080: mv.visitVarInsn(ILOAD, 4);
1081: mv.visitVarInsn(ALOAD, 5);
1082: mv.visitMethodInsn(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, Label defaultLabel) {
1126: int nFields = fields.size();
1127: if (nFields == 0) {
1128: mv.visitJumpInsn(GOTO, defaultLabel);
1129: return;
1130: }
1131: Label[] labels = new Label[nFields];
1132: for (int i = 0; i < nFields; i += 1) {
1133: labels[i] = new Label();
1134: }
1135: mv.visitVarInsn(ILOAD, 2);
1136: mv.visitTableSwitchInsn(0, nFields - 1, defaultLabel, labels);
1137: for (int i = 0; i < nFields; i += 1) {
1138: FieldInfo field = fields.get(i);
1139: mv.visitLabel(labels[i]);
1140: mv.visitVarInsn(ALOAD, 0);
1141: mv.visitVarInsn(ALOAD, 5);
1142: if (isRefType(field.type)) {
1143: mv
1144: .visitTypeInsn(CHECKCAST,
1145: getTypeInstName(field.type));
1146: } else {
1147: int sort = field.type.getSort();
1148: mv.visitTypeInsn(CHECKCAST, getPrimitiveWrapperClass(
1149: sort).replace('.', '/'));
1150: genUnwrapPrimitive(mv, sort);
1151: }
1152: mv.visitFieldInsn(PUTFIELD, className, field.name,
1153: 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(INVOKEINTERFACE,
1162: "com/sleepycat/persist/impl/EntityOutput",
1163: "writeBoolean",
1164: "(Z)Lcom/sleepycat/bind/tuple/TupleOutput;");
1165: break;
1166: case Type.CHAR:
1167: mv.visitMethodInsn(INVOKEINTERFACE,
1168: "com/sleepycat/persist/impl/EntityOutput",
1169: "writeChar",
1170: "(I)Lcom/sleepycat/bind/tuple/TupleOutput;");
1171: break;
1172: case Type.BYTE:
1173: mv.visitMethodInsn(INVOKEINTERFACE,
1174: "com/sleepycat/persist/impl/EntityOutput",
1175: "writeByte",
1176: "(I)Lcom/sleepycat/bind/tuple/TupleOutput;");
1177: break;
1178: case Type.SHORT:
1179: mv.visitMethodInsn(INVOKEINTERFACE,
1180: "com/sleepycat/persist/impl/EntityOutput",
1181: "writeShort",
1182: "(I)Lcom/sleepycat/bind/tuple/TupleOutput;");
1183: break;
1184: case Type.INT:
1185: mv.visitMethodInsn(INVOKEINTERFACE,
1186: "com/sleepycat/persist/impl/EntityOutput",
1187: "writeInt",
1188: "(I)Lcom/sleepycat/bind/tuple/TupleOutput;");
1189: break;
1190: case Type.LONG:
1191: mv.visitMethodInsn(INVOKEINTERFACE,
1192: "com/sleepycat/persist/impl/EntityOutput",
1193: "writeLong",
1194: "(J)Lcom/sleepycat/bind/tuple/TupleOutput;");
1195: break;
1196: case Type.FLOAT:
1197: mv.visitMethodInsn(INVOKEINTERFACE,
1198: "com/sleepycat/persist/impl/EntityOutput",
1199: "writeSortedFloat",
1200: "(F)Lcom/sleepycat/bind/tuple/TupleOutput;");
1201: break;
1202: case Type.DOUBLE:
1203: mv.visitMethodInsn(INVOKEINTERFACE,
1204: "com/sleepycat/persist/impl/EntityOutput",
1205: "writeSortedDouble",
1206: "(D)Lcom/sleepycat/bind/tuple/TupleOutput;");
1207: break;
1208: default:
1209: throw new IllegalStateException(String.valueOf(sort));
1210: }
1211: /* The write methods always return 'this' and we always discard it. */
1212: mv.visitInsn(POP);
1213: }
1214:
1215: private void genReadPrimitive(MethodVisitor mv, int sort) {
1216: switch (sort) {
1217: case Type.BOOLEAN:
1218: mv.visitMethodInsn(INVOKEINTERFACE,
1219: "com/sleepycat/persist/impl/EntityInput",
1220: "readBoolean", "()Z");
1221: break;
1222: case Type.CHAR:
1223: mv.visitMethodInsn(INVOKEINTERFACE,
1224: "com/sleepycat/persist/impl/EntityInput",
1225: "readChar", "()C");
1226: break;
1227: case Type.BYTE:
1228: mv.visitMethodInsn(INVOKEINTERFACE,
1229: "com/sleepycat/persist/impl/EntityInput",
1230: "readByte", "()B");
1231: break;
1232: case Type.SHORT:
1233: mv.visitMethodInsn(INVOKEINTERFACE,
1234: "com/sleepycat/persist/impl/EntityInput",
1235: "readShort", "()S");
1236: break;
1237: case Type.INT:
1238: mv.visitMethodInsn(INVOKEINTERFACE,
1239: "com/sleepycat/persist/impl/EntityInput",
1240: "readInt", "()I");
1241: break;
1242: case Type.LONG:
1243: mv.visitMethodInsn(INVOKEINTERFACE,
1244: "com/sleepycat/persist/impl/EntityInput",
1245: "readLong", "()J");
1246: break;
1247: case Type.FLOAT:
1248: mv.visitMethodInsn(INVOKEINTERFACE,
1249: "com/sleepycat/persist/impl/EntityInput",
1250: "readSortedFloat", "()F");
1251: break;
1252: case Type.DOUBLE:
1253: mv.visitMethodInsn(INVOKEINTERFACE,
1254: "com/sleepycat/persist/impl/EntityInput",
1255: "readSortedDouble", "()D");
1256: break;
1257: default:
1258: throw new IllegalStateException(String.valueOf(sort));
1259: }
1260: }
1261:
1262: private void genWrapPrimitive(MethodVisitor mv, int sort) {
1263: switch (sort) {
1264: case Type.BOOLEAN:
1265: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean",
1266: "valueOf", "(Z)Ljava/lang/Boolean;");
1267: break;
1268: case Type.CHAR:
1269: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character",
1270: "valueOf", "(C)Ljava/lang/Character;");
1271: break;
1272: case Type.BYTE:
1273: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte",
1274: "valueOf", "(B)Ljava/lang/Byte;");
1275: break;
1276: case Type.SHORT:
1277: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short",
1278: "valueOf", "(S)Ljava/lang/Short;");
1279: break;
1280: case Type.INT:
1281: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer",
1282: "valueOf", "(I)Ljava/lang/Integer;");
1283: break;
1284: case Type.LONG:
1285: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long",
1286: "valueOf", "(J)Ljava/lang/Long;");
1287: break;
1288: case Type.FLOAT:
1289: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float",
1290: "valueOf", "(F)Ljava/lang/Float;");
1291: break;
1292: case Type.DOUBLE:
1293: mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double",
1294: "valueOf", "(D)Ljava/lang/Double;");
1295: break;
1296: default:
1297: throw new IllegalStateException(String.valueOf(sort));
1298: }
1299: }
1300:
1301: private void genUnwrapPrimitive(MethodVisitor mv, int sort) {
1302: switch (sort) {
1303: case Type.BOOLEAN:
1304: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean",
1305: "booleanValue", "()Z");
1306: break;
1307: case Type.CHAR:
1308: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character",
1309: "charValue", "()C");
1310: break;
1311: case Type.BYTE:
1312: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte",
1313: "byteValue", "()B");
1314: break;
1315: case Type.SHORT:
1316: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short",
1317: "shortValue", "()S");
1318: break;
1319: case Type.INT:
1320: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer",
1321: "intValue", "()I");
1322: break;
1323: case Type.LONG:
1324: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long",
1325: "longValue", "()J");
1326: break;
1327: case Type.FLOAT:
1328: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float",
1329: "floatValue", "()F");
1330: break;
1331: case Type.DOUBLE:
1332: mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double",
1333: "doubleValue", "()D");
1334: break;
1335: default:
1336: throw new IllegalStateException(String.valueOf(sort));
1337: }
1338: }
1339:
1340: /**
1341: * Returns the type name for a visitTypeInsn operand, which is the internal
1342: * name for an object type and the descriptor for an array type. Must not
1343: * be called for a non-reference type.
1344: */
1345: private static String getTypeInstName(Type type) {
1346: if (type.getSort() == Type.OBJECT) {
1347: return type.getInternalName();
1348: } else if (type.getSort() == Type.ARRAY) {
1349: return type.getDescriptor();
1350: } else {
1351: throw new IllegalStateException();
1352: }
1353: }
1354:
1355: /**
1356: * Call this method before comparing a non-reference operand to zero as an
1357: * int, for example, with IFNE, IFEQ, IFLT, etc. If the operand is a long,
1358: * float or double, this method will compare it to zero and leave the
1359: * result as an int operand.
1360: */
1361: private static void genBeforeCompareToZero(MethodVisitor mv,
1362: Type type) {
1363: switch (type.getSort()) {
1364: case Type.LONG:
1365: mv.visitInsn(LCONST_0);
1366: mv.visitInsn(LCMP);
1367: break;
1368: case Type.FLOAT:
1369: mv.visitInsn(FCONST_0);
1370: mv.visitInsn(FCMPL);
1371: break;
1372: case Type.DOUBLE:
1373: mv.visitInsn(DCONST_0);
1374: mv.visitInsn(DCMPL);
1375: break;
1376: }
1377: }
1378:
1379: /**
1380: * Returns true if the given class is a primitive wrapper, Date or String.
1381: */
1382: static boolean isSimpleRefType(String className) {
1383: return (PRIMITIVE_WRAPPERS.containsKey(className)
1384: || className.equals(BigInteger.class.getName())
1385: || className.equals(Date.class.getName()) || className
1386: .equals(String.class.getName()));
1387: }
1388:
1389: /**
1390: * Returns the wrapper class for a primitive.
1391: */
1392: static String getPrimitiveWrapperClass(int primitiveSort) {
1393: for (Map.Entry<String, Integer> entry : PRIMITIVE_WRAPPERS
1394: .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,
1465: visible);
1466: if (desc.equals("Lcom/sleepycat/persist/model/KeyField;")) {
1467: order = new OrderInfo(ret);
1468: ret = order;
1469: } else if (desc
1470: .equals("Lcom/sleepycat/persist/model/PrimaryKey;")) {
1471: isPriKey = true;
1472: } else if (desc
1473: .equals("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
1521: AnnotationVisitor {
1522:
1523: AnnotationVisitor parent;
1524:
1525: AnnotationInfo(AnnotationVisitor parent) {
1526: this .parent = parent;
1527: }
1528:
1529: public void visit(String name, Object value) {
1530: parent.visit(name, value);
1531: }
1532:
1533: public AnnotationVisitor visitAnnotation(String name,
1534: String desc) {
1535: return parent.visitAnnotation(name, desc);
1536: }
1537:
1538: public AnnotationVisitor visitArray(String name) {
1539: return parent.visitArray(name);
1540: }
1541:
1542: public void visitEnum(String name, String desc, String value) {
1543: parent.visitEnum(name, desc, value);
1544: }
1545:
1546: public void visitEnd() {
1547: parent.visitEnd();
1548: }
1549: }
1550: }
|