/**
* 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);
}
}