You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/05/22 19:55:54 UTC
svn commit: r171351 [10/16] - in /incubator/jdo/trunk/enhancer20: ./ src/
src/conf/ src/java/ src/java/org/ src/java/org/apache/
src/java/org/apache/jdo/ src/java/org/apache/jdo/enhancer/
src/java/org/apache/jdo/impl/ src/java/org/apache/jdo/impl/enhancer/
src/java/org/apache/jdo/impl/enhancer/classfile/
src/java/org/apache/jdo/impl/enhancer/core/
src/java/org/apache/jdo/impl/enhancer/generator/
src/java/org/apache/jdo/impl/enhancer/meta/
src/java/org/apache/jdo/impl/enhancer/meta/model/
src/java/org/apache/jdo/impl/enhancer/meta/prop/
src/java/org/apache/jdo/impl/enhancer/meta/util/
src/java/org/apache/jdo/impl/enhancer/util/ test/ test/sempdept/
test/sempdept/src/ test/sempdept/src/empdept/
Added: incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/core/Builder.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/core/Builder.java?rev=171351&view=auto
==============================================================================
--- incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/core/Builder.java (added)
+++ incubator/jdo/trunk/enhancer20/src/java/org/apache/jdo/impl/enhancer/core/Builder.java Sun May 22 10:55:51 2005
@@ -0,0 +1,4716 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.enhancer.core;
+
+import java.util.HashMap;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.Enumeration;
+
+import org.apache.jdo.impl.enhancer.classfile.AttributeVector;
+import org.apache.jdo.impl.enhancer.classfile.ClassField;
+import org.apache.jdo.impl.enhancer.classfile.ClassFile;
+import org.apache.jdo.impl.enhancer.classfile.CodeAttribute;
+import org.apache.jdo.impl.enhancer.classfile.ConstClass;
+import org.apache.jdo.impl.enhancer.classfile.ConstFieldRef;
+import org.apache.jdo.impl.enhancer.classfile.ConstNameAndType;
+import org.apache.jdo.impl.enhancer.classfile.ConstUtf8;
+import org.apache.jdo.impl.enhancer.classfile.ConstantPool;
+import org.apache.jdo.impl.enhancer.classfile.Descriptor;
+import org.apache.jdo.impl.enhancer.classfile.ExceptionRange;
+import org.apache.jdo.impl.enhancer.classfile.ExceptionTable;
+import org.apache.jdo.impl.enhancer.classfile.ExceptionsAttribute;
+import org.apache.jdo.impl.enhancer.classfile.Insn;
+import org.apache.jdo.impl.enhancer.classfile.InsnIInc;
+import org.apache.jdo.impl.enhancer.classfile.InsnInterfaceInvoke;
+import org.apache.jdo.impl.enhancer.classfile.InsnLookupSwitch;
+import org.apache.jdo.impl.enhancer.classfile.InsnTableSwitch;
+import org.apache.jdo.impl.enhancer.classfile.InsnTarget;
+import org.apache.jdo.impl.enhancer.classfile.InsnUtils;
+import org.apache.jdo.impl.enhancer.classfile.VMConstants;
+import org.apache.jdo.impl.enhancer.util.InternalError;
+import org.apache.jdo.impl.enhancer.util.Support;
+
+/**
+ * Helper object to create the generic JDO methods for a class.
+ */
+class Builder
+ extends Support
+ implements VMConstants, JDOConstants, EnhancerConstants
+{
+ /**
+ * The augmentation controller for this class.
+ */
+ private final Augmenter augmenter;
+
+ /**
+ * The class analyzer for this class.
+ */
+ private final Analyzer analyzer;
+
+ /**
+ * The classfile to be annotated.
+ */
+ private final ClassFile classFile;
+
+ /**
+ * The class name in VM form.
+ */
+ private final String className;
+
+ /**
+ * The class name in user ('.' delimited) form.
+ */
+ private final String userClassName;
+
+ /**
+ * The classfile's constant pool.
+ */
+ private final ConstantPool pool;
+
+ /**
+ * Repository for the enhancement options.
+ */
+ private final Environment env;
+
+ /**
+ * The constant utf8 string for the CodeAttribute.
+ */
+ private ConstUtf8 codeAttributeUtf8;
+ /**
+
+ * The constant field ref for the jdoStateManager field.
+ */
+ private ConstFieldRef jdoStateManagerFieldRef;
+
+ /**
+ * The constant field ref for the jdoFlags field.
+ */
+ private ConstFieldRef jdoFlagsFieldRef;
+
+ /**
+ * The constant field ref for the jdoFieldNames field.
+ */
+ private ConstFieldRef jdoFieldNamesFieldRef;
+
+ /**
+ * The constant field ref for the jdoFieldTypes field.
+ */
+ private ConstFieldRef jdoFieldTypesFieldRef;
+
+ /**
+ * The constant field ref for the jdoFieldFlags field.
+ */
+ private ConstFieldRef jdoFieldFlagsFieldRef;
+
+ /**
+ * The constant field ref for the jdoPersistenceCapableSuperclass field.
+ */
+ private ConstFieldRef jdoPersistenceCapableSuperclassFieldRef;
+
+ /**
+ * The constant field refs for the annotated fields sorted by their
+ * relative field index.
+ */
+ private ConstFieldRef[] annotatedFieldRefs;
+
+ /**
+ * The constant field refs for the key fields sorted by
+ * ascending relative field index.
+ */
+ private ConstFieldRef[] keyFieldRefs;
+
+ /**
+ * The constant field refs on the key class for the key fields sorted by
+ * ascending relative field index.
+ */
+ private ConstFieldRef[] keyClassKeyFieldRefs;
+
+ /**
+ * Constructor.
+ */
+ public Builder(Analyzer analyzer,
+ Augmenter augmenter,
+ Environment env)
+ {
+ affirm(analyzer != null);
+ affirm(augmenter != null);
+ affirm(env != null);
+
+ this.analyzer = analyzer;
+ this.augmenter = augmenter;
+ this.classFile = analyzer.getClassFile();
+ this.className = classFile.classNameString();
+ this.userClassName = classFile.userClassName();
+ this.pool = classFile.pool();
+ this.env = env;
+
+ affirm(classFile != null);
+ affirm(className != null);
+ affirm(userClassName != null);
+ affirm(pool != null);
+ }
+
+ // ----------------------------------------------------------------------
+ // Internal Helper Methods
+ // ----------------------------------------------------------------------
+
+ /**
+ * Holder object for returning a size info from a code generation method.
+ */
+ static private class SizeHolder
+ {
+ int size;
+ }
+
+ /**
+ * Returns the minimum of two numbers.
+ */
+ static private int min(int i, int j) {
+ return (i < j ? i : j);
+ }
+
+ /**
+ * Returns the maximum of two numbers.
+ */
+ static private int max(int i, int j) {
+ return (i < j ? j : i);
+ }
+
+ /**
+ * Count the size of the arguments to an invokevirtual method call.
+ */
+ static private int countMethodArgWords(String sig)
+ {
+ // the 'this' pointer is to be accounted too
+ return Descriptor.countMethodArgWords(sig) + 1;
+ }
+
+ /**
+ * Returns the utf8 string for the CodeAttribute.
+ */
+ private ConstUtf8 getCodeAttributeUtf8()
+ {
+ // create utf8 in constant pool if not done yet
+ if (codeAttributeUtf8 == null) {
+ codeAttributeUtf8 = pool.addUtf8(CodeAttribute.expectedAttrName);
+ }
+ return codeAttributeUtf8;
+ }
+
+ /**
+ * Returns the constant field ref for the jdoStateManager field.
+ */
+ private ConstFieldRef getjdoStateManagerFieldRef()
+ {
+ //^olsen: javac uses the truelly declaring class
+ final String pcRootName = analyzer.getPCRootClassName();
+ affirm(pcRootName != null);
+
+ // create field reference in constant pool if not done yet
+ if (jdoStateManagerFieldRef == null) {
+ jdoStateManagerFieldRef
+ = pool.addFieldRef(pcRootName, //className,
+ JDO_PC_jdoStateManager_Name,
+ JDO_PC_jdoStateManager_Sig);
+ }
+ return jdoStateManagerFieldRef;
+ }
+
+ /**
+ * Returns the constant field ref for the jdoFlags field.
+ */
+ private ConstFieldRef getjdoFlagsFieldRef()
+ {
+ //^olsen: javac uses the truelly declaring class
+ final String pcRootName = analyzer.getPCRootClassName();
+ affirm(pcRootName != null);
+
+ // create field reference in constant pool if not done yet
+ if (jdoFlagsFieldRef == null) {
+ jdoFlagsFieldRef
+ = pool.addFieldRef(pcRootName, //className,
+ JDO_PC_jdoFlags_Name,
+ JDO_PC_jdoFlags_Sig);
+ }
+ return jdoFlagsFieldRef;
+ }
+
+ /**
+ * Returns the constant field ref for the jdoFieldNames field.
+ */
+ private ConstFieldRef getjdoFieldNamesFieldRef()
+ {
+ // create field reference in constant pool if not done yet
+ if (jdoFieldNamesFieldRef == null) {
+ jdoFieldNamesFieldRef
+ = pool.addFieldRef(className,
+ JDO_PC_jdoFieldNames_Name,
+ JDO_PC_jdoFieldNames_Sig);
+ }
+ return jdoFieldNamesFieldRef;
+ }
+
+ /**
+ * Returns the constant field ref for the jdoFieldTypes field.
+ */
+ private ConstFieldRef getjdoFieldTypesFieldRef()
+ {
+ // create field reference in constant pool if not done yet
+ if (jdoFieldTypesFieldRef == null) {
+ jdoFieldTypesFieldRef
+ = pool.addFieldRef(className,
+ JDO_PC_jdoFieldTypes_Name,
+ JDO_PC_jdoFieldTypes_Sig);
+ }
+ return jdoFieldTypesFieldRef;
+ }
+
+ /**
+ * Returns the constant field ref for the jdoFieldFlags field.
+ */
+ private ConstFieldRef getjdoFieldFlagsFieldRef()
+ {
+ // create field reference in constant pool if not done yet
+ if (jdoFieldFlagsFieldRef == null) {
+ jdoFieldFlagsFieldRef
+ = pool.addFieldRef(className,
+ JDO_PC_jdoFieldFlags_Name,
+ JDO_PC_jdoFieldFlags_Sig);
+ }
+ return jdoFieldFlagsFieldRef;
+ }
+
+ /**
+ * Returns the constant field ref for the jdoPersistenceCapableSuperclass field.
+ */
+ private ConstFieldRef getjdoPersistenceCapableSuperclassFieldRef()
+ {
+ // create field reference in constant pool if not done yet
+ if (jdoPersistenceCapableSuperclassFieldRef == null) {
+ jdoPersistenceCapableSuperclassFieldRef
+ = pool.addFieldRef(className,
+ JDO_PC_jdoPersistenceCapableSuperclass_Name,
+ JDO_PC_jdoPersistenceCapableSuperclass_Sig);
+ }
+ return jdoPersistenceCapableSuperclassFieldRef;
+ }
+
+ /**
+ * Returns the constant field refs for the annotated fields.
+ */
+ private ConstFieldRef[] getAnnotatedFieldRefs()
+ {
+ // create field references in constant pool if not done yet
+ if (annotatedFieldRefs == null) {
+ final int annotatedFieldCount = analyzer.getAnnotatedFieldCount();
+ final String[] annotatedFieldNames
+ = analyzer.getAnnotatedFieldNames();
+ final String[] annotatedFieldSigs
+ = analyzer.getAnnotatedFieldSigs();
+ affirm(annotatedFieldNames.length == annotatedFieldCount);
+ affirm(annotatedFieldSigs.length == annotatedFieldCount);
+
+ // add field references to constant pool
+ annotatedFieldRefs = new ConstFieldRef[annotatedFieldCount];
+ for (int i = 0; i < annotatedFieldCount; i++) {
+ final String name = annotatedFieldNames[i];
+ final String sig = annotatedFieldSigs[i];
+ annotatedFieldRefs[i] = pool.addFieldRef(className, name, sig);
+ affirm(annotatedFieldRefs[i] != null);
+ }
+ }
+ affirm(annotatedFieldRefs != null);
+ return annotatedFieldRefs;
+ }
+
+ /**
+ * Returns the constant field refs for the key fields.
+ */
+ private ConstFieldRef[] getKeyFieldRefs()
+ {
+ // get field references if not done yet
+ if (keyFieldRefs == null) {
+ final ConstFieldRef[] annotatedFieldRefs = getAnnotatedFieldRefs();
+ final int keyFieldCount = analyzer.getKeyFieldCount();
+ final int[] keyFieldIndexes = analyzer.getKeyFieldIndexes();
+ affirm(keyFieldIndexes.length == keyFieldCount);
+
+ // add field references
+ keyFieldRefs = new ConstFieldRef[keyFieldCount];
+ for (int i = 0; i < keyFieldCount; i++) {
+ keyFieldRefs[i] = annotatedFieldRefs[keyFieldIndexes[i]];
+ affirm(keyFieldRefs[i] != null);
+ }
+ }
+ affirm(keyFieldRefs != null);
+ return keyFieldRefs;
+ }
+
+ /**
+ * Returns the constant field refs for the key fields of the key class.
+ */
+ private ConstFieldRef[] getKeyClassKeyFieldRefs()
+ {
+ // get field references if not done yet
+ if (keyClassKeyFieldRefs == null) {
+ final String keyClassName = analyzer.getKeyClassName();
+ affirm(keyClassName != null);
+ final int keyFieldCount = analyzer.getKeyFieldCount();
+ final ConstFieldRef[] keyFieldRefs = getKeyFieldRefs();
+ affirm(keyFieldRefs.length == keyFieldCount);
+
+ // add field references
+ keyClassKeyFieldRefs = new ConstFieldRef[keyFieldCount];
+ for (int i = 0; i < keyFieldCount; i++) {
+ final ConstNameAndType nt = keyFieldRefs[i].nameAndType();
+ final String name = nt.name().asString();
+ final String sig = nt.signature().asString();
+ keyClassKeyFieldRefs[i]
+ = pool.addFieldRef(keyClassName, name, sig);
+ affirm(keyClassKeyFieldRefs[i] != null);
+ }
+ }
+ affirm(keyClassKeyFieldRefs != null);
+ return keyClassKeyFieldRefs;
+ }
+
+ /**
+ * Adds the code for throwing a IllegalArgumentException.
+ */
+ private Insn appendThrowJavaException(Insn insn,
+ String exceptionName,
+ String exceptionText)
+ {
+ affirm(insn != null);
+ affirm(exceptionName != null);
+ affirm(exceptionText != null);
+
+ // throw exception
+ final String exceptionCtorName
+ = NameHelper.constructorName();
+ final String exceptionCtorSig
+ = NameHelper.constructorSig(JAVA_String_Sig);
+ insn = insn.append(
+ Insn.create(opc_new,
+ pool.addClass(exceptionName)));
+ insn = insn.append(Insn.create(opc_dup));
+ insn = insn.append(
+ InsnUtils.stringConstant(
+ exceptionText, pool));
+ insn = insn.append(
+ Insn.create(opc_invokespecial,
+ pool.addMethodRef(
+ exceptionName,
+ exceptionCtorName,
+ exceptionCtorSig)));
+ insn = insn.append(Insn.create(opc_athrow));
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the code for handling if jdoStateManager field is null.
+ */
+ private Insn appendCheckStateManager(Insn insn,
+ int argStart,
+ String exceptionName,
+ String exceptionText)
+ {
+ affirm(insn != null);
+ affirm(exceptionName != null);
+ affirm(exceptionText != null);
+
+ // throw exception if sm == null
+ final InsnTarget body = new InsnTarget();
+ insn = insn.append(InsnUtils.aLoad(argStart, pool));
+ insn = insn.append(
+ Insn.create(
+ opc_getfield,
+ getjdoStateManagerFieldRef()));
+ insn = insn.append(Insn.create(opc_ifnonnull, body));
+ insn = appendThrowJavaException(insn, exceptionName, exceptionText);
+ insn = insn.append(body);
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the code for handling if an argument is null.
+ */
+ private Insn appendCheckVarNonNull(Insn insn,
+ int argStart,
+ String exceptionName,
+ String exceptionText)
+ {
+ affirm(insn != null);
+ affirm(exceptionName != null);
+ affirm(exceptionText != null);
+
+ // throw exception if obj == null
+ final InsnTarget body = new InsnTarget();
+ insn = insn.append(InsnUtils.aLoad(argStart, pool));
+ insn = insn.append(Insn.create(opc_ifnonnull, body));
+ insn = appendThrowJavaException(insn, exceptionName, exceptionText);
+ insn = insn.append(body);
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the code for handling if an argument is instance of a class.
+ */
+ private Insn appendCheckVarInstanceOf(Insn insn,
+ int argStart,
+ ConstClass constClass,
+ String exceptionName,
+ String exceptionText)
+ {
+ affirm(insn != null);
+ affirm(constClass != null);
+ affirm(exceptionName != null);
+ affirm(exceptionText != null);
+
+ // throw exception if obj not instance of class
+ final InsnTarget body = new InsnTarget();
+ insn = insn.append(InsnUtils.aLoad(argStart, pool));
+ insn = insn.append(Insn.create(opc_instanceof, constClass));
+ insn = insn.append(Insn.create(opc_ifne, body));
+ insn = appendThrowJavaException(insn, exceptionName, exceptionText);
+ insn = insn.append(body);
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Builds an empty method (for debugging).
+ *
+ * public void XXX() {
+ * }
+ */
+ public void addNullMethod(final String methodName,
+ final String methodSig,
+ final int accessFlags)
+ {
+ // assumed nonstatic call; otherwise subtract 'this' from maxStack
+ affirm((accessFlags & ACCStatic) == 0);
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_return));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 0, // maxStack
+ countMethodArgWords(methodSig), // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+ // Generic Augmentation
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build the jdoSetStateManager method for the class.
+ *
+ * public final synchronized void jdoReplaceStateManager(javax.jdo.StateManager sm)
+ * {
+ * final javax.jdo.StateManager s = this.jdoStateManager;
+ * if (s != null) {
+ * this.jdoStateManager = s.replacingStateManager(this, sm);
+ * return;
+ * }
+ * // throws exception if not authorized
+ * JDOImplHelper.checkAuthorizedStateManager(sm);
+ * this.jdoStateManager = sm;
+ * this.jdoFlags = LOAD_REQUIRED;
+ * }
+ */
+ public void addJDOReplaceStateManager()
+ {
+ final String methodName = JDO_PC_jdoReplaceStateManager_Name;
+ final String methodSig = JDO_PC_jdoReplaceStateManager_Sig;
+ final int accessFlags = JDO_PC_jdoReplaceStateManager_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ //^olsen: exceptAttr != null ???
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // store the sm field into local var
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(
+ opc_getfield,
+ getjdoStateManagerFieldRef()));
+ insn = insn.append(Insn.create(opc_astore_2));
+
+ // test the sm field and call the sm if nonnull
+ final InsnTarget check = new InsnTarget();
+ insn = insn.append(Insn.create(opc_aload_2));
+ insn = insn.append(Insn.create(opc_ifnull, check));
+
+ // load 'this' on the stack
+ insn = insn.append(Insn.create(opc_aload_0));
+
+ // call the sm's method with 'this' and 'sm' arguments
+ insn = insn.append(Insn.create(opc_aload_2));
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(
+ new InsnInterfaceInvoke(
+ pool.addInterfaceMethodRef(
+ JDO_StateManager_Path,
+ JDO_SM_replacingStateManager_Name,
+ JDO_SM_replacingStateManager_Sig),
+ countMethodArgWords(JDO_SM_replacingStateManager_Sig)));
+
+ // put result value to sm field and return
+ insn = insn.append(
+ Insn.create(opc_putfield,
+ getjdoStateManagerFieldRef()));
+ insn = insn.append(Insn.create(opc_return));
+
+ // invoke JDOImplHelper.checkAuthorizedStateManager with 'sm' argument
+ insn = insn.append(check);
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(
+ Insn.create(opc_invokestatic,
+ pool.addMethodRef(
+ JDO_JDOImplHelper_Path,
+ JDO_JDOImplHelper_checkAuthorizedStateManager_Name,
+ JDO_JDOImplHelper_checkAuthorizedStateManager_Sig)));
+
+ // put argument value to jdoStateManager field
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(
+ Insn.create(opc_putfield,
+ getjdoStateManagerFieldRef()));
+
+ // reset flags to LOAD_REQUIRED
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(Insn.create(opc_iconst_1));
+ insn = insn.append(
+ Insn.create(opc_putfield,
+ getjdoFlagsFieldRef()));
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_return));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 4, // maxStack
+ 3, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build the jdoReplaceFlags method for the class.
+ *
+ * public final void jdoReplaceFlags()
+ * {
+ * final StateManager sm = this.jdoStateManager;
+ * if (sm != null) {
+ * this.jdoFlags = sm.replacingFlags(this);
+ * }
+ * }
+ */
+ public void addJDOReplaceFlags()
+ {
+ final String methodName = JDO_PC_jdoReplaceFlags_Name;
+ final String methodSig = JDO_PC_jdoReplaceFlags_Sig;
+ final int accessFlags = JDO_PC_jdoReplaceFlags_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // store the sm field into local var
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(
+ opc_getfield,
+ getjdoStateManagerFieldRef()));
+ insn = insn.append(Insn.create(opc_astore_1));
+
+ // test the sm field and goto end if null
+ final InsnTarget end = new InsnTarget();
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_ifnull, end));
+
+ // load 'this' on the stack
+ insn = insn.append(Insn.create(opc_aload_0));
+
+ // call the sm's method with 'this' argument
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ new InsnInterfaceInvoke(
+ pool.addInterfaceMethodRef(
+ JDO_StateManager_Path,
+ JDO_SM_replacingFlags_Name,
+ JDO_SM_replacingFlags_Sig),
+ countMethodArgWords(JDO_SM_replacingFlags_Sig)));
+
+ // put result value to flags field
+ insn = insn.append(
+ Insn.create(opc_putfield,
+ getjdoFlagsFieldRef()));
+
+ // end of method body
+ insn = insn.append(end);
+ insn = insn.append(Insn.create(opc_return));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 3, // maxStack
+ 2, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build the jdoMakeDirty method for the class.
+ *
+ * public final void jdoMakeDirty(java.lang.String fieldname)
+ * {
+ * final javax.jdo.StateManager sm = this.jdoStateManager;
+ * if (sm != null) {
+ * sm.makeDirty(this, fieldname);
+ * }
+ * }
+ */
+ public void addJDOMakeDirtyMethod()
+ {
+ final String methodName = JDO_PC_jdoMakeDirty_Name;
+ final String methodSig = JDO_PC_jdoMakeDirty_Sig;
+ final int accessFlags = JDO_PC_jdoMakeDirty_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // store the sm field into local var
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(
+ opc_getfield,
+ getjdoStateManagerFieldRef()));
+ insn = insn.append(Insn.create(opc_astore_2));
+
+ // test the sm field and goto end if null
+ final InsnTarget end = new InsnTarget();
+ insn = insn.append(Insn.create(opc_aload_2));
+ insn = insn.append(Insn.create(opc_ifnull, end));
+
+ // call the sm's method with 'this' and 'fieldname' arguments
+ insn = insn.append(Insn.create(opc_aload_2));
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(
+ new InsnInterfaceInvoke(
+ pool.addInterfaceMethodRef(
+ JDO_StateManager_Path,
+ JDO_SM_makeDirty_Name,
+ JDO_SM_makeDirty_Sig),
+ countMethodArgWords(JDO_SM_makeDirty_Sig)));
+
+ // end of method body
+ insn = insn.append(end);
+ insn = insn.append(Insn.create(opc_return));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 3, // maxStack
+ 3, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build the jdoPreSerialize method for the class.
+ *
+ * protected final void jdoPreSerialize()
+ * {
+ * final javax.jdo.StateManager sm = this.jdoStateManager;
+ * if (sm != null) {
+ * sm.preSerialize(this);
+ * }
+ * }
+ */
+ public void addJDOPreSerializeMethod()
+ {
+ final String methodName = JDO_PC_jdoPreSerialize_Name;
+ final String methodSig = JDO_PC_jdoPreSerialize_Sig;
+ final int accessFlags = JDO_PC_jdoPreSerialize_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // store the sm field into local var
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(
+ opc_getfield,
+ getjdoStateManagerFieldRef()));
+ insn = insn.append(Insn.create(opc_astore_1));
+
+ // test the sm field and goto end if null
+ final InsnTarget end = new InsnTarget();
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_ifnull, end));
+
+ // call the sm's method with 'this' argument
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ new InsnInterfaceInvoke(
+ pool.addInterfaceMethodRef(
+ JDO_StateManager_Path,
+ JDO_SM_preSerialize_Name,
+ JDO_SM_preSerialize_Sig),
+ countMethodArgWords(JDO_SM_preSerialize_Sig)));
+
+ // end of method body
+ insn = insn.append(end);
+ insn = insn.append(Insn.create(opc_return));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 2, // maxStack
+ 2, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build the writeObject method for the class.
+ *
+ * private void writeObject(java.io.ObjectOutputStream out)
+ * throws java.io.IOException
+ * {
+ * jdoPreSerialize();
+ * out.defaultWriteObject();
+ * }
+ */
+ public void addWriteObjectMethod()
+ {
+ final String methodName = JAVA_Object_writeObject_Name;
+ final String methodSig = JAVA_Object_writeObject_Sig;
+ final int accessFlags = JAVA_Object_writeObject_Mods;
+ final ExceptionsAttribute exceptAttr
+ = new ExceptionsAttribute(
+ pool.addUtf8(ExceptionsAttribute.expectedAttrName),
+ pool.addClass("java/io/IOException"));
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // call jdoPreSerialize
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(opc_invokevirtual,
+ pool.addMethodRef(
+ className,
+ JDO_PC_jdoPreSerialize_Name,
+ JDO_PC_jdoPreSerialize_Sig)));
+
+ // call out.defaultWriteObject();
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(
+ Insn.create(opc_invokevirtual,
+ pool.addMethodRef(
+ JAVA_ObjectOutputStream_Path,
+ JAVA_ObjectOutputStream_defaultWriteObject_Name,
+ JDO_PC_jdoPreSerialize_Sig)));
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_return));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 1, // maxStack
+ 2, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Adds a call to jdoPreSerialize as first statement to the existing method.
+ */
+ public void addJDOPreSerializeCall(String methodName, String methodSig)
+ {
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // invoke jdoPreSerialize
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(opc_invokevirtual,
+ pool.addMethodRef(
+ className,
+ JDO_PC_jdoPreSerialize_Name,
+ JDO_PC_jdoPreSerialize_Sig)));
+
+ // create code block to be added
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 1, // maxStack
+ 0, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+
+ augmenter.prependMethod(methodName, methodSig, codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build an interrogative method for the class.
+ */
+ public void addJDOIsPersistentMethod()
+ {
+ addJDOInterrogativeMethod(JDO_PC_jdoIsPersistent_Name,
+ JDO_PC_jdoIsPersistent_Sig,
+ JDO_PC_jdoIsPersistent_Mods,
+ JDO_SM_isPersistent_Name,
+ JDO_SM_isPersistent_Sig);
+ }
+
+ /**
+ * Build an interrogative method for the class.
+ */
+ public void addJDOIsTransactionalMethod()
+ {
+ addJDOInterrogativeMethod(JDO_PC_jdoIsTransactional_Name,
+ JDO_PC_jdoIsTransactional_Sig,
+ JDO_PC_jdoIsTransactional_Mods,
+ JDO_SM_isTransactional_Name,
+ JDO_SM_isTransactional_Sig);
+ }
+
+ /**
+ * Build an interrogative method for the class.
+ */
+ public void addJDOIsNewMethod()
+ {
+ addJDOInterrogativeMethod(JDO_PC_jdoIsNew_Name,
+ JDO_PC_jdoIsNew_Sig,
+ JDO_PC_jdoIsNew_Mods,
+ JDO_SM_isNew_Name,
+ JDO_SM_isNew_Sig);
+ }
+
+ /**
+ * Build an interrogative method for the class.
+ */
+ public void addJDOIsDeletedMethod()
+ {
+ addJDOInterrogativeMethod(JDO_PC_jdoIsDeleted_Name,
+ JDO_PC_jdoIsDeleted_Sig,
+ JDO_PC_jdoIsDeleted_Mods,
+ JDO_SM_isDeleted_Name,
+ JDO_SM_isDeleted_Sig);
+ }
+
+ /**
+ * Build an interrogative method for the class.
+ */
+ public void addJDOIsDirtyMethod()
+ {
+ addJDOInterrogativeMethod(JDO_PC_jdoIsDirty_Name,
+ JDO_PC_jdoIsDirty_Sig,
+ JDO_PC_jdoIsDirty_Mods,
+ JDO_SM_isDirty_Name,
+ JDO_SM_isDirty_Sig);
+ }
+
+ /**
+ * Build an interrogative method named methodName for the class.
+ *
+ * public boolean isXXX() {
+ * final StateManager sm = this.jdoStateManager;
+ * if (sm == null)
+ * return false;
+ * return sm.isXXXX(this);
+ * }
+ */
+ private void addJDOInterrogativeMethod(final String methodName,
+ final String methodSig,
+ final int accessFlags,
+ final String delegateName,
+ final String delegateSig)
+ {
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // store the sm field into local var
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(
+ opc_getfield,
+ getjdoStateManagerFieldRef()));
+ insn = insn.append(Insn.create(opc_astore_1));
+
+ // test the sm field and do the call if nonnull
+ InsnTarget noncall = new InsnTarget();
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_ifnull, noncall));
+
+ // call the sm's method with 'this' argument and return
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ new InsnInterfaceInvoke(
+ pool.addInterfaceMethodRef(
+ JDO_StateManager_Path,
+ delegateName,
+ delegateSig),
+ countMethodArgWords(delegateSig)));
+ insn = insn.append(Insn.create(opc_ireturn));
+
+ // return false
+ insn = insn.append(noncall);
+ insn = insn.append(Insn.create(opc_iconst_0));
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_ireturn));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 2, // maxStack
+ 2, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build an object query method for the class.
+ */
+ public void addJDOGetPersistenceManagerMethod()
+ {
+ addJDOObjectQueryMethod(JDO_PC_jdoGetPersistenceManager_Name,
+ JDO_PC_jdoGetPersistenceManager_Sig,
+ JDO_PC_jdoGetPersistenceManager_Mods,
+ JDO_SM_getPersistenceManager_Name,
+ JDO_SM_getPersistenceManager_Sig);
+ }
+
+ /**
+ * Build an object query method for the class.
+ */
+ public void addJDOGetObjectIdMethod()
+ {
+ addJDOObjectQueryMethod(JDO_PC_jdoGetObjectId_Name,
+ JDO_PC_jdoGetObjectId_Sig,
+ JDO_PC_jdoGetObjectId_Mods,
+ JDO_SM_getObjectId_Name,
+ JDO_SM_getObjectId_Sig);
+ }
+
+ /**
+ * Build an object query method for the class.
+ */
+ public void addJDOGetTransactionalObjectIdMethod()
+ {
+ addJDOObjectQueryMethod(JDO_PC_jdoGetTransactionalObjectId_Name,
+ JDO_PC_jdoGetTransactionalObjectId_Sig,
+ JDO_PC_jdoGetTransactionalObjectId_Mods,
+ JDO_SM_getTransactionalObjectId_Name,
+ JDO_SM_getTransactionalObjectId_Sig);
+ }
+
+ /**
+ * Build an object query method for the class.
+ *
+ * public final XXX jdoGetYYY()
+ * {
+ * final javax.jdo.StateManager sm = this.jdoStateManager;
+ * if (sm != null) {
+ * return sm.getYYY(this);
+ * }
+ * return null;
+ * }
+ */
+ private void addJDOObjectQueryMethod(final String methodName,
+ final String methodSig,
+ final int accessFlags,
+ final String delegateName,
+ final String delegateSig)
+ {
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // store the sm field into local var
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(
+ opc_getfield,
+ getjdoStateManagerFieldRef()));
+ insn = insn.append(Insn.create(opc_astore_1));
+
+ // test the sm field and do the call if nonnull
+ InsnTarget noncall = new InsnTarget();
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_ifnull, noncall));
+
+ // call the sm's method with 'this' argument and return
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ new InsnInterfaceInvoke(
+ pool.addInterfaceMethodRef(
+ JDO_StateManager_Path,
+ delegateName,
+ delegateSig),
+ countMethodArgWords(delegateSig)));
+ insn = insn.append(Insn.create(opc_areturn));
+
+ // return null
+ insn = insn.append(noncall);
+ insn = insn.append(Insn.create(opc_aconst_null));
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_areturn));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 2, // maxStack
+ 2, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build the jdoArrayArgumentIteration method for the class.
+ */
+ public void addJDOProvideFieldsMethod()
+ {
+ addJDOArrayArgumentIterationMethod(JDO_PC_jdoProvideFields_Name,
+ JDO_PC_jdoProvideFields_Sig,
+ JDO_PC_jdoProvideFields_Mods,
+ JDO_PC_jdoProvideField_Name,
+ JDO_PC_jdoProvideField_Sig);
+ }
+
+ /**
+ * Build the jdoArrayArgumentIteration method for the class.
+ */
+ public void addJDOReplaceFieldsMethod()
+ {
+ addJDOArrayArgumentIterationMethod(JDO_PC_jdoReplaceFields_Name,
+ JDO_PC_jdoReplaceFields_Sig,
+ JDO_PC_jdoReplaceFields_Mods,
+ JDO_PC_jdoReplaceField_Name,
+ JDO_PC_jdoReplaceField_Sig);
+ }
+
+ /**
+ * Build the jdoArrayArgumentIteration method for the class.
+ *
+ * public final void jdoXXXFields(int[] fieldnumbers)
+ * {
+ * final int n = fieldnumbers.length;
+ * for (int i = 0; i < n; i++) {
+ * this.jdoXXXField(fieldnumbers[i]);
+ * }
+ * }
+ */
+ public void addJDOArrayArgumentIterationMethod(final String methodName,
+ final String methodSig,
+ final int accessFlags,
+ final String delegateName,
+ final String delegateSig)
+ {
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // check arg
+ insn = appendCheckVarNonNull(insn, 1,
+ JAVA_IllegalArgumentException_Path,
+ "arg1");
+
+ // store the array argument length into local var
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_arraylength));
+ insn = insn.append(Insn.create(opc_istore_2));
+
+ // init loop counter and goto loop check
+ final InsnTarget loopcheck = new InsnTarget();
+ insn = insn.append(Insn.create(opc_iconst_0));
+ insn = insn.append(Insn.create(opc_istore_3));
+ insn = insn.append(Insn.create(opc_goto, loopcheck));
+
+ // loop body: call self-delegating method with array element
+ final InsnTarget loopbody = new InsnTarget();
+ insn = insn.append(loopbody);
+ insn = insn.append(Insn.create(opc_aload_0));
+
+ // select element from array argument at loop counter
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(Insn.create(opc_iload_3));
+ insn = insn.append(Insn.create(opc_iaload));
+
+ // call self-delegating method
+ insn = insn.append(
+ Insn.create(opc_invokevirtual,
+ pool.addMethodRef(
+ className,
+ delegateName,
+ delegateSig)));
+
+ // loop counter increment
+ insn = insn.append(new InsnIInc(3, 1));
+
+ // loop termination check
+ insn = insn.append(loopcheck);
+ insn = insn.append(Insn.create(opc_iload_3));
+ insn = insn.append(Insn.create(opc_iload_2));
+ insn = insn.append(Insn.create(opc_if_icmplt, loopbody));
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_return));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 3, // maxStack
+ 4, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build the sunjdoClassForName method for the class.
+ *
+ * public final Class sunjdoClassForName(java.lang.String classname)
+ * {
+ * try {
+ * return Class.forName(classname);
+ * catch (ClassNotFoundException ex) {
+ * throw new NoClassDefFoundError(ex.getMessage());
+ * }
+ * }
+ */
+ public void addSunJDOClassForNameMethod()
+ {
+ final String methodName = SUNJDO_PC_sunjdoClassForName_Name;
+ final String methodSig = SUNJDO_PC_sunjdoClassForName_Sig;
+ final int accessFlags = SUNJDO_PC_sunjdoClassForName_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // invoke the Class.forName(String) method with argument
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(opc_invokestatic,
+ pool.addMethodRef(
+ JAVA_Class_Path,
+ JAVA_Class_forName_Name,
+ JAVA_Class_forName_Sig)));
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_areturn));
+
+ // begin of exception handler
+ final InsnTarget end = new InsnTarget();
+ final InsnTarget beginHandler = end;
+ insn = insn.append(beginHandler);
+
+ // create NoClassDefFoundError with message from caught exception
+ insn = insn.append(Insn.create(opc_astore_1));
+ insn = insn.append(
+ Insn.create(opc_new,
+ pool.addClass(JAVA_NoClassDefFoundError_Path)));
+ insn = insn.append(Insn.create(opc_dup));
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(
+ Insn.create(
+ opc_invokevirtual,
+ pool.addMethodRef(
+ JAVA_Throwable_Path,
+ JAVA_Throwable_getMessage_Name,
+ JAVA_Throwable_getMessage_Sig)));
+ insn = insn.append(
+ Insn.create(
+ opc_invokespecial,
+ pool.addMethodRef(
+ JAVA_NoClassDefFoundError_Path,
+ JAVA_NoClassDefFoundError_NoClassDefFoundError_Name,
+ JAVA_NoClassDefFoundError_NoClassDefFoundError_Sig)));
+
+ // end of exception handler
+ insn = insn.append(Insn.create(opc_athrow));
+
+ // create exception table
+ final ConstClass catchType
+ = pool.addClass(JAVA_ClassNotFoundException_Path);
+ final ExceptionRange exceptionRange
+ = new ExceptionRange(begin, end, beginHandler, catchType);
+ final ExceptionTable exceptionTable
+ = new ExceptionTable();
+ exceptionTable.addElement(exceptionRange);
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 3, // maxStack
+ 3, // maxLocals
+ begin,
+ exceptionTable,
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+ // Specific Augmentation
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build the jdoGetManagedFieldCount method for the class.
+ *
+ * protected static int jdoGetManagedFieldCount()
+ * {
+ * return jdoInheritedFieldCount + X;
+ * }
+ */
+ public void addJDOGetManagedFieldCountMethod()
+ {
+ final String methodName = JDO_PC_jdoGetManagedFieldCount_Name;
+ final String methodSig = JDO_PC_jdoGetManagedFieldCount_Sig;
+ final int accessFlags = JDO_PC_jdoGetManagedFieldCount_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ final int managedFieldCount = analyzer.getManagedFieldCount();
+ affirm(managedFieldCount >= 0);
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // push total (absolute) number of managed fields
+ final boolean isPCRoot = analyzer.isAugmentableAsRoot();
+ if (isPCRoot) {
+ insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
+ }
+ else {
+ final ConstClass superConstClass = classFile.superName();
+ affirm(superConstClass != null);
+ final String superClassName = superConstClass.asString();
+ affirm(superClassName != null);
+ // call the superclass' jdoGetManagedFieldCount method
+ insn = insn.append(
+ Insn.create(opc_invokestatic,
+ pool.addMethodRef(
+ superClassName,
+ JDO_PC_jdoGetManagedFieldCount_Name,
+ JDO_PC_jdoGetManagedFieldCount_Sig)));
+ insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
+ insn = insn.append(Insn.create(opc_iadd));
+ }
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_ireturn));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ isPCRoot ? 1 : 2, // maxStack
+ 0, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Adds the initialization code for the jdoInheritedFieldCount field.
+ */
+ private Insn initJdoInheritedFieldCount(Insn insn)
+ {
+ affirm(insn != null);
+
+ // invoke jdoGetManagedFieldCount if not PCRoot class
+ final boolean isPCRoot = analyzer.isAugmentableAsRoot();
+ if (isPCRoot) {
+ insn = insn.append(Insn.create(opc_iconst_0));
+ } else {
+ final ConstClass superConstClass = classFile.superName();
+ affirm(superConstClass != null);
+ final String superClassName = superConstClass.asString();
+ affirm(superClassName != null);
+ insn = insn.append(
+ Insn.create(opc_invokestatic,
+ pool.addMethodRef(
+ superClassName,
+ JDO_PC_jdoGetManagedFieldCount_Name,
+ JDO_PC_jdoGetManagedFieldCount_Sig)));
+ }
+
+ // store to field
+ insn = insn.append(
+ Insn.create(opc_putstatic,
+ pool.addFieldRef(
+ className,
+ JDO_PC_jdoInheritedFieldCount_Name,
+ JDO_PC_jdoInheritedFieldCount_Sig)));
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the initialization code for the jdoFieldNames field.
+ */
+ private Insn initJdoFieldNames(Insn insn)
+ {
+ affirm(insn != null);
+
+ final int managedFieldCount = analyzer.getManagedFieldCount();
+ final String[] managedFieldNames = analyzer.getAnnotatedFieldNames();
+ affirm(managedFieldNames.length >= managedFieldCount);
+
+ // create array
+ affirm(NameHelper.elementPathForSig(JDO_PC_jdoFieldNames_Sig)
+ .equals(JAVA_String_Path));
+ insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
+ insn = insn.append(
+ Insn.create(opc_anewarray,
+ pool.addClass(JAVA_String_Path)));
+
+ // initialize elements
+ for (int i = 0; i < managedFieldCount; i++) {
+ insn = insn.append(Insn.create(opc_dup));
+ insn = insn.append(InsnUtils.integerConstant(i, pool));
+ final String name = managedFieldNames[i];
+ affirm(name != null);
+ insn = insn.append(
+ InsnUtils.stringConstant(name, pool));
+ insn = insn.append(Insn.create(opc_aastore));
+ }
+
+ // store to field
+ insn = insn.append(
+ Insn.create(opc_putstatic,
+ getjdoFieldNamesFieldRef()));
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the initialization code for the jdoFieldTypes field.
+ */
+ private Insn initJdoFieldTypes(Insn insn)
+ {
+ affirm(insn != null);
+
+ final int managedFieldCount = analyzer.getManagedFieldCount();
+ final String[] managedFieldSigs = analyzer.getAnnotatedFieldSigs();
+ affirm(managedFieldSigs.length >= managedFieldCount);
+
+ // create array
+ affirm(NameHelper.elementPathForSig(JDO_PC_jdoFieldTypes_Sig)
+ .equals(JAVA_Class_Path));
+ insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
+ insn = insn.append(
+ Insn.create(opc_anewarray,
+ pool.addClass(JAVA_Class_Path)));
+
+ // initialize elements
+ for (int i = 0; i < managedFieldCount; i++) {
+ insn = insn.append(Insn.create(opc_dup));
+ insn = insn.append(InsnUtils.integerConstant(i, pool));
+ final String sig = managedFieldSigs[i];
+ affirm(sig != null && sig.length() > 0);
+
+ // push the class object
+ // If the field is of primitive type then access the
+ // corresponding wrapper class' static 'TYPE' field;
+ // otherwise call generated, static method sunjdoClassForName.
+ switch (sig.charAt(0)) {
+ case 'Z':
+ // for primitive types, the wrapper's TYPE field is pushed
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ pool.addFieldRef(
+ JAVA_Boolean_Path,
+ JAVA_Boolean_TYPE_Name,
+ JAVA_Boolean_TYPE_Sig)));
+ break;
+ case 'C':
+ // for primitive types, the wrapper's TYPE field is pushed
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ pool.addFieldRef(
+ JAVA_Character_Path,
+ JAVA_Character_TYPE_Name,
+ JAVA_Character_TYPE_Sig)));
+ break;
+ case 'B':
+ // for primitive types, the wrapper's TYPE field is pushed
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ pool.addFieldRef(
+ JAVA_Byte_Path,
+ JAVA_Byte_TYPE_Name,
+ JAVA_Byte_TYPE_Sig)));
+ break;
+ case 'S':
+ // for primitive types, the wrapper's TYPE field is pushed
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ pool.addFieldRef(
+ JAVA_Short_Path,
+ JAVA_Short_TYPE_Name,
+ JAVA_Short_TYPE_Sig)));
+ break;
+ case 'I':
+ // for primitive types, the wrapper's TYPE field is pushed
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ pool.addFieldRef(
+ JAVA_Integer_Path,
+ JAVA_Integer_TYPE_Name,
+ JAVA_Integer_TYPE_Sig)));
+ break;
+ case 'J':
+ // for primitive types, the wrapper's TYPE field is pushed
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ pool.addFieldRef(
+ JAVA_Long_Path,
+ JAVA_Long_TYPE_Name,
+ JAVA_Long_TYPE_Sig)));
+ break;
+ case 'F':
+ // for primitive types, the wrapper's TYPE field is pushed
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ pool.addFieldRef(
+ JAVA_Float_Path,
+ JAVA_Float_TYPE_Name,
+ JAVA_Float_TYPE_Sig)));
+ break;
+ case 'D':
+ // for primitive types, the wrapper's TYPE field is pushed
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ pool.addFieldRef(
+ JAVA_Double_Path,
+ JAVA_Double_TYPE_Name,
+ JAVA_Double_TYPE_Sig)));
+ break;
+ case 'L':
+ // for object types, the signature is simply converted
+ // into a type name, e.g.:
+ // ldc #13 <String "java.lang.String">
+ insn = insn.append(
+ InsnUtils.stringConstant(
+ NameHelper.typeForSig(sig), pool));
+
+ // push class object using the generated helper method
+ insn = insn.append(
+ Insn.create(opc_invokestatic,
+ pool.addMethodRef(
+ className,
+ SUNJDO_PC_sunjdoClassForName_Name,
+ SUNJDO_PC_sunjdoClassForName_Sig)));
+ break;
+ case '[':
+ // for array types, the element's signature is simply
+ // converted into a type name, e.g.:
+ // ldc #10 <String "[I">
+ // ldc #15 <String "[Ljava.lang.String;">
+ insn = insn.append(
+ InsnUtils.stringConstant(
+ NameHelper.typeForPath(sig), pool));
+
+ // push class object using the generated helper method
+ insn = insn.append(
+ Insn.create(opc_invokestatic,
+ pool.addMethodRef(
+ className,
+ SUNJDO_PC_sunjdoClassForName_Name,
+ SUNJDO_PC_sunjdoClassForName_Sig)));
+ break;
+ default:
+ affirm(false, "Illegal field type: " + sig);
+ }
+
+ insn = insn.append(Insn.create(opc_aastore));
+ }
+
+ // store to field
+ insn = insn.append(
+ Insn.create(opc_putstatic,
+ getjdoFieldTypesFieldRef()));
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the initialization code for the jdoFieldFlags field.
+ */
+ private Insn initJdoFieldFlags(Insn insn)
+ {
+ affirm(insn != null);
+
+ final int managedFieldCount = analyzer.getManagedFieldCount();
+ final int[] managedFieldFlags = analyzer.getAnnotatedFieldFlags();
+ affirm(managedFieldFlags.length >= managedFieldCount);
+
+ // create array
+ affirm(NameHelper.elementSigForSig(JDO_PC_jdoFieldFlags_Sig)
+ .equals("B"));
+ insn = insn.append(InsnUtils.integerConstant(managedFieldCount, pool));
+ insn = insn.append(
+ Insn.create(opc_newarray, T_BYTE));
+
+ // initialize elements
+ for (int i = 0; i < managedFieldCount; i++) {
+ insn = insn.append(Insn.create(opc_dup));
+ insn = insn.append(InsnUtils.integerConstant(i, pool));
+ final int flags = managedFieldFlags[i];
+
+ // ensure we're using [opc_iconst_x .. opc_bipush]
+ affirm(-128 <= flags && flags < 128);
+ insn = insn.append(InsnUtils.integerConstant(flags, pool));
+ insn = insn.append(Insn.create(opc_bastore));
+ }
+
+ // store to field
+ insn = insn.append(
+ Insn.create(opc_putstatic,
+ getjdoFieldFlagsFieldRef()));
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the initialization code for the jdoPersistenceCapableSuperclass
+ * field.
+ */
+ private Insn initJdoPersistenceCapableSuperclass(Insn insn)
+ {
+ affirm(insn != null);
+
+ final String pcSuperName = analyzer.getPCSuperClassName();
+ final String pcRootName = analyzer.getPCRootClassName();
+ affirm(pcSuperName == null || pcRootName != null);
+ //final ConstClass superConstClass = classFile.superName();
+ //affirm(pcSuperName == null || superConstClass != null);
+ //affirm(pcRootName == null || superConstClass != null);
+
+ if (pcSuperName == null) {
+ insn = insn.append(Insn.create(opc_aconst_null));
+ } else {
+ // the type name is used for loading, e.g.:
+ // ldc #13 <String "java.lang.String">
+ insn = insn.append(
+ InsnUtils.stringConstant(
+ NameHelper.typeForPath(pcSuperName), pool));
+
+ //^olsen: decide on whether to use PCRoot class or superclass
+ // push class object using the generated helper method
+ insn = insn.append(
+ Insn.create(opc_invokestatic,
+ pool.addMethodRef(
+ pcRootName, //superConstClass.asString(),
+ SUNJDO_PC_sunjdoClassForName_Name,
+ SUNJDO_PC_sunjdoClassForName_Sig)));
+ }
+
+ // store to field
+ insn = insn.append(
+ Insn.create(opc_putstatic,
+ getjdoPersistenceCapableSuperclassFieldRef()));
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the code for the jdoPersistenceCapableSuperclass
+ * field.
+ */
+ private Insn registerClass(Insn insn)
+ {
+ affirm(insn != null);
+
+ final String pcRootName = analyzer.getPCRootClassName();
+ //final ConstClass superConstClass = classFile.superName();
+ //affirm(pcRootName == null || superConstClass != null);
+
+ // push the class object for this class
+ // the type name is used for loading, e.g.:
+ // ldc #13 <String "java.lang.String">
+ insn = insn.append(
+ InsnUtils.stringConstant(
+ NameHelper.typeForPath(className), pool));
+
+ //^olsen: decide on whether to use PCRoot class or superclass
+ // push class object using the generated helper method
+ insn = insn.append(
+ Insn.create(opc_invokestatic,
+ pool.addMethodRef(
+ pcRootName, //superConstClass.asString(),
+ SUNJDO_PC_sunjdoClassForName_Name,
+ SUNJDO_PC_sunjdoClassForName_Sig)));
+
+ // push the jdoFieldNames field
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ getjdoFieldNamesFieldRef()));
+
+ // push the jdoFieldTypes field
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ getjdoFieldTypesFieldRef()));
+
+ // push the jdoFieldFlags field
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ getjdoFieldFlagsFieldRef()));
+
+ // push the jdoPersistenceCapableSuperclass field
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ getjdoPersistenceCapableSuperclassFieldRef()));
+
+ // push a newly created an instance of this class or null if
+ // class is abstract
+ if (classFile.isAbstract()) {
+ insn = insn.append(Insn.create(opc_aconst_null));
+ } else {
+ final ConstClass thisConstClass = classFile.className();
+ affirm(thisConstClass != null);
+ insn = insn.append(Insn.create(opc_new, thisConstClass));
+ insn = insn.append(Insn.create(opc_dup));
+ insn = insn.append(
+ Insn.create(opc_invokespecial,
+ pool.addMethodRef(
+ className,
+ NameHelper.constructorName(),
+ NameHelper.constructorSig())));
+ }
+
+ // invoke registerClass
+ insn = insn.append(
+ Insn.create(opc_invokestatic,
+ pool.addMethodRef(
+ JDO_JDOImplHelper_Path,
+ JDO_JDOImplHelper_registerClass_Name,
+ JDO_JDOImplHelper_registerClass_Sig)));
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Build the static initialization code for the class.
+ *
+ * static
+ * {
+ * jdoInheritedFieldCount = 0 | super.jdoGetManagedFieldCount();
+ * jdoFieldNames = new String[]{ ... };
+ * jdoFieldTypes = new Class[]{ ... };
+ * jdoFieldFlags = new byte[]{ ... };
+ * jdoPersistenceCapableSuperclass = ...;
+ * javax.jdo.JDOImplHelper.registerClass(
+ * XXX.class,
+ * jdoFieldNames,
+ * jdoFieldTypes,
+ * jdoFieldFlags,
+ * jdoPersistenceCapableSuperclass,
+ * new XXX()
+ * );
+ * }
+ */
+ public void addStaticInitialization()
+ {
+ final String methodName = JAVA_clinit_Name;
+ final String methodSig = JAVA_clinit_Sig;
+ final int accessFlags = JAVA_clinit_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // initialize jdo fields
+ insn = initJdoInheritedFieldCount(insn);
+ insn = initJdoFieldNames(insn);
+ insn = initJdoFieldTypes(insn);
+ insn = initJdoFieldFlags(insn);
+ insn = initJdoPersistenceCapableSuperclass(insn);
+
+ // invoke registerClass
+ insn = registerClass(insn);
+
+ // add or extend the static initializer
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 7, // maxStack
+ 0, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+
+ if (analyzer.hasStaticInitializer()) {
+ // not end of method body
+ augmenter.prependMethod(methodName, methodSig,
+ codeAttr, exceptAttr);
+ } else {
+ // end of method body
+ insn = insn.append(Insn.create(opc_return));
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Build the jdoNewInstance method for the class.
+ *
+ * public PersistenceCapable jdoNewInstance(StateManager sm)
+ * {
+ * final XXX pc = new XXX();
+ * pc.jdoFlags = 1; // == LOAD_REQUIRED
+ * pc.jdoStateManager = sm;
+ * return pc;
+ * }
+ */
+ public void addJDONewInstanceMethod()
+ {
+ final String methodName = JDO_PC_jdoNewInstance_Name;
+ final String methodSig = JDO_PC_jdoNewInstance_Sig;
+ final int accessFlags = JDO_PC_jdoNewInstance_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // push a newly created an instance of this class
+ final ConstClass thisConstClass = classFile.className();
+ affirm(thisConstClass != null);
+ insn = insn.append(Insn.create(opc_new, thisConstClass));
+ insn = insn.append(Insn.create(opc_dup));
+ insn = insn.append(
+ Insn.create(opc_invokespecial,
+ pool.addMethodRef(
+ className,
+ NameHelper.constructorName(),
+ NameHelper.constructorSig())));
+ insn = insn.append(Insn.create(opc_astore_2));
+
+ // init jdo flags and assign argument to sm
+ insn = insn.append(Insn.create(opc_aload_2));
+ insn = insn.append(Insn.create(opc_iconst_1));
+ insn = insn.append(
+ Insn.create(opc_putfield,
+ getjdoFlagsFieldRef()));
+ insn = insn.append(Insn.create(opc_aload_2));
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(
+ Insn.create(opc_putfield,
+ getjdoStateManagerFieldRef()));
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_aload_2));
+ insn = insn.append(Insn.create(opc_areturn));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 2, // maxStack
+ 3, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ /**
+ * Build the jdoNewInstance method for the class.
+ *
+ * public PersistenceCapable jdoNewInstance(StateManager sm, Object oid)
+ * {
+ * final XXX pc = new XXX();
+ * pc.jdoCopyKeyFieldsFromObjectId(oid);
+ * pc.jdoFlags = 1; // == LOAD_REQUIRED
+ * pc.jdoStateManager = sm;
+ * return pc;
+ * }
+ */
+ public void addJDONewInstanceOidMethod()
+ {
+ final String methodName = JDO_PC_jdoNewInstance_Object_Name;
+ final String methodSig = JDO_PC_jdoNewInstance_Object_Sig;
+ final int accessFlags = JDO_PC_jdoNewInstance_Object_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // push a newly created an instance of this class
+ final ConstClass thisConstClass = classFile.className();
+ affirm(thisConstClass != null);
+ insn = insn.append(Insn.create(opc_new, thisConstClass));
+ insn = insn.append(Insn.create(opc_dup));
+ insn = insn.append(
+ Insn.create(opc_invokespecial,
+ pool.addMethodRef(
+ className,
+ NameHelper.constructorName(),
+ NameHelper.constructorSig())));
+ insn = insn.append(Insn.create(opc_astore_3));
+
+ // class on instance pc.jdoCopyKeyFieldsFromObjectId(oid)
+ //^olsen: javac uses the truelly declaring class
+ final String pcKeyOwnerClassName = analyzer.getPCKeyOwnerClassName();
+ affirm(pcKeyOwnerClassName != null);
+ insn = insn.append(Insn.create(opc_aload_3));
+ insn = insn.append(Insn.create(opc_aload_2));
+ insn = insn.append(
+ Insn.create(opc_invokevirtual,
+ pool.addMethodRef(
+ pcKeyOwnerClassName,
+ JDO_PC_jdoCopyKeyFieldsFromObjectId_Name,
+ JDO_PC_jdoCopyKeyFieldsFromObjectId_Sig)));
+
+ // init jdo flags and assign argument to sm
+ insn = insn.append(Insn.create(opc_aload_3));
+ insn = insn.append(Insn.create(opc_iconst_1));
+ insn = insn.append(
+ Insn.create(opc_putfield,
+ getjdoFlagsFieldRef()));
+ insn = insn.append(Insn.create(opc_aload_3));
+ insn = insn.append(Insn.create(opc_aload_1));
+ insn = insn.append(
+ Insn.create(opc_putfield,
+ getjdoStateManagerFieldRef()));
+
+ // end of method body
+ insn = insn.append(Insn.create(opc_aload_3));
+ insn = insn.append(Insn.create(opc_areturn));
+
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ 2, // maxStack
+ 4, // maxLocals
+ begin,
+ new ExceptionTable(),
+ new AttributeVector());
+ augmenter.addMethod(methodName, methodSig, accessFlags,
+ codeAttr, exceptAttr);
+ }
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * Adds the code for the begin of the jdoProvideField and
+ * jdoReplaceField methods.
+ */
+ private Insn appendBeginProvideReplaceField(Insn insn)
+ {
+ affirm(insn != null);
+
+ // store the sm field into local var
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(
+ Insn.create(opc_getfield,
+ getjdoStateManagerFieldRef()));
+ insn = insn.append(Insn.create(opc_astore_2));
+
+ // push (fieldnumber - jdoInheritedFieldCount)
+ insn = insn.append(Insn.create(opc_iload_1));
+ insn = insn.append(
+ Insn.create(opc_getstatic,
+ pool.addFieldRef(
+ className,
+ JDO_PC_jdoInheritedFieldCount_Name,
+ JDO_PC_jdoInheritedFieldCount_Sig)));
+ insn = insn.append(Insn.create(opc_isub));
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the default-branch code for the jdoProvideField and
+ * jdoReplaceField methods.
+ */
+ private Insn appendEndProvideReplaceField(Insn insn,
+ String provideReplaceField_Name,
+ String provideReplaceField_Sig)
+ {
+ affirm(insn != null);
+ affirm(provideReplaceField_Name);
+ affirm(provideReplaceField_Sig);
+
+ // throw exception or delegate to PC superclass
+ final boolean isPCRoot = analyzer.isAugmentableAsRoot();
+ if (isPCRoot) {
+ insn = appendThrowJavaException(insn,
+ JAVA_IllegalArgumentException_Path,
+ "arg1");
+ } else {
+ // call super.jdoProvideField(int)
+ final ConstClass superConstClass = classFile.superName();
+ affirm(superConstClass != null);
+ final String superClassName = superConstClass.asString();
+ affirm(superClassName != null);
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(Insn.create(opc_iload_1));
+ insn = insn.append(
+ Insn.create(opc_invokespecial,
+ pool.addMethodRef(
+ superClassName,
+ provideReplaceField_Name,
+ provideReplaceField_Sig)));
+ insn = insn.append(Insn.create(opc_return));
+ }
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the code for one case-branch in the jdoProvideField method.
+ */
+ private Insn appendCaseBranchForProvideField(Insn insn,
+ String providedXXXField_Name,
+ String providedXXXField_Sig,
+ ConstFieldRef managedFieldRef)
+ {
+ affirm(insn != null);
+ affirm(providedXXXField_Name != null);
+ affirm(providedXXXField_Sig != null);
+ affirm(managedFieldRef != null);
+
+ // check sm
+ insn = appendCheckVarNonNull(insn, 2,
+ JAVA_IllegalStateException_Path,
+ "arg0." + JDO_PC_jdoStateManager_Name);
+
+ // push sm and args: this, fieldnumber, and field
+ insn = insn.append(Insn.create(opc_aload_2));
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(Insn.create(opc_iload_1));
+ insn = insn.append(Insn.create(opc_aload_0));
+ insn = insn.append(Insn.create(opc_getfield, managedFieldRef));
+
+ // call providedXXXField
+ insn = insn.append(
+ new InsnInterfaceInvoke(
+ pool.addInterfaceMethodRef(
+ JDO_StateManager_Path,
+ providedXXXField_Name,
+ providedXXXField_Sig),
+ countMethodArgWords(providedXXXField_Sig)));
+
+ // return
+ insn = insn.append(Insn.create(opc_return));
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Adds the switch code for the jdoProvideField method.
+ */
+ private Insn appendSwitchForProvideField(Insn insn,
+ SizeHolder sizeHolder)
+ {
+ affirm(insn != null);
+ affirm(sizeHolder != null);
+
+ // generate the switch-statement only if more than zero fields
+ final int managedFieldCount = analyzer.getManagedFieldCount();
+ //if (managedFieldCount == 0) {
+ // return insn;
+ //}
+
+ // get types of and field references of the managed fields
+ final String[] managedFieldSigs = analyzer.getAnnotatedFieldSigs();
+ final ConstFieldRef[] managedFieldRefs = getAnnotatedFieldRefs();
+ affirm(managedFieldSigs.length >= managedFieldCount);
+ affirm(managedFieldRefs.length >= managedFieldCount);
+
+ // generate the switch
+ final int lowOp = 0;
+ final InsnTarget defaultOp = new InsnTarget();
+ final InsnTarget[] targetsOp = new InsnTarget[managedFieldCount];
+ for (int i = 0; i < managedFieldCount; i++) {
+ targetsOp[i] = new InsnTarget();
+ }
+
+ // javac prefers lookup switches for 1-element tables
+ if (managedFieldCount <= 1) {
+ final int[] matchesOp
+ = (managedFieldCount == 0 ? new int[]{} : new int[]{ lowOp });
+ insn = insn.append(
+ new InsnLookupSwitch(defaultOp, matchesOp, targetsOp));
+ } else {
+ insn = insn.append(
+ new InsnTableSwitch(lowOp, defaultOp, targetsOp));
+ }
+
+ // generate the case-targets for the method calls
+ for (int i = 0; i < managedFieldCount; i++) {
+ // target for accessing field [i]
+ insn = insn.append(targetsOp[i]);
+
+ // get signature and constant field reference for field
+ final String sig = managedFieldSigs[i];
+ final ConstFieldRef ref = managedFieldRefs[i];
+ affirm(sig != null && sig.length() > 0);
+ affirm(ref != null);
+
+ // compute stack demand
+ sizeHolder.size = max(sizeHolder.size,
+ Descriptor.countFieldWords(sig));
+
+ // generate the case-branch for a field depending on its type
+ switch (sig.charAt(0)) {
+ case 'Z':
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedBooleanField_Name,
+ JDO_SM_providedBooleanField_Sig,
+ ref);
+ break;
+ case 'C':
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedCharField_Name,
+ JDO_SM_providedCharField_Sig,
+ ref);
+ break;
+ case 'B':
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedByteField_Name,
+ JDO_SM_providedByteField_Sig,
+ ref);
+ break;
+ case 'S':
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedShortField_Name,
+ JDO_SM_providedShortField_Sig,
+ ref);
+ break;
+ case 'I':
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedIntField_Name,
+ JDO_SM_providedIntField_Sig,
+ ref);
+ break;
+ case 'J':
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedLongField_Name,
+ JDO_SM_providedLongField_Sig,
+ ref);
+ break;
+ case 'F':
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedFloatField_Name,
+ JDO_SM_providedFloatField_Sig,
+ ref);
+ break;
+ case 'D':
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedDoubleField_Name,
+ JDO_SM_providedDoubleField_Sig,
+ ref);
+ break;
+ case 'L':
+ case '[':
+ if (sig.equals(JAVA_String_Sig)) {
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedStringField_Name,
+ JDO_SM_providedStringField_Sig,
+ ref);
+ } else {
+ insn = appendCaseBranchForProvideField(
+ insn,
+ JDO_SM_providedObjectField_Name,
+ JDO_SM_providedObjectField_Sig,
+ ref);
+ }
+ break;
+ default:
+ affirm(false, "Illegal field type: " + sig);
+ }
+ }
+
+ // the default branch target comes next
+ insn = insn.append(defaultOp);
+
+ affirm(insn != null);
+ return insn;
+ }
+
+ /**
+ * Build the jdoProvideField method for the class.
+ *
+ * public void jdoProvideField(int fieldnumber)
+ * {
+ * final javax.jdo.StateManager sm = this.jdoStateManager;
+ * switch(fieldnumber - jdoInheritedFieldCount) {
+ * case 0:
+ * sm.providedXXXField(this, fieldnumber, this.yyy);
+ * return;
+ * case 1:
+ * ...
+ * default:
+ * <if (isPCRoot) {>
+ * throw new javax.jdo.JDOFatalInternalException();
+ * <} else {>
+ * super.jdoProvideField(fieldnumber);
+ * <}>
+ * }
+ * }
+ */
+ public void addJDOProvideFieldMethod()
+ {
+ final String methodName = JDO_PC_jdoProvideField_Name;
+ final String methodSig = JDO_PC_jdoProvideField_Sig;
+ final int accessFlags = JDO_PC_jdoProvideField_Mods;
+ final ExceptionsAttribute exceptAttr = null;
+
+ // begin of method body
+ final InsnTarget begin = new InsnTarget();
+ Insn insn = begin;
+
+ // generate the begin code
+ insn = appendBeginProvideReplaceField(insn);
+
+ // generate the switch code
+ final SizeHolder sizeHolder = new SizeHolder();
+ insn = appendSwitchForProvideField(insn, sizeHolder);
+
+ // generate the default-branch code with throw/return
+ insn = appendEndProvideReplaceField(insn,
+ JDO_PC_jdoProvideField_Name,
+ JDO_PC_jdoProvideField_Sig);
+
+ // end of method body
+ affirm(insn.opcode() == opc_athrow || insn.opcode() == opc_return);
+
+ affirm(0 <= sizeHolder.size && sizeHolder.size <= 2);
+ //System.out.println("sizeHolder.size = " + sizeHolder.size);
+ final int maxStack = (sizeHolder.size == 0
+ ? 3 : (sizeHolder.size == 1 ? 4 : 5));
+ final CodeAttribute codeAttr
+ = new CodeAttribute(getCodeAttributeUtf8(),
+ maxStack, // maxStack
+ 3, // maxLocals
+ begin,
+ new ExceptionTable(),
[... 2401 lines stripped ...]