Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Annotater.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Annotater.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Annotater.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Annotater.java Fri
Mar 18 17:02:29 2005
@@ -0,0 +1,354 @@
+/*
+ * 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.Iterator;
+
+import org.apache.jdo.impl.enhancer.classfile.ClassFile;
+import org.apache.jdo.impl.enhancer.classfile.ClassMethod;
+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.ConstMethodRef;
+import org.apache.jdo.impl.enhancer.classfile.ConstNameAndType;
+import org.apache.jdo.impl.enhancer.classfile.ConstantPool;
+import org.apache.jdo.impl.enhancer.classfile.Descriptor;
+import org.apache.jdo.impl.enhancer.classfile.Insn;
+import org.apache.jdo.impl.enhancer.classfile.InsnConstOp;
+import org.apache.jdo.impl.enhancer.classfile.VMConstants;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
+import org.apache.jdo.impl.enhancer.util.Support;
+
+
+
+
+
+/**
+ * Handles the augmentation actions for a method.
+ */
+class Annotater
+ extends Support
+ implements VMConstants
+{
+ /**
+ * The classfile's enhancement controller.
+ */
+ private final Controller control;
+
+ /**
+ * The class analyzer for this class.
+ */
+ private final Analyzer analyzer;
+
+ /**
+ * The classfile to be enhanced.
+ */
+ private final ClassFile classFile;
+
+ /**
+ * The class name in user ('.' delimited) form.
+ */
+ private final String userClassName;
+
+ /**
+ * The classfile's constant pool.
+ */
+ private final ConstantPool pool;
+
+ /**
+ * Repository for the enhancer options.
+ */
+ private final Environment env;
+
+ /**
+ * Repository for JDO meta-data on classes.
+ */
+ private final EnhancerMetaData meta;
+
+ /**
+ * Constructor
+ */
+ public Annotater(Controller control,
+ Analyzer analyzer,
+ Environment env)
+ {
+ affirm(control != null);
+ affirm(analyzer != null);
+ affirm(env != null);
+
+ this.control = control;
+ this.analyzer = analyzer;
+ this.env = env;
+ this.meta = env.getEnhancerMetaData();
+ this.classFile = control.getClassFile();
+ this.userClassName = classFile.userClassName();
+ this.pool = classFile.pool();
+
+ affirm(classFile != null);
+ affirm(userClassName != null);
+ affirm(meta != null);
+ affirm(pool != null);
+ }
+
+ /**
+ * Performs necessary annotation actions on the class.
+ */
+ public void annotate()
+ {
+ affirm(analyzer.isAnnotateable() && !env.noAnnotate());
+ env.message("annotating class " + userClassName);
+
+ boolean annotated = false;
+ for (final Iterator i = analyzer.getAnnotatableMethods().iterator();
+ i.hasNext();) {
+ final ClassMethod method = (ClassMethod)i.next();
+ annotated |= annotated(method);
+ }
+
+ // notify controller if class changed
+ if (annotated) {
+ control.noteUpdate();
+ }
+
+//^olsen: reenable
+/*
+ //@olsen: do special annotation if detected super.clone()
+ if ((annotate & SuperClone) != 0) {
+ //final String superName = control.classFile().superName().asString();
+ //annotateClone(method, superName);
+ }
+*/
+ }
+
+ /**
+ * Annotate the class method. For now, brute force rules.
+ */
+ private boolean annotated(ClassMethod method)
+ {
+ boolean annotated = false;
+ final CodeAttribute codeAttr = method.codeAttribute();
+ if (codeAttr == null) {
+ return annotated;
+ }
+
+ env.message(
+ "annotating: " + userClassName
+ + "." + method.name().asString()
+ + Descriptor.userMethodArgs(method.signature().asString()));
+
+ // first instruction is a target
+ final Insn firstInsn = codeAttr.theCode();
+ affirm(firstInsn.opcode() == Insn.opc_target);
+ Insn insn = firstInsn.next();
+ while (insn != null) {
+ switch(insn.opcode()) {
+ case opc_getfield:
+ case opc_putfield:
+ final Insn newInsn = insnAnnotation(insn);
+ if (insn != newInsn) {
+ annotated = true;
+ }
+ insn = newInsn;
+ break;
+ default:
+ }
+
+ insn = insn.next();
+ }
+
+ return annotated;
+ }
+
+ /**
+ * Generate annotations for put/getfield instructions.
+ */
+ private Insn insnAnnotation(final Insn insn)
+ {
+ if (false) {
+ System.out.println("MethodAnnotator.insnAnnotation(): ");
+ insn.printInsn(System.out);
+ System.out.println();
+ }
+
+ affirm(insn.opcode() == opc_getfield || insn.opcode() == opc_putfield);
+ final boolean isGet = (insn.opcode() == opc_getfield);
+
+ // get the instruction arguments
+ final InsnConstOp fieldInsn = (InsnConstOp)insn;
+ final ConstFieldRef fieldRef = (ConstFieldRef)fieldInsn.value();
+
+ final ConstNameAndType fieldNameAndType = fieldRef.nameAndType();
+ final String fieldName = fieldNameAndType.name().asString();
+ final String fieldType = fieldNameAndType.signature().asString();
+
+ final String qualifyingClassName = fieldRef.className().asString();
+ // get the field's declaring class from the model
+ final String declClassName =
+ meta.getDeclaringClass(qualifyingClassName, fieldName);
+ affirm(declClassName != null, "Cannot get declaring class of "
+ + qualifyingClassName + "." + fieldName);
+ final ConstClass declClass = pool.addClass(declClassName);
+
+ // check if field is known to be non-managed
+ if (meta.isKnownNonManagedField(declClassName, fieldName, fieldType)) {
+ return insn;
+ }
+
+ // never annotate a jdo field; such may occur in pre-enhanced clone()
+ if (meta.isPersistenceCapableClass(declClassName)
+ && (fieldName.equals(JDOConstants.JDO_PC_jdoStateManager_Name)
+ || fieldName.equals(JDOConstants.JDO_PC_jdoFlags_Name))) {
+ return insn;
+ }
+
+ if (false) {
+ System.out.println(" " + (isGet ? "get" : "put") + "field "
+ + declClassName + "." + fieldName
+ + " : " + fieldType);
+ }
+
+ final String methodName;
+ final String methodSig;
+ if (isGet) {
+ methodName = "jdoGet" + fieldName;
+ methodSig = "(L" + declClassName + ";)" + fieldType;
+ } else {
+ methodName = "jdoSet" + fieldName;
+ methodSig = "(L" + declClassName + ";" + fieldType + ")V";
+ }
+
+ if (false) {
+ System.out.println(" "
+ + declClassName + "." + methodName
+ + " : " + methodSig);
+ }
+
+ // call the PC's static accessor/mutator
+ final Insn frag = Insn.create(opc_invokestatic,
+ pool.addMethodRef(declClassName,
+ methodName,
+ methodSig));
+
+ //insn.prev().insert(Insn.create(opc_nop));
+ // replace instruction
+ final Insn prev = insn.prev();
+ insn.remove();
+
+ // replace current instruction with new fragment
+ final Insn last = prev.insert(frag);
+ return last;
+ }
+
+ private void annotateClone(ClassMethod method,
+ String superName)
+ {
+ //^olsen: extend for full support of inheritance on PC classes
+
+ if (false) {
+ final String methodName = method.name().asString();
+ final String methodSig = method.signature().asString();
+ System.out.println("annotateClone()");
+ System.out.println(" methodName = " + methodName);
+ System.out.println(" methodSig = " + methodSig);
+ System.out.println(" superName = " + superName);
+ }
+
+ final CodeAttribute codeAttr = method.codeAttribute();
+ for (Insn insn = codeAttr.theCode();
+ insn != null;
+ insn = insn.next()) {
+
+ // Found the clone method. See if it is the flavor of clone()
+ // which does a super.clone() call, and if it is, add
+ // field initializations for the jdoStateManager and jdoFlags
+ // fields.
+ if (insn.opcode() != opc_invokespecial)
+ continue;
+
+ final InsnConstOp invoke = (InsnConstOp)insn;
+ final ConstMethodRef methodRef = (ConstMethodRef)invoke.value();
+ final ConstNameAndType methodNT = methodRef.nameAndType();
+ final String methodName = methodNT.name().asString();
+ final String methodSig = methodNT.signature().asString();
+
+ if (!(methodName.equals("clone")
+ && methodSig.equals("()Ljava/lang/Object;")))
+ continue;
+
+ if (false) {
+ final ConstClass methodClass = methodRef.className();
+ final String methodClassName = methodClass.asString();
+ System.out.println(" found invocation of: "
+ + methodClassName
+ + "." + methodName + methodSig);
+ }
+
+ // check whether next instruction already is a downcast to a
+ // class implementing PersistenceCapable
+ final String thisClass = classFile.classNameString();
+ final Insn checkCastInsn = insn.next();
+ final boolean needCheckcast;
+ if (checkCastInsn.opcode() != opc_checkcast) {
+ needCheckcast = true;
+ } else {
+ ConstClass target =
+ (ConstClass) ((InsnConstOp)checkCastInsn).value();
+ if (target.asString().equals(thisClass)) {
+ insn = checkCastInsn;
+ needCheckcast = false;
+ } else {
+ needCheckcast = true;
+ }
+ }
+
+ // clear jdo fields of clone
+ {
+ // duplicate downcasted reference
+ final Insn newInsn = Insn.create(opc_dup);
+ if (needCheckcast) {
+ newInsn.append(Insn.create(opc_checkcast,
+ pool.addClass(thisClass)));
+ }
+ newInsn.append(Insn.create(opc_dup));
+
+ // clear jdo fields
+ newInsn.append(Insn.create(opc_aconst_null));
+ newInsn.append(Insn.create(
+ opc_putfield,
+ pool.addFieldRef(
+ thisClass,
+ JDOConstants.JDO_PC_jdoStateManager_Name,
+ JDOConstants.JDO_PC_jdoStateManager_Sig)));
+ newInsn.append(Insn.create(opc_iconst_0));
+ newInsn.append(Insn.create(
+ opc_putfield,
+ pool.addFieldRef(
+ thisClass,
+ JDOConstants.JDO_PC_jdoFlags_Name,
+ JDOConstants.JDO_PC_jdoFlags_Sig)));
+
+ // insert code
+ insn.insert(newInsn);
+
+ // increase stack
+ final int annotationStack = 3;
+ codeAttr.setStackUsed(codeAttr.stackUsed() + annotationStack);
+ }
+ }
+ }
+}
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Augmenter.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Augmenter.java?view=auto&rev=158176
==============================================================================
--- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Augmenter.java (added)
+++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/enhancer/core/Augmenter.java Fri
Mar 18 17:02:29 2005
@@ -0,0 +1,612 @@
+/*
+ * 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.Enumeration;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Set;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.HashMap;
+
+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.ClassMethod;
+import org.apache.jdo.impl.enhancer.classfile.CodeAttribute;
+import org.apache.jdo.impl.enhancer.classfile.ConstClass;
+import org.apache.jdo.impl.enhancer.classfile.ConstantPool;
+import org.apache.jdo.impl.enhancer.classfile.Descriptor;
+import org.apache.jdo.impl.enhancer.classfile.ExceptionsAttribute;
+import org.apache.jdo.impl.enhancer.classfile.Insn;
+import org.apache.jdo.impl.enhancer.classfile.InsnTarget;
+import org.apache.jdo.impl.enhancer.classfile.LineNumberTableAttribute;
+import org.apache.jdo.impl.enhancer.classfile.SyntheticAttribute;
+import org.apache.jdo.impl.enhancer.classfile.VMConstants;
+import org.apache.jdo.impl.enhancer.meta.EnhancerMetaData;
+import org.apache.jdo.impl.enhancer.util.Support;
+
+
+
+
+/**
+ * Handles the augmentation actions for a class.
+ */
+final class Augmenter
+ extends Support
+ implements JDOConstants
+{
+ //@olsen: fix for bug 4467428:
+ // Debugging under jdk 1.3.1 shows the problem that any breakpoints
+ // in PC classes are ignored if the added jdo methods do NOT have a
+ // non-empty line number table attribute, no matter whether the
+ // 'Synthetic' attribute is given or not. However, this doesn't
+ // seem to comply with the JVM Spec (2nd edition), which states
+ // that the synthetic attribute _must_ be specified if no source
+ // code information is available for the member:
+ //
+ // 4.7.6 The Synthetic Attribute
+ // ... A class member that does not appear in the source code must
+ // be marked using a Synthetic attribute. ...
+ //
+ // 4.7.8 The LineNumberTable Attribute
+ // The LineNumberTable attribute is an optional variable-length
+ // attribute in the attributes table of a Code (ยง4.7.3)
+ // attribute. It may be used by debuggers to determine which
+ // part of the Java virtual machine code array corresponds to a
+ // given line number in the original source file. ... Furthermore,
+ // multiple LineNumberTable attributes may together represent a
+ // given line of a source file; that is, LineNumberTable attributes
+ // need not be one-to-one with source lines.
+ //
+ // Unfortunately, if we do both, adding the synthetic attribute and
+ // a (dummy) line number table on generated methods, jdk's 1.3.1 javap
+ // fails to disassemble the classfile with an exception:
+ //
+ // sun.tools.java.CompilerError: checkOverride() synthetic
+ //
+ // So, to workaround these problems and to allow for both, debugging
+ // and disassembling with the jdk (1.3.1) tools, we pretend that the
+ // generated jdo methods have source code equivalents by
+ // - not adding the synthetic code attribute
+ // - providing a dummy line number table code attribute
+ static private final boolean addSyntheticAttr = false;
+ static private final boolean addLineNumberTableAttr = true;
+
+ /**
+ * The classfile's enhancement controller.
+ */
+ private final Controller control;
+
+ /**
+ * The class analyzer for this class.
+ */
+ private final Analyzer analyzer;
+
+ /**
+ * The classfile to be enhanced.
+ */
+ 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 method builder helper object.
+ */
+ private final Builder builder;
+
+ // public accessors
+
+ /**
+ * Constructor
+ */
+ public Augmenter(Controller control,
+ Analyzer analyzer,
+ Environment env)
+ {
+ affirm(control != null);
+ affirm(analyzer != null);
+ affirm(env != null);
+
+ this.control = control;
+ this.analyzer = analyzer;
+ this.env = env;
+ this.classFile = control.getClassFile();
+ this.className = classFile.classNameString();
+ this.userClassName = classFile.userClassName();
+ this.pool = classFile.pool();
+ this.builder = new Builder(analyzer, this, env);
+
+ affirm(classFile != null);
+ affirm(className != null);
+ affirm(userClassName != null);
+ affirm(pool != null);
+ affirm(builder != null);
+ }
+
+ // ----------------------------------------------------------------------
+
+ //^olsen: check public access modifier
+
+ /**
+ * Adds the augmentation to the class.
+ */
+ public void augment()
+ {
+ affirm(analyzer.isAugmentable() && !env.noAugment());
+ env.message("augmenting class " + userClassName);
+
+ if (analyzer.isAugmentableAsRoot()) {
+ augmentGenericJDOFields();
+ augmentGenericJDOMethods();
+ }
+ augmentClassInterface(JDO_PersistenceCapable_Path);
+ augmentSpecificJDOFields();
+ augmentSpecificJDOMethods();
+ augmentJDOAccessorMutatorMethods();
+ augmentSerializableSupportMethods();
+ }
+
+ /**
+ * Adds the specified interface to the implements clause of the class.
+ */
+ private void augmentClassInterface(String interfaceName)
+ {
+ env.message("adding: implements "
+ + ClassFile.userClassFromVMClass(interfaceName));
+
+ final ConstClass iface = pool.addClass(interfaceName);
+ classFile.addInterface(iface);
+
+ // notify controller of class change
+ control.noteUpdate();
+ }
+
+ /**
+ * Adds the generic JDO fields to the class.
+ */
+ public void augmentGenericJDOFields()
+ {
+ //protected transient javax.jdo.StateManager jdoStateManager
+ addField(
+ JDO_PC_jdoStateManager_Name,
+ JDO_PC_jdoStateManager_Sig,
+ JDO_PC_jdoStateManager_Mods);
+
+ //protected transient byte jdoFlags
+ addField(
+ JDO_PC_jdoFlags_Name,
+ JDO_PC_jdoFlags_Sig,
+ JDO_PC_jdoFlags_Mods);
+ }
+
+ /**
+ * Adds the specific JDO fields to the class.
+ */
+ public void augmentSpecificJDOFields()
+ {
+ //private static final int jdoInheritedFieldCount
+ addField(
+ JDO_PC_jdoInheritedFieldCount_Name,
+ JDO_PC_jdoInheritedFieldCount_Sig,
+ JDO_PC_jdoInheritedFieldCount_Mods);
+
+ //private static final String[] jdoFieldNames
+ addField(
+ JDO_PC_jdoFieldNames_Name,
+ JDO_PC_jdoFieldNames_Sig,
+ JDO_PC_jdoFieldNames_Mods);
+
+ //private static final Class[] jdoFieldTypes
+ addField(
+ JDO_PC_jdoFieldTypes_Name,
+ JDO_PC_jdoFieldTypes_Sig,
+ JDO_PC_jdoFieldTypes_Mods);
+
+ //private static final byte[] jdoFieldFlags
+ addField(
+ JDO_PC_jdoFieldFlags_Name,
+ JDO_PC_jdoFieldFlags_Sig,
+ JDO_PC_jdoFieldFlags_Mods);
+
+ //private static final Class jdoPersistenceCapableSuperclass
+ addField(
+ JDO_PC_jdoPersistenceCapableSuperclass_Name,
+ JDO_PC_jdoPersistenceCapableSuperclass_Sig,
+ JDO_PC_jdoPersistenceCapableSuperclass_Mods);
+ }
+
+ /**
+ * Adds a field to the class.
+ */
+ private void addField(String fieldName,
+ String fieldSig,
+ int accessFlags)
+ {
+ affirm(fieldName != null);
+ affirm(fieldSig != null);
+
+ env.message("adding: "
+ + Descriptor.userFieldSig(fieldSig)
+ + " " + fieldName);
+
+ //@olsen: fix 4467428, add synthetic attribute for generated fields
+ final AttributeVector fieldAttrs = new AttributeVector();
+ fieldAttrs.addElement(
+ new SyntheticAttribute(
+ pool.addUtf8(SyntheticAttribute.expectedAttrName)));
+
+ // create and add the field
+ final ClassField field
+ = new ClassField(accessFlags,
+ pool.addUtf8(fieldName),
+ pool.addUtf8(fieldSig),
+ fieldAttrs);
+ affirm(classFile.findField(fieldName) == null,
+ "Attempt to add a repeated field.");
+ classFile.addField(field);
+
+ // notify controller of class change
+ control.noteUpdate();
+ }
+
+ /**
+ * Adds the generic JDO methods to the class.
+ */
+ public void augmentGenericJDOMethods()
+ {
+ builder.addJDOReplaceFlags();
+ builder.addJDOIsPersistentMethod();
+ builder.addJDOIsTransactionalMethod();
+ builder.addJDOIsNewMethod();
+ builder.addJDOIsDeletedMethod();
+ builder.addJDOIsDirtyMethod();
+ builder.addJDOMakeDirtyMethod();
+ builder.addJDOPreSerializeMethod();
+ builder.addJDOGetPersistenceManagerMethod();
+ builder.addJDOGetObjectIdMethod();
+ builder.addJDOGetTransactionalObjectIdMethod();
+ builder.addJDOReplaceStateManager();
+ builder.addJDOProvideFieldsMethod();
+ builder.addJDOReplaceFieldsMethod();
+
+ builder.addSunJDOClassForNameMethod();
+
+/*
+ if (!hasCloneMethod) {
+ classFile.addMethod(
+ builder.makeJDOClone(
+ this,
+ JAVA_Object_clone_Name));
+ }
+*/
+ }
+
+ /**
+ * Adds the specific JDO methods to the class.
+ */
+ public void augmentSpecificJDOMethods()
+ {
+ // class registration
+ builder.addJDOGetManagedFieldCountMethod();
+ builder.addStaticInitialization();
+
+ // instantiation methods
+ builder.addJDONewInstanceMethod();
+ builder.addJDONewInstanceOidMethod();
+
+ // field handling methods
+ builder.addJDOProvideFieldMethod();
+ builder.addJDOReplaceFieldMethod();
+ builder.addJDOCopyFieldMethod();
+ builder.addJDOCopyFieldsMethod();
+
+ // key handling methods
+ if (analyzer.isAugmentableAsRoot()
+ || analyzer.getKeyClassName() != null) {
+ builder.addJDONewObjectIdInstanceMethod();
+ builder.addJDONewObjectIdInstanceStringMethod();
+ builder.addJDOCopyKeyFieldsToObjectIdMethod();
+ builder.addJDOCopyKeyFieldsFromObjectIdMethod();
+ builder.addJDOCopyKeyFieldsToObjectIdOIFSMethod();
+ builder.addJDOCopyKeyFieldsFromObjectIdOIFCMethod();
+ }
+
+/*
+ builder.addNullMethod(JDO_PC_jdoProvideField_Name,
+ JDO_PC_jdoProvideField_Sig,
+ JDO_PC_jdoProvideField_Mods);
+ builder.addNullMethod(JDO_PC_jdoReplaceField_Name,
+ JDO_PC_jdoReplaceField_Sig,
+ JDO_PC_jdoReplaceField_Mods);
+*/
+ }
+
+ /**
+ * Adds the JDO accessor+mutator method for a field.
+ */
+ public void augmentJDOAccessorMutatorMethod(String fieldName,
+ String fieldSig,
+ int fieldMods,
+ int fieldFlags,
+ int index)
+ {
+ affirm(fieldName != null);
+ affirm(fieldSig != null);
+ affirm((fieldMods & ACCStatic) == 0);
+ affirm((fieldFlags & CHECK_READ) == 0
+ | (fieldFlags & MEDIATE_READ) == 0);
+ affirm((fieldFlags & CHECK_WRITE) == 0
+ | (fieldFlags & MEDIATE_WRITE) == 0);
+
+ // these combinations are not supported by JDO
+ affirm((fieldFlags & CHECK_READ) == 0
+ | (fieldFlags & MEDIATE_WRITE) == 0);
+ affirm((fieldFlags & CHECK_WRITE) == 0
+ | (fieldFlags & MEDIATE_READ) == 0);
+
+ // add accessor
+ final String aName
+ = JDONameHelper.getJDO_PC_jdoAccessor_Name(fieldName);
+ final String aSig
+ = JDONameHelper.getJDO_PC_jdoAccessor_Sig(className, fieldSig);
+ final int aMods
+ = JDONameHelper.getJDO_PC_jdoAccessor_Mods(fieldMods);
+ if ((fieldFlags & CHECK_READ) != 0) {
+ builder.addJDOCheckedReadAccessMethod(aName, aSig, aMods, index);
+ } else if ((fieldFlags & MEDIATE_READ) != 0) {
+ builder.addJDOMediatedReadAccessMethod(aName, aSig, aMods, index);
+ } else {
+ builder.addJDODirectReadAccessMethod(aName, aSig, aMods, index);
+ }
+
+ // add mutator
+ final String mName
+ = JDONameHelper.getJDO_PC_jdoMutator_Name(fieldName);
+ final String mSig
+ = JDONameHelper.getJDO_PC_jdoMutator_Sig(className, fieldSig);
+ final int mMods
+ = JDONameHelper.getJDO_PC_jdoMutator_Mods(fieldMods);
+ if ((fieldFlags & CHECK_WRITE) != 0) {
+ builder.addJDOCheckedWriteAccessMethod(mName, mSig, mMods, index);
+ } else if ((fieldFlags & MEDIATE_WRITE) != 0) {
+ builder.addJDOMediatedWriteAccessMethod(mName, mSig, mMods, index);
+ } else {
+ builder.addJDODirectWriteAccessMethod(mName, mSig, mMods, index);
+ }
+ }
+
+ /**
+ * Adds the JDO accessor+mutator methods to the class.
+ */
+ public void augmentJDOAccessorMutatorMethods()
+ {
+ final int annotatedFieldCount = analyzer.getAnnotatedFieldCount();
+ final String[] annotatedFieldNames = analyzer.getAnnotatedFieldNames();
+ final String[] annotatedFieldSigs = analyzer.getAnnotatedFieldSigs();
+ final int[] annotatedFieldMods = analyzer.getAnnotatedFieldMods();
+ final int[] annotatedFieldFlags = analyzer.getAnnotatedFieldFlags();
+ affirm(annotatedFieldNames.length == annotatedFieldCount);
+ affirm(annotatedFieldSigs.length == annotatedFieldCount);
+ affirm(annotatedFieldMods.length == annotatedFieldCount);
+ affirm(annotatedFieldFlags.length == annotatedFieldCount);
+
+ for (int i = 0; i < annotatedFieldCount; i++) {
+ augmentJDOAccessorMutatorMethod(annotatedFieldNames[i],
+ annotatedFieldSigs[i],
+ annotatedFieldMods[i],
+ annotatedFieldFlags[i], i);
+ }
+ }
+
+ /**
+ *
+ */
+ public void augmentSerializableSupportMethods()
+ {
+ final EnhancerMetaData meta = env.getEnhancerMetaData();
+ final String pcSuperClassName = analyzer.getPCSuperClassName();
+
+ // Add serializable support, if
+ // - this class implements Serializable and
+ // - the pc superclass (if available) does NOT implement Serializable
+ if (meta.isSerializableClass(className) &&
+ (pcSuperClassName == null ||
+ !meta.isSerializableClass(pcSuperClassName))) {
+ // add writeObject if this class does not provide method writeObject and
+ // does not provide method writeReplace
+ if (!analyzer.hasWriteObjectMethod() &&
+ !analyzer.hasWriteReplaceMethod()) {
+ builder.addWriteObjectMethod();
+ }
+ else {
+ if (analyzer.hasWriteObjectMethod()) {
+ // add call of jdoPreSerialize to writeObject
+ builder.addJDOPreSerializeCall(
+ JAVA_Object_writeObject_Name,
+ JAVA_Object_writeObject_Sig);
+ }
+ if (analyzer.hasWriteReplaceMethod()) {
+ // add call of jdoPreSerialize to writeReplace
+ builder.addJDOPreSerializeCall(
+ JAVA_Object_writeReplace_Name,
+ JAVA_Object_writeReplace_Sig);
+ }
+ }
+ }
+ }
+
+ /**
+ * Adds a method to the class.
+ */
+ void addMethod(String methodName,
+ String methodSig,
+ int accessFlags,
+ CodeAttribute codeAttr,
+ ExceptionsAttribute exceptAttr)
+ {
+ affirm(methodName != null);
+ affirm(methodSig != null);
+ affirm(codeAttr != null);
+
+ env.message("adding: "
+ + Descriptor.userMethodResult(methodSig)
+ + " " + methodName
+ + Descriptor.userMethodArgs(methodSig));
+
+ //@olsen: fix 4467428, add dummy, non-empty line number table
+ if (addLineNumberTableAttr) {
+ // get first instruction which always is an instruction target
+ affirm(codeAttr.theCode().opcode() == Insn.opc_target);
+ final InsnTarget begin = (InsnTarget)codeAttr.theCode();
+
+ // get attributes of the code attribute
+ final AttributeVector codeSpecificAttrs = codeAttr.attributes();
+ affirm(codeSpecificAttrs != null);
+
+ // add dummy line number attribute with first instruction
+ codeSpecificAttrs.addElement(
+ new LineNumberTableAttribute(
+ pool.addUtf8(LineNumberTableAttribute.expectedAttrName),
+ new short[]{ 0 }, new InsnTarget[]{ begin }));
+ }
+
+ // add the method's code and exception attributes
+ final AttributeVector methodAttrs = new AttributeVector();
+ methodAttrs.addElement(codeAttr);
+ if (exceptAttr != null) {
+ methodAttrs.addElement(exceptAttr);
+ }
+
+ //@olsen: fix 4467428, add synthetic attribute for generated methods
+ if (addSyntheticAttr) {
+ methodAttrs.addElement(
+ new SyntheticAttribute(
+ pool.addUtf8(SyntheticAttribute.expectedAttrName)));
+ }
+
+ // create and add the method
+ final ClassMethod method
+ = new ClassMethod(accessFlags,
+ pool.addUtf8(methodName),
+ pool.addUtf8(methodSig),
+ methodAttrs);
+ affirm(classFile.findMethod(methodName, methodSig) == null,
+ "Attempt to add a repeated method.");
+ classFile.addMethod(method);
+
+ // notify controller of class change
+ control.noteUpdate();
+ }
+
+ /**
+ * Extends an exisiting method by prepending code.
+ */
+ void prependMethod(String methodName,
+ String methodSig,
+ CodeAttribute codeAttr,
+ ExceptionsAttribute exceptAttr)
+ {
+ affirm(methodName != null);
+ affirm(methodSig != null);
+ affirm(codeAttr != null);
+
+ env.message("extending: "
+ + Descriptor.userMethodResult(methodSig)
+ + " " + methodName
+ + Descriptor.userMethodArgs(methodSig));
+
+ // get method
+ final ClassMethod method = classFile.findMethod(methodName, methodSig);
+ affirm(method != null,
+ "Attempt to add code to a non-existing method.");
+
+ // check the found method
+ affirm(!method.isAbstract(),
+ "Attempt to add code to an abstract method.");
+ affirm(!method.isNative(),
+ "Attempt to add code to a native method.");
+ final CodeAttribute foundCodeAttr = method.codeAttribute();
+ affirm(foundCodeAttr != null); // by JVM spec
+
+ // prepend the new code to the current one
+ final Insn firstInsn = codeAttr.theCode();
+ affirm(firstInsn != null);
+ final Insn foundFirstInsn = foundCodeAttr.theCode();
+ affirm(foundFirstInsn != null);
+ final Insn lastInsn = firstInsn.append(foundFirstInsn);
+ affirm(lastInsn != null);
+ foundCodeAttr.setTheCode(firstInsn);
+
+ // ajust the method's stack and locals demand
+ foundCodeAttr.setStackUsed(max(foundCodeAttr.stackUsed(),
+ codeAttr.stackUsed()));
+ foundCodeAttr.setLocalsUsed(max(foundCodeAttr.localsUsed(),
+ codeAttr.localsUsed()));
+
+ // add the exception attribute or its exceptions
+ if (exceptAttr != null) {
+ affirm((exceptAttr.getExceptions().size()
+ == new HashSet(exceptAttr.getExceptions()).size()),
+ "Exception attribute contains duplicate exceptions.");
+
+ final ExceptionsAttribute foundExceptAttr
+ = method.exceptionsAttribute();
+ if (foundExceptAttr == null) {
+ // add the exception attribute
+ final AttributeVector methodAttrs = method.attributes();
+ affirm(methodAttrs != null);
+ methodAttrs.addElement(exceptAttr);
+ } else {
+ // add those exceptions not already present
+ final List foundEx = foundExceptAttr.getExceptions();
+ final List newEx = exceptAttr.getExceptions();
+ newEx.removeAll(foundEx);
+ foundEx.addAll(newEx);
+ }
+ }
+
+ // notify controller of class change
+ control.noteUpdate();
+ }
+
+ static private int max(int i, int j)
+ {
+ return (i < j) ? j : i;
+ }
+}
|