Package org.objectweb.speedo.generation.enhancer.pc

Source Code of org.objectweb.speedo.generation.enhancer.pc.FieldAccessorsAdder

/**
* Copyright (C) 2001-2005 France Telecom R&D
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/
package org.objectweb.speedo.generation.enhancer.pc;

import org.objectweb.asm.ClassVisitor;
import org.objectweb.asm.CodeVisitor;
import org.objectweb.asm.Label;
import org.objectweb.asm.Type;
import org.objectweb.speedo.genclass.api.SpeedoGenClassCoherence;
import org.objectweb.speedo.genclass.api.SpeedoGenClassListener;
import org.objectweb.speedo.generation.api.SpeedoCompilerParameter;
import org.objectweb.speedo.generation.enhancer.common.Util;
import org.objectweb.speedo.generation.generator.lib.AbstractSpeedoGenerator.Field;
import org.objectweb.speedo.generation.lib.NamingRules;
import org.objectweb.speedo.lib.Personality;
import org.objectweb.speedo.metadata.SpeedoClass;
import org.objectweb.speedo.metadata.SpeedoField;
import org.objectweb.speedo.mim.api.DetachedLifeCycle;
import org.objectweb.util.monolog.api.Logger;

import java.util.Iterator;
import java.util.List;
import java.util.Map;

/**
* Generates the speedo accessors (static and normal) for each persistent field
* of the class. It generates also setter for coherency management of relation.
*
* @author S.Chassande-Barrioz
*/
public class FieldAccessorsAdder
    extends AbstractPCModifier
    implements POVariableNames {

    public FieldAccessorsAdder(ClassVisitor classVisitor,
            Logger logger,
            SpeedoClass sc,
            SpeedoCompilerParameter cp,
            Personality p) {
        super(classVisitor, logger, sc, cp, p);
    }
   
    public void visit(final int version,
            final int access,
              final String name,
              final String superName,
              final String[] interfaces,
              final String sourceFile) {
        Map ctx = getGenerationContext();
        boolean needSpeedoGenClassListener = ((Boolean) ctx
                .get("needSpeedoGenClassListener")).booleanValue();
       
        String[] itfs;
        //indicate the number of new interface to add
        if (needSpeedoGenClassListener) {
            if (interfaces != null && interfaces.length > 0) {
                itfs = new String[interfaces.length + 1];
                System.arraycopy(interfaces, 0, itfs, 1, interfaces.length);
            } else {
                itfs = new String[1];
            }
            itfs[0] =  Type.getInternalName(SpeedoGenClassListener.class);
        } else {
            itfs = interfaces;
        }
        cv.visit(version, access, name, superName, itfs, sourceFile);
        final List fields = (List) ctx.get("fields");
        final int nbfields = fields.size();
        for (Iterator iter = fields.iterator(); iter.hasNext();) {
            Field f = (Field) iter.next();
            final String ftd = f.jvmType;
            Type ft = Type.getType(ftd);
            generateStaticFieldGetter(f, ft);
            generateStaticFieldSetter(f, ft);
            generateFieldGetter(f, ft, ftd, nbfields);
            generateFieldSetter(f, ft, ftd, nbfields);
            if (f.getCoherentSetter() != null) {
                generateCoherenceFieldSetter(f, ft, ftd, nbfields);
            }
        }
        if (needSpeedoGenClassListener) {
            generateSpeedoElementAddedMethod();
            generateSpeedoElementRemovedMethod();
        }
    }

    private void generateStaticFieldGetter(Field f, Type ft) {
        //public final static ${f.memoryType} ${f.getter}(${baseClassName} instance) {
        CodeVisitor mv;
        mv = cv.visitMethod(ACC_PUBLIC + ACC_FINAL + ACC_STATIC,
                f.getGetter(),
                "(" + getJVMType(classToWrite) + ")" + ft.getDescriptor(), null, null);
        //return instance.${f.getter}();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite,
                f.getGetter(), "()" +  ft.getDescriptor());
        mv.visitInsn(ft.getOpcode(IRETURN));
        mv.visitMaxs(0, 0);
    }
    private void generateStaticFieldSetter(Field f, Type ft) {
        //public final static void ${f.setter}(${baseClassName} instance, ${f.memoryType} val) {
        CodeVisitor mv;
        mv = cv.visitMethod(ACC_PUBLIC + ACC_FINAL + ACC_STATIC, f.getSetter(),
                "(" + getJVMType(classToWrite) + ft.getDescriptor() + ")V", null, null);
        //instance.${f.setter}(val);
        mv.visitVarInsn(ALOAD, 0); //Class instance
        mv.visitVarInsn(ft.getOpcode(ILOAD), 1); //field
        mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, f.getSetter(),
                "(" + ft.getDescriptor() + ")V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
    }
    private void generateFieldGetter(Field f, Type ft, String ftd, int nbField) {
        CodeVisitor mv;
        mv = cv.visitMethod(ACC_PUBLIC, f.getGetter(), "()" + ftd, null, null);
        if (f.isReference) {
            // if ( (speedoReferenceState != null)
            generateGetRefState(mv, false);
            Label l1 = new Label();
            mv.visitJumpInsn(IFNULL, l1);
            // && (speedoReferenceState.getDetachedStatus() != DetachedLifeCycle.DETACHED_NONE)
            generateGetRefState(mv, false);
            mv.visitMethodInsn(INVOKEVIRTUAL, xfieldsAncestorJCN, "getDetachedStatus", "()B");
            Util.visitIntConstant(mv, DetachedLifeCycle.DETACHED_NONE);
            mv.visitInsn(I2B);
            mv.visitJumpInsn(IF_ICMPEQ, l1);
            // && !(($classNameFields) speedoReferenceState).${f.name}Loaded
            generateGetRefState(mv, true);
            mv.visitFieldInsn(GETFIELD, xfieldsJCN, f.getName() + "Loaded", "Z");
            mv.visitJumpInsn(IFNE, l1);
            {
                mv.visitTypeInsn(NEW, personality.getDetachedFieldAccessExceptionClassNameSlash());
                mv.visitInsn(DUP);
                mv.visitLdcInsn("Field " + f.getName() + " cannot be accessed: not loaded when the object has been detached");
                mv.visitMethodInsn(INVOKESPECIAL, personality.getDetachedFieldAccessExceptionClassNameSlash(), "<init>", "(Ljava/lang/String;)V");
                mv.visitInsn(ATHROW);
            }
            mv.visitLabel(l1);
        }
       
        //StateItf sa = this.speedoReadIntention(new long[] { ... });
        mv.visitVarInsn(ALOAD, 0);
        generateFieldIdAsLongArray(f, nbField, mv);
        mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, "speedoReadIntention",
                "([J)" + JT_STATE);
        mv.visitTypeInsn(CHECKCAST, xfieldsJCN);
        mv.visitVarInsn(ASTORE, 1);

        //return sa.f1;
        mv.visitVarInsn(ALOAD, 1);
        mv.visitFieldInsn(GETFIELD, xfieldsJCN, f.getName(), ftd);
        mv.visitInsn(ft.getOpcode(IRETURN));
        mv.visitMaxs(0, 0);
    }

    private void generateFieldSetter(Field f, Type ft, String ftd, int nbField) {
        CodeVisitor mv;
        int nextLocalVarIdx = 1 + ft.getSize();
        mv = cv.visitMethod(ACC_PUBLIC, f.getSetter(), "(" + ftd + ")V", null, null);

        //if (!speedoIsActive()) {
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, ISACTIVE_FIELD_NAME, "()Z");
        Label l1 = new Label();
        mv.visitJumpInsn(IFNE, l1);
        {
            //if(speedoReferenceState.getDetachedStatus() != DetachedLifeCycle.DETACHED_NONE) {
            generateGetRefState(mv, false);
            mv.visitMethodInsn(INVOKEVIRTUAL, xfieldsAncestorJCN, "getDetachedStatus", "()B");
            Util.visitIntConstant(mv, DetachedLifeCycle.DETACHED_NONE);
            mv.visitInsn(I2B);
            Label l3 = new Label();
            mv.visitJumpInsn(IF_ICMPEQ, l3);
            {
                //if (!(($classNameFields) speedoReferenceState).${f.name}Loaded ) {
                generateGetRefState(mv, true);
                mv.visitFieldInsn(GETFIELD, xfieldsJCN, f.getName() + "Loaded", "Z");
                Label l5 = new Label();
                mv.visitJumpInsn(IFNE, l5);
                {
                    //throw new DetachedFieldAccessException("Field $f.name cannot be accessed: not loaded when the object has been detached");
                    mv.visitTypeInsn(NEW, personality.getDetachedFieldAccessExceptionClassNameSlash());
                    mv.visitInsn(DUP);
                    mv.visitLdcInsn("Field " + f.getName()
                            + " cannot be accessed: not loaded when the object has been detached");
                    mv.visitMethodInsn(INVOKESPECIAL, personality.getDetachedFieldAccessExceptionClassNameSlash(), "<init>", "(Ljava/lang/String;)V");
                    mv.visitInsn(ATHROW);
                }
                mv.visitLabel(l5);
                //mark the detached copy as dirty
                //speedoReferenceState.setDetachedStatus(DetachedLifeCycle.DETACHED_DIRTY);
                generateGetRefState(mv, false);
                Util.visitIntConstant(mv, DetachedLifeCycle.DETACHED_DIRTY);
                mv.visitInsn(I2B);
                mv.visitMethodInsn(INVOKEVIRTUAL, xfieldsAncestorJCN, "setDetachedStatus", "(B)V");
            }
            mv.visitLabel(l3);
            //(($classNameFields) speedoReferenceState).${f.name} = val;
            generateGetRefState(mv, true);
            mv.visitVarInsn(ft.getOpcode(ILOAD), 1);
            mv.visitFieldInsn(PUTFIELD, xfieldsJCN, f.getName(), ftd);

            //return
            mv.visitInsn(RETURN);
        }

        mv.visitLabel(l1);
        //The po is activated
        //Logger logger = ((org.objectweb.jorm.util.api.Loggable) getPClassMapping()).getLogger();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, "getPClassMapping",
                "()Lorg/objectweb/jorm/api/PClassMapping;");
        mv.visitTypeInsn(CHECKCAST, "org/objectweb/jorm/util/api/Loggable");
        mv.visitMethodInsn(INVOKEINTERFACE, "org/objectweb/jorm/util/api/Loggable",
                "getLogger", "()Lorg/objectweb/util/monolog/api/Logger;");
        final int loggerIdx = nextLocalVarIdx;
        nextLocalVarIdx++;
        mv.visitVarInsn(ASTORE, loggerIdx);

        //$classNameFields state = ($classNameFields) speedoWriteIntention(${f.jormFielIdDecl});
        mv.visitVarInsn(ALOAD, 0);
        generateFieldIdAsLongArray(f, nbField, mv);
        mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, "speedoWriteIntention",
                "([J)" + JT_STATE);
        mv.visitTypeInsn(CHECKCAST, xfieldsJCN);
        final int stateIdx = nextLocalVarIdx;
        nextLocalVarIdx++;
        mv.visitVarInsn(ASTORE, stateIdx);

        if (f.getIsReference()) {
            generateReferenceSetter(f, ft, nbField, loggerIdx, stateIdx, nextLocalVarIdx, mv);
        } else {
            mv.visitVarInsn(ALOAD, stateIdx);
            mv.visitVarInsn(ft.getOpcode(ILOAD), 1);
            mv.visitFieldInsn(PUTFIELD, xfieldsJCN, f.getName(), ftd);
        }
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
    }
    /**
     * Generate the part of the setter concerning reference (the field is a
     * reference
     * @param f is the Field descriptor
     * @param ft is the field type
     * @param nbField is the total number of field. This value permits to know
     * the size of the long[] to pass on the speedoWriteIntention call
     * @param loggerIdx is the register number of the logger local variable
     * @param mv is the code vistor of the setter method where the code
     * dedicated to the reference, has to be generated.
     */
    private void generateReferenceSetter(Field f,
            Type ft,
            int nbField,
            int loggerIdx,
            int stateIdx,
            int nextLocalVarIdx,
            CodeVisitor mv) {
        //if (val == state.${f.name}) {
        mv.visitVarInsn(ALOAD, 1);
        mv.visitVarInsn(ALOAD, stateIdx);
        mv.visitFieldInsn(GETFIELD, xfieldsJCN, f.getName(), ft.getDescriptor());
        Label l12 = new Label();
        mv.visitJumpInsn(IF_ACMPNE, l12);
        {
            mv.visitInsn(RETURN);
        }
        mv.visitLabel(l12);
        Label labelEnd = new Label();
        //if (val == null) {
        mv.visitVarInsn(ALOAD, 1);
        Label labelElse = new Label();
        mv.visitJumpInsn(IFNONNULL, labelElse);
        nextLocalVarIdx = generateAssignNullInSetter(f, ft, stateIdx, nextLocalVarIdx, mv);
        mv.visitJumpInsn(GOTO, labelEnd);
        mv.visitLabel(labelElse);
        nextLocalVarIdx = generateAssignNotNullInSetter(f, ft, loggerIdx, stateIdx, nextLocalVarIdx, mv);
        mv.visitLabel(labelEnd);
    }

    /**
     * Generate the byte code corresponding to a part of the setter method.
     * This part is the assignement to a null value to a reference field.
     * #see generateReferenceSetter 
     * @param stateIdx is the number of the register where is stored the
     * reference to the state (XXXFields instance).
     * @param nextLocalVarIdx is the next register availlable for declaring a
     * local variable
     * @return the next register availlable for declaring a local variable.
     */
    private int generateAssignNullInSetter(Field f, Type ft,
            int stateIdx,
            int nextLocalVarIdx,
            CodeVisitor mv) {
        //state.${f.name}PName = null;
        mv.visitVarInsn(ALOAD, stateIdx);
        mv.visitInsn(ACONST_NULL);
        mv.visitFieldInsn(PUTFIELD, xfieldsJCN, f.getName() + "PName",
                "Lorg/objectweb/jorm/naming/api/PName;");
        if (f.isMultiValued) {
            Label l31 = new Label();
            mv.visitVarInsn(ALOAD, stateIdx);
            mv.visitFieldInsn(GETFIELD, xfieldsJCN, f.getName(), ft.getDescriptor());
            mv.visitJumpInsn(IFNULL, l31);
            //if (state.${f.name} != null) {
            {
                //((SpeedoGenClassPO) state.${f.name}).setElements(null);
                mv.visitVarInsn(ALOAD, stateIdx);
                mv.visitFieldInsn(GETFIELD, xfieldsJCN, f.getName(), ft.getDescriptor());
                mv.visitTypeInsn(CHECKCAST, JCN_GCPO);
                mv.visitInsn(ACONST_NULL);
                mv.visitMethodInsn(INVOKEINTERFACE, JCN_GCPO, "setElements",
                        "(Ljava/lang/Object;)V");
            } //else state.${f.name} is null then there is no generic class
            mv.visitLabel(l31);
        } else {
            mv.visitVarInsn(ALOAD, stateIdx);
            mv.visitInsn(ACONST_NULL);
            mv.visitFieldInsn(PUTFIELD, xfieldsJCN, f.getName(), ft.getDescriptor());
        }
        return nextLocalVarIdx;
    }

    /**
     * Generate the byte code corresponding to a part of the setter method.
     * This part is the assignement to a non null value to a reference field.
     * #see generateReferenceSetter
     * @param loggerIdx is the number of the register where is stored the logger
     * @param stateIdx is the number of the register where is stored the
     * reference to the state (XXXFields instance).
     * @param nextLocalVarIdx is the next register availlable for declaring a
     * local variable
     * @return the next register availlable for declaring a local variable.
     */
    private int generateAssignNotNullInSetter(Field f,
            Type ft,
            int loggerIdx,
            int stateIdx,
            int nextLocalVarIdx,
            CodeVisitor mv) {
        if (f.isMultiValued) {
            //The field '${f.name}' is a multivalued reference
            //if (state.${f.name} == null) {
            Label l32 = new Label();
            mv.visitVarInsn(ALOAD, stateIdx);
            mv.visitFieldInsn(GETFIELD, xfieldsJCN, f.getName(), ft.getDescriptor());
            mv.visitJumpInsn(IFNONNULL, l32);
            {
                //Allocate a new ${f.gc}
                //state.initGC${f.name}(logger);
                mv.visitVarInsn(ALOAD, stateIdx);
                mv.visitVarInsn(ALOAD, loggerIdx);
                mv.visitMethodInsn(INVOKEVIRTUAL, xfieldsJCN,
                        "initGC" + f.getName(),
                        "(Lorg/objectweb/util/monolog/api/Logger;)V");
            }
            mv.visitLabel(l32);
        } else {
            //The field '${f.name}' is a simple reference
            //state.${f.name} = val;
            mv.visitVarInsn(ALOAD, stateIdx);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitFieldInsn(PUTFIELD, xfieldsJCN, f.getName(), ft.getDescriptor());
        }

        //PersistentObjectItf sp = (PersistentObjectItf) state.${f.name};
        mv.visitVarInsn(ALOAD, stateIdx);
        mv.visitFieldInsn(GETFIELD, xfieldsJCN, f.getName(), ft.getDescriptor());
        mv.visitTypeInsn(CHECKCAST, JCN_PO);
        final int spIdx = nextLocalVarIdx;
        nextLocalVarIdx++;
        mv.visitVarInsn(ASTORE, spIdx);

        //if (!sp.speedoIsActive()) {
        mv.visitVarInsn(ALOAD, spIdx);
        mv.visitMethodInsn(INVOKEINTERFACE,JCN_PO, ISACTIVE_FIELD_NAME, "()Z");
        Label l20 = new Label();
        mv.visitJumpInsn(IFNE, l20);
        {
            //speedoGetPOManager().speedoMakePersistent(sp, null);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite,
                    "speedoGetPOManager",
                    "()" + JT_POM);
            mv.visitVarInsn(ALOAD, spIdx);
            mv.visitInsn(ACONST_NULL);
            mv.visitMethodInsn(INVOKEINTERFACE, JCN_POM,
                    "speedoMakePersistent", "(" + JT_PO + "Ljava/util/Map;)Ljava/lang/Object;");
            mv.visitInsn(POP);
        }
        mv.visitLabel(l20);
        //state.${f.name}PName = sp.getPName();
        mv.visitVarInsn(ALOAD, stateIdx);
        mv.visitVarInsn(ALOAD, spIdx);
        mv.visitMethodInsn(INVOKEINTERFACE, JCN_PO, "getPName",
                "()Lorg/objectweb/jorm/naming/api/PName;");
        mv.visitFieldInsn(PUTFIELD, xfieldsJCN, f.getName() + "PName",
                "Lorg/objectweb/jorm/naming/api/PName;");
        if (f.isMultiValued) {
            //Assign values after the po initialization
            //((SpeedoGenClassPO) state.${f.name}).setElements(val);
            mv.visitVarInsn(ALOAD, stateIdx);
            mv.visitFieldInsn(GETFIELD, xfieldsJCN, f.getName(), ft.getDescriptor());
            mv.visitTypeInsn(CHECKCAST, JCN_GCPO);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKEINTERFACE, JCN_GCPO, "setElements",
                    "(Ljava/lang/Object;)V");
        }
        return nextLocalVarIdx;
    }
    private void generateCoherenceFieldSetter(Field f, Type ft, String ftd, int nbField) {
        CodeVisitor mv;
        mv = cv.visitMethod(ACC_PUBLIC, f.getCoherentSetter(), "(" + ftd + ")V", null, null);
        if (f.getIs11Relation()) {
            generateCoherenceFieldSetter11(f, ft, ftd, nbField, mv);
        } else if (f.getIsM1Relation()) {
            generateCoherenceFieldSetterM1(f, ft, ftd, nbField, mv);
        } else if (f.getIsxMRelation()) {
            //The coherency management is done on the GenClass implementation
            // by the setElements method (see the normal setter)
           
            //${f.setter}(val);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ft.getOpcode(ILOAD), 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, f.getSetter(),
                    "(" + ftd + ")V");
        }
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
    }
    private void generateCoherenceFieldSetter11(Field f, Type ft, String ftd, int nbField, CodeVisitor mv) {
        //${f.memoryType} oldVal = ${f.getter}();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, f.getGetter(), "()" + ftd);
        mv.visitVarInsn(ASTORE, 2);

        //if (oldVal != val) {
        mv.visitVarInsn(ALOAD, 2);
        mv.visitVarInsn(ALOAD, 1);
        Label l2 = new Label();
        mv.visitJumpInsn(IF_ACMPEQ, l2);
        {
            //The assigned value is different from the current
            //if (oldVal != null) {
            mv.visitVarInsn(ALOAD, 2);
            Label l4 = new Label();
            mv.visitJumpInsn(IFNULL, l4);
            {
                //The old value is not null ==> set the reverse field to because
                // it does not reference anymore 'this' because this references
                // another stuff.
                //oldVal.${f.reverseSetter}(null);
                mv.visitVarInsn(ALOAD, 2);
                mv.visitInsn(ACONST_NULL);
                mv.visitMethodInsn(INVOKEVIRTUAL, ft.getInternalName(),
                        f.getReverseSetter(),
                        "(" + getJVMType(classToWrite) + ")V");
            }
            //if (val != null) {
            mv.visitLabel(l4);
            mv.visitVarInsn(ALOAD, 1);
            Label l6 = new Label();
            mv.visitJumpInsn(IFNULL, l6);
            {
                //The new value is not null ==> set the reverse field to this
                // because this reference the new value
                //${baseClassName} reverse = val.${f.reverseGetter}();
                mv.visitVarInsn(ALOAD, 1);
                mv.visitMethodInsn(INVOKEVIRTUAL, ft.getInternalName(),
                        f.getReverseGetter(), "()" + getJVMType(classToWrite));
                mv.visitVarInsn(ASTORE, 3);
                //if (reverse != null) {
                mv.visitVarInsn(ALOAD, 3);
                Label l9 = new Label();
                mv.visitJumpInsn(IFNULL, l9);
                {
                    //reverse.${f.setter}(null);
                    mv.visitVarInsn(ALOAD, 3);
                    mv.visitInsn(ACONST_NULL);
                    mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite,
                            f.getSetter(), "(" + ftd + ")V");
                }
                //val.${f.reverseSetter}(this);
                mv.visitLabel(l9);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitVarInsn(ALOAD, 0);
                mv.visitMethodInsn(INVOKEVIRTUAL, ft.getInternalName(),
                        f.getReverseSetter(),
                        "(" + getJVMType(classToWrite) + ")V");
            }
            //Assign the value
            //${f.setter}(val);
            mv.visitLabel(l6);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, f.getSetter(),
                    "(" + ftd + ")V");
        }
        mv.visitLabel(l2);
    }
    private void generateCoherenceFieldSetterM1(Field f, Type ft, String ftd, int nbField, CodeVisitor mv) {
        //${f.memoryType} oldVal = ${f.getter}();
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, f.getGetter(), "()" + ftd);
        mv.visitVarInsn(ASTORE, 2);
       
        //if (oldVal != val) {
        mv.visitVarInsn(ALOAD, 2);
        mv.visitVarInsn(ALOAD, 1);
        Label l2 = new Label();
        mv.visitJumpInsn(IF_ACMPEQ, l2);
        {
            //remove this from reverse collection
            //if (oldVal != null) {
            mv.visitVarInsn(ALOAD, 2);
            Label labelOldValIsNull = new Label();
            mv.visitJumpInsn(IFNULL, labelOldValIsNull);
            {
                //((SpeedoGenClassCoherence)oldVal.${f.reverseGetter}())
                //    .speedoRemove(this, ${f.reverseKeyField});
                mv.visitVarInsn(ALOAD, 2);
                mv.visitMethodInsn(INVOKEVIRTUAL, ft.getInternalName(),
                        f.getReverseGetter(), "()"
                        + f.reverseField.type);
                mv.visitTypeInsn(CHECKCAST, getJVMClassName(SpeedoGenClassCoherence.class));
               
                mv.visitVarInsn(ALOAD, 0);
                if (f.getReverseIsMap()) {
                    SpeedoField sf = f.reverseKField;
                    mv.visitVarInsn(ALOAD, 0);
                    mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite,
                            NamingRules.getterName(sf), "()" + sf.type);
                } else {
                    mv.visitInsn(ACONST_NULL);
                }
                mv.visitMethodInsn(INVOKEINTERFACE,
                        getJVMClassName(SpeedoGenClassCoherence.class),
                        "speedoRemove",
                        "(Ljava/lang/Object;Ljava/lang/Object;)Z");
                mv.visitInsn(POP);
            }
            mv.visitLabel(labelOldValIsNull);
           
            //assign reference
            //${f.setter}(val);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKEVIRTUAL, classToWrite, f.getSetter(),
                    "(" + ftd + ")V");

            //add this from reverse collection
            //if (val != null) {
            mv.visitVarInsn(ALOAD, 1);
            Label labelValIsNull = new Label();
            mv.visitJumpInsn(IFNULL, labelValIsNull);
            {
                //${f.accessorClassName}.speedoAdd(this, ${f.reverseNumber}, (PersistentObjectItf) val);// ${f.reverse}
                mv.visitVarInsn(ALOAD, 0);
                Util.visitIntConstant(mv, f.reverseNumber);
                mv.visitVarInsn(ALOAD, 1);
                mv.visitTypeInsn(CHECKCAST, JCN_PO);
                mv.visitMethodInsn(INVOKESTATIC,
                        getJVMClassName(f.accessorClassName),
                        "speedoAdd", "(Ljava/lang/Object;I" + JT_PO + ")V");
            }
            mv.visitLabel(labelValIsNull);
        }
        mv.visitLabel(l2);
    }
    private void generateSpeedoElementAddedMethod() {
        CodeVisitor mv;
        mv = cv.visitMethod(ACC_PUBLIC, "speedoElementAdded",
                "(Ljava/lang/Object;I)V", null, null);
        //${classNameFields}.speedoElementAdded(elem, gcid, this);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitVarInsn(ILOAD, 2);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESTATIC, xfieldsJCN, "speedoElementAdded",
                "(Ljava/lang/Object;I" + JT_PO + ")V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
    }
    private void generateSpeedoElementRemovedMethod() {
        CodeVisitor mv;
        mv = cv.visitMethod(ACC_PUBLIC, "speedoElementRemoved",
                "(Ljava/lang/Object;I)V", null, null);
        //${classNameFields}.speedoElementRemoved(elem, gcid, this);
        mv.visitVarInsn(ALOAD, 1);
        mv.visitVarInsn(ILOAD, 2);
        mv.visitVarInsn(ALOAD, 0);
        mv.visitMethodInsn(INVOKESTATIC, xfieldsJCN, "speedoElementRemoved",
                "(Ljava/lang/Object;I" + JT_PO + ")V");
        mv.visitInsn(RETURN);
        mv.visitMaxs(0, 0);
    }
}
TOP

Related Classes of org.objectweb.speedo.generation.enhancer.pc.FieldAccessorsAdder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.