MethodAnnotaterpublic class MethodAnnotater extends com.sun.jdo.api.persistence.enhancer.util.Support implements AnnotationConstantsMethodAnnotater controls the code annotation for a single method
within a class. |
Fields Summary |
---|
private final ClassAction | ca | private final ClassMethod | method | private final ConstantPool | pool | private final Environment | env | private int | annotate | private Vector | tmpRegisters | private Vector | tmpDoubleRegisters | private short | annotationStack | private Map | insnNotes |
Constructors Summary |
---|
MethodAnnotater(ClassAction ca, ClassMethod method, Environment env)Constructor
this.ca = ca;
this.method = method;
this.env = env;
this.pool = ca.classFile().pool();
|
Methods Summary |
---|
private final void | addNoteList(com.sun.jdo.api.persistence.enhancer.impl.InsnNote note)Add a list of notes to the note list.
insnNotes.put(note.insn, note);
| private void | annotateClone(CodeAttribute codeAttr, java.lang.String superName)Optimize out obviously redundant fetch(this) and dirty(this)
annotations. These are repeated fetches and dirties which occur
in straight-line code with no intervening branch targets or
method calls.
if (false) {
final String methodName = method.name().asString();
final String methodSig = method.signature().asString();
System.out.println("annotateClone()");//NOI18N
System.out.println(" methodName = " + methodName);//NOI18N
System.out.println(" methodSig = " + methodSig);//NOI18N
System.out.println(" superName = " + superName);//NOI18N
}
Insn insn;
for (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")//NOI18N
&& methodSig.equals("()Ljava/lang/Object;")))//NOI18N
continue;
if (false) {
final ConstClass methodClass = methodRef.className();
final String methodClassName = methodClass.asString();
System.out.println(" found invocation of: "//NOI18N
+ methodClassName
+ "." + methodName + methodSig);//NOI18N
}
// check whether next instruction already is a downcast to a
// class implementing PersistenceCapable
final String thisClass = ca.className();
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 downcastet 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,
JDOMetaData.JDOStateManagerFieldName,
JDOMetaData.JDOStateManagerFieldSig)));
newInsn.append(Insn.create(opc_iconst_0));
newInsn.append(Insn.create(
opc_putfield,
pool.addFieldRef(thisClass,
JDOMetaData.JDOFlagsFieldName,
JDOMetaData.JDOFlagsFieldSig)));
// insert code
insn.insert(newInsn);
noteStack(3);
}
}
| void | annotateMethod()Annotate the class method. For now, brute force rules.
//@olsen: cosmetics
final CodeAttribute codeAttr = method.codeAttribute();
if (codeAttr == null || !needsAnnotation())
return;
//@olsen: disabled feature
/*
if ((annotate & MakeThisTransient) != 0) {
makeThisTransient(codeAttr);
if (annotate == MakeThisTransient)
return;
}
*/
//@olsen: added printing output
env.message(
"annotating method " + ca.userClassName()//NOI18N
+ "." + method.name().asString()//NOI18N
+ Descriptor.userMethodArgs(method.signature().asString()));
//@olsen: disabled feature
/*
clearThisAnnotation();
removeRedundantThisAnnotation();
*/
Insn firstInsn = codeAttr.theCode();
// First instruction is a target
Insn insn = firstInsn.next();
while (insn != null) {
switch(insn.opcode()) {
//@olsen: disabled feature
/*
case opc_invokestatic:
case opc_invokespecial:
case opc_invokevirtual:
case opc_invokeinterface:
*/
case opc_getfield:
case opc_putfield:
//@olsen: disabled feature
/*
case opc_aaload:
case opc_baload:
case opc_caload:
case opc_saload:
case opc_iaload:
case opc_laload:
case opc_faload:
case opc_daload:
case opc_aastore:
case opc_bastore:
case opc_castore:
case opc_sastore:
case opc_iastore:
case opc_lastore:
case opc_fastore:
case opc_dastore:
*/
insn = insnAnnotation(insn);
break;
default:
break;
}
insn = insn.next();
}
//@olsen: do special annotation if detected super.clone()
if ((annotate & SuperClone) != 0) {
final String superName = ca.classFile().superName().asString();
annotateClone(codeAttr, superName);
}
//@olsen: disabled feature
/*
if (methodIsInitializer()) {
} else {
// Pre- fetch/dirty this if needed
if (fetchThis || dirtyThis) {
// Optimize a fetch(this) or dirty(this) to the start of
// the method.
// For fetch calls this is:
// if (jdoFlags < 0)
// Implementation.fetch(this);
//
// For dirty calls this is:
// if ((jdoFlags&PersistenceCapable.writeBarrierSet) != 0)
// Implementation.dirty(this);
Insn newInsn = Insn.create(opc_aload_0);
Insn annotationStart = newInsn;
InsnTarget afterCondition = null;
//@olsen: disabled feature
///
if (ca.getFlagsMemberValid() &&
ca.getFlagsMember() != null) {
///
//@olsen: changed to use JDOMetaData
final String className = ca.className();
final String pcRootClass
= env.getJDOMetaData().getPersistenceCapableRootClass(className);
newInsn = newInsn.append(
Insn.create(opc_getfield,
pool.addFieldRef(
pcRootClass,
JDOMetaData.JDOFlagsFieldName,
JDOMetaData.JDOFlagsFieldSig)));
//@olsen: disabled feature
///
ClassControl flagsCC
= ca.getFlagsMemberClassControl();
newInsn = newInsn.append(
Insn.create(opc_getfield,
pool.addFieldRef(
flagsCC.className(),
ca.getFlagsMember(),
"B")));
///
afterCondition = new InsnTarget();
if (dirtyThis) {
newInsn = newInsn.append(Insn.create(opc_iconst_2));
newInsn = newInsn.append(Insn.create(opc_iand));
newInsn = newInsn.append(Insn.create(opc_ifeq, afterCondition));
newInsn = newInsn.append(Insn.create(opc_aload_0));
} else {
newInsn = newInsn.append(Insn.create(opc_ifge, afterCondition));
newInsn = newInsn.append(Insn.create(opc_aload_0));
}
//@olsen: disabled feature
///
}
///
newInsn = newInsn.append(
Insn.create(
opc_invokestatic,
pool.addMethodRef("com/sun/forte4j/persistence/internal/Implementation",
(dirtyThis ? "dirty" : "fetch"),
"(" + JDOMetaData.JDOPersistenceCapableSig + ")V")));
if (afterCondition != null)
newInsn = newInsn.append(afterCondition);
firstInsn.insert(annotationStart);
noteStack(2);
}
//@olsen: disabled feature
///
if (methodName.equals("clone") &&
methodSig.equals("()Ljava/lang/Object;") &&
!ca.getNeedsClone()) {
annotateClone(codeAttr, superName);
}
///
//@olsen: disabled feature
}
*/
//@olsen: disabled feature
/*
//^olsen: caches -> int[] ?
if (caches != null && caches.size() > 0) {
// Generate fetch/dirty cache initializers
Insn initInsn = null;
//^olsen: optimize traversal ?
for (int i = 0; i < caches.size(); i++) {
int slot = ((Integer) caches.elementAt(i)).intValue();
Insn nullInsn = Insn.create(opc_aconst_null);
if (initInsn == null)
initInsn = nullInsn;
else
initInsn.append(nullInsn);
initInsn.append(InsnUtils.aStore(slot, pool));
}
// These initializations must not occur in an
// exception handler or the code may fail to verify. If an
// exception handler starts at offset 0, our initializations
// will fall into the exception handler block. For
// simplicity, just add a new target as the initial
// instruction - it doesn't cost anything in the
// generated code.
InsnTarget newFirstInsn = new InsnTarget();
initInsn.append(firstInsn);
newFirstInsn.append(initInsn);
firstInsn = newFirstInsn;
codeAttr.setTheCode(firstInsn);
}
*/
if (annotationStack > 0)
codeAttr.setStackUsed(codeAttr.stackUsed() + annotationStack);
| private boolean | avoidAnnotation()Check to see if this is a special case that should not be
annotated.
//@olsen: cosmetics
//@olsen: allow for annotating initializers+finalizers
/*
final String methodName = method.name().asString();
final String methodSig = method.signature().asString();
if (methodName.equals("<clinit>") || methodIsFinalize())
// Never annotate class initializers or finalizers
return true;
*/
//^olsen: enable feature, rather use HashMap for lookup
//@olsen: disabled feature
/*
if (ca.persistCapable()) {
if ((methodName.equals("initializeContents") &&
methodSig.equals("(Lcom/sun/forte4j/persistence/internal/ObjectContents;)V")) ||
(methodName.equals("flushContents") &&
methodSig.equals("(Lcom/sun/forte4j/persistence/internal/ObjectContents;)V")) ||
(methodName.equals("clearContents") &&
methodSig.equals("()V")) ||
(methodName.equals("postInitializeContents") &&
methodSig.equals("()V")) ||
(methodName.equals("preFlushContents") &&
methodSig.equals("()V")) ||
(methodName.equals("preClearContents") &&
methodSig.equals("()V")) ||
(methodName.equals("jdoGetStateManager") &&
methodSig.equals("()Lcom/sun/forte4j/persistence/internal/StateManager;")) ||
(methodName.equals("jdoSetStateManager") &&
methodSig.equals("(Lcom/sun/forte4j/persistence/internal/StateManager;)V")) ||
(methodName.equals("jdoGetFlags") &&
methodSig.equals("()B")) ||
(methodName.equals("jdoSetFlags") &&
methodSig.equals("(B)V")))
// This is one of the special persistence actions.
// Don't annotate it
return true;
}
*/
return false;
| private com.sun.jdo.api.persistence.enhancer.impl.AnnotationFragment | buildAccessAnnotation(com.sun.jdo.api.persistence.enhancer.impl.InsnNote note)
final int requiredStack;
final Insn annotation;
final String targetClassName = note.targetClassName;
final String targetFieldName = note.targetFieldName;
final String targetPCRootClass = note.targetPCRootClass;
//@olsen: not needed to ensure: note.dirtyThis() && !method.isStatic()
final boolean fetch = (note.fetchPersistent() || note.fetchThis());
final boolean dirty = (note.dirtyPersistent() || note.dirtyThis());
//@olsen: added consistency check
affirm((fetch ^ dirty),
"Inconsistent fetch/dirty flags.");//NOI18N
//@olsen: added println() for debugging
if (false) {
final boolean dfgField = note.dfgFieldAccess();
final boolean pkField = note.pkFieldAccess();
System.out.println(" build access annotation: "//NOI18N
+ targetClassName
+ "." + targetFieldName + " : "//NOI18N
+ (pkField ? "pk," : "!pk,")//NOI18N
+ (dfgField ? "dfg," : "!dfg,")//NOI18N
+ (fetch ? "fetch " : "dirty ")//NOI18N
+ (note.fetchPersistent()
? "persistent" : "this")//NOI18N
+ ";");//NOI18N
}
final int argSize = note.arg();
final String fieldSig = note.sig();
final int fieldType = Descriptor.elementType(fieldSig);
final int fieldIndex = note.targetFieldIndex;
if (false) {
System.out.println(" argSize = " + argSize);//NOI18N
System.out.println(" fieldSig = " + fieldSig);//NOI18N
System.out.println(" fieldType = " + fieldType);//NOI18N
System.out.println(" fieldIndex = " + fieldIndex);//NOI18N
}
if (fetch) {
// get jdoStateManager
Insn insn = annotation = Insn.create(opc_dup);
insn = insn.append(
Insn.create(opc_getfield,
pool.addFieldRef(
targetPCRootClass,
JDOMetaData.JDOStateManagerFieldName,
JDOMetaData.JDOStateManagerFieldSig)));
// test jdoStateManager
// load/dirty field if nonnull
InsnTarget fetchDirty = new InsnTarget();
InsnTarget afterFetchDirty = new InsnTarget();
insn = insn.append(Insn.create(opc_dup));
insn = insn.append(
Insn.create(opc_ifnonnull, fetchDirty));
// pop jdoStateManager and skip loading/dirtying
insn = insn.append(Insn.create(opc_pop));
insn = insn.append(
Insn.create(opc_goto, afterFetchDirty));
// invoke StateManager's fetch method
insn = insn.append(fetchDirty);
// push field's unique index onto stack (1st arg)
insn = insn.append(InsnUtils.integerConstant(fieldIndex, pool));
// call stateManager's void prepareGetField(int fieldID) method
requiredStack = 2;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"prepareGetField",//NOI18N
"(I)V"),//NOI18N
requiredStack));
insn = insn.append(afterFetchDirty);
insn = insn.append(note.insn);
} else {
//affirm(dirty);
int singleRegs = 0;
int doubleRegs = 0;
// move current value into temp registers
affirm(argSize > 0);
final int reg = ((argSize == 1)
? tmpReg(singleRegs++)
: tmpReg2(doubleRegs++));
Insn insn = annotation = InsnUtils.store(fieldType, reg, pool);
// get jdoStateManager
insn = insn.append(Insn.create(opc_dup));
insn = insn.append(
Insn.create(opc_getfield,
pool.addFieldRef(
targetPCRootClass,
JDOMetaData.JDOStateManagerFieldName,
JDOMetaData.JDOStateManagerFieldSig)));
// test jdoStateManager
// load/dirty field if nonnull
InsnTarget fetchDirty = new InsnTarget();
InsnTarget afterFetchDirty = new InsnTarget();
insn = insn.append(Insn.create(opc_dup));
insn = insn.append(
Insn.create(opc_ifnonnull, fetchDirty));
// pop jdoStateManager and skip loading/dirtying
insn = insn.append(Insn.create(opc_pop));
// restore value from registers
affirm(argSize > 0);
insn = insn.append(InsnUtils.load(fieldType, reg, pool));
//@olsen: 4429769, insert the original putfield instruction here
insn = insn.append(note.insn);
insn = insn.append(
Insn.create(opc_goto, afterFetchDirty));
// invoke StateManager's load method
insn = insn.append(fetchDirty);
// push field's unique index onto stack (1st arg)
insn = insn.append(InsnUtils.integerConstant(fieldIndex, pool));
// restore value from registers (2nd arg)
affirm(argSize > 0);
insn = insn.append(InsnUtils.load(fieldType, reg, pool));
// call stateManager's set<Type>Field(index, value) method
switch(fieldType) {
case T_BOOLEAN:
//boolean setBooleanField(int fieldNumber, boolean value);
requiredStack = 3;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"setBooleanField",//NOI18N
"(IB)B"),//NOI18N
requiredStack));
//@olsen: 4429769, disregard object and setField's return value
insn = insn.append(Insn.create(opc_pop2));
break;
case T_CHAR:
//char setCharField(int fieldNumber, char 3);
requiredStack = 3;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"setCharField",//NOI18N
"(IC)C"),//NOI18N
requiredStack));
//@olsen: 4429769, disregard object and setField's return value
insn = insn.append(Insn.create(opc_pop2));
break;
case T_BYTE:
//byte setByteField(int fieldNumber, byte value);
requiredStack = 3;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"setByteField",//NOI18N
"(IZ)Z"),//NOI18N
requiredStack));
//@olsen: 4429769, disregard object and setField's return value
insn = insn.append(Insn.create(opc_pop2));
break;
case T_SHORT:
//short setShortField(int fieldNumber, short value);
requiredStack = 3;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"setShortField",//NOI18N
"(IS)S"),//NOI18N
requiredStack));
//@olsen: 4429769, disregard object and setField's return value
insn = insn.append(Insn.create(opc_pop2));
break;
case T_INT:
//int setIntField(int fieldNumber, int value);
requiredStack = 3;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"setIntField",//NOI18N
"(II)I"),//NOI18N
requiredStack));
//@olsen: 4429769, disregard object and setField's return value
insn = insn.append(Insn.create(opc_pop2));
break;
case T_LONG:
//long setLongField(int fieldNumber, long value);
requiredStack = 4;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"setLongField",//NOI18N
"(IJ)J"),//NOI18N
requiredStack));
//@olsen: 4429769, disregard object and setField's return value
insn = insn.append(Insn.create(opc_pop2));
insn = insn.append(Insn.create(opc_pop));
break;
case T_FLOAT:
//float setFloatField(int fieldNumber, float value);
requiredStack = 3;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"setFloatField",//NOI18N
"(IF)F"),//NOI18N
requiredStack));
//@olsen: 4429769, disregard object and setField's return value
insn = insn.append(Insn.create(opc_pop2));
break;
case T_DOUBLE:
//double setDoubleField(int fieldNumber, double value);
requiredStack = 4;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"setDoubleField",//NOI18N
"(ID)D"),//NOI18N
requiredStack));
//@olsen: 4429769, disregard object and setField's return value
insn = insn.append(Insn.create(opc_pop2));
insn = insn.append(Insn.create(opc_pop));
break;
case TC_OBJECT:
case TC_INTERFACE:
//Object setObjectField(int fieldNumber, Object value);
requiredStack = 3;
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
"setObjectField",//NOI18N
"(ILjava/lang/Object;)Ljava/lang/Object;"),//NOI18N
requiredStack));
//@olsen: 4429769, no need to downcast anymore
/*
// add a down-cast to the field's type
affirm((fieldSig.charAt(0) == 'L'
&& fieldSig.charAt(fieldSig.length() - 1) == ';'),
"Inconsistent field signature");//NOI18N
final String fieldTypeClassName
= fieldSig.substring(1, fieldSig.length() - 1);
final ConstClass fieldTypeConstClass
= pool.addClass(fieldTypeClassName);
insn = insn.append(
Insn.create(opc_checkcast, fieldTypeConstClass));
*/
//@olsen: 4429769, disregard object and setField's return value
insn = insn.append(Insn.create(opc_pop2));
break;
default:
throw new InternalError("Unexpected field type");//NOI18N
}
insn = insn.append(afterFetchDirty);
}
//@olsen: added println() for debugging
if (false) {
System.out.println(" built annotation, "//NOI18N
+ "required stack = "//NOI18N
+ requiredStack);
}
return new AnnotationFragment(annotation, requiredStack);
| private com.sun.jdo.api.persistence.enhancer.impl.AnnotationFragment | buildBasicAnnotation(com.sun.jdo.api.persistence.enhancer.impl.InsnNote note)Assuming that an object reference is on the top of stack,
generate an instruction sequence to perform the annotation
indicated by the note.
int requiredStack = 2;
Insn basicAnnotation = null;
//@olsen: changed to use JDOMetaData
final String targetClassName = note.targetClassName;
final String targetFieldName = note.targetFieldName;
final String targetPCRootClass = note.targetPCRootClass;
//@olsen: not needed to ensure: note.dirtyThis() && !method.isStatic()
final boolean fetch = (note.fetchPersistent() || note.fetchThis());
final boolean dirty = (note.dirtyPersistent() || note.dirtyThis());
//@olsen: added consistency check
affirm((fetch ^ dirty),
"Inconsistent fetch/dirty flags.");//NOI18N
//@olsen: added println() for debugging
if (false) {
final boolean dfgField = note.dfgFieldAccess();
final boolean pkField = note.pkFieldAccess();
System.out.println(" build basic annotation: "//NOI18N
+ targetClassName
+ "." + targetFieldName + " : "//NOI18N
+ (pkField ? "pk," : "!pk,")//NOI18N
+ (dfgField ? "dfg," : "!dfg,")//NOI18N
+ (fetch ? "fetch " : "dirty ")//NOI18N
+ (note.fetchPersistent()
? "persistent" : "this")//NOI18N
+ ";");//NOI18N
}
//@olsen: changed code for annotation
{
Insn insn = null;
//requiredStack = 2;
// get jdoFlags
basicAnnotation = insn = Insn.create(opc_dup);
insn = insn.append(
Insn.create(opc_getfield,
pool.addFieldRef(
targetPCRootClass,
JDOMetaData.JDOFlagsFieldName,
JDOMetaData.JDOFlagsFieldSig)));
// test jdoFlags
// skip loading for read if <= 0 / for update if == 0
InsnTarget afterFetchDirty = new InsnTarget();
insn = insn.append(
Insn.create((fetch ? opc_ifle : opc_ifeq),
afterFetchDirty));
// get jdoStateManager
insn = insn.append(Insn.create(opc_dup));
insn = insn.append(
Insn.create(opc_getfield,
pool.addFieldRef(
targetPCRootClass,
JDOMetaData.JDOStateManagerFieldName,
JDOMetaData.JDOStateManagerFieldSig)));
// invoke StateManager's load method
insn = insn.append(
new InsnInterfaceInvoke(
pool.addInterfaceMethodRef(
JDOMetaData.JDOStateManagerPath,
(fetch ? "loadForRead" : "loadForUpdate"),//NOI18N
"()V"),//NOI18N
1));
insn = insn.append(afterFetchDirty);
}
//@olsen: added println() for debugging
if (false) {
System.out.println(" built annotation, "//NOI18N
+ "required stack = "//NOI18N
+ requiredStack);
}
return new AnnotationFragment(basicAnnotation, requiredStack);
| void | checkCode(CodeAttribute codeAttr)Check the code attribute for possible annotations
//@olsen: cosmetics
Insn firstInsn = codeAttr.theCode();
// mark branch targets so we can distinguish them from
// targets which exist for the benefit of line numbers,
// local variables, etc.
for (Insn markInsn = firstInsn;
markInsn != null;
markInsn = markInsn.next()) {
markInsn.markTargets();
}
int allFlags = 0;
//@olsen: disabled feature
/*
boolean branchesSeen = false;
*/
for (Insn insn = firstInsn; insn != null; insn = insn.next() ) {
InsnNote note = null;
switch(insn.opcode()) {
//@olsen: disabled feature
/*
case opc_invokestatic:
case opc_invokespecial:
case opc_invokevirtual:
case opc_invokeinterface:
note = noteInvokeAnnotation(insn);
break;
*/
case opc_getfield:
note = noteGetFieldAnnotation(insn);
break;
case opc_putfield:
note = notePutFieldAnnotation(insn);
break;
//@olsen: disabled feature
/*
case opc_aaload:
case opc_baload:
case opc_caload:
case opc_saload:
case opc_iaload:
case opc_laload:
case opc_faload:
case opc_daload:
note = noteArrayLoadAnnotation(insn);
break;
case opc_aastore:
case opc_bastore:
case opc_castore:
case opc_sastore:
case opc_iastore:
case opc_lastore:
case opc_fastore:
case opc_dastore:
note = noteArrayStoreAnnotation(insn);
break;
*/
default:
break;
}
if (note != null) {
addNoteList(note);
//@olsen: ensured to use single note only (as instantiated)
affirm((note.next() == null),
"Number of annotation notes for instruction > 1.");//NOI18N
allFlags |= note.insnFlags;
//@olsen: ensured to use single note only (as instantiated)
/*
for (InsnNote aNote = note;
aNote != null;
aNote = aNote.next()) {
//@olsen: disabled feature
///
if (branchesSeen == false)
aNote.insnFlags |= Unconditional;
///
//@olsen: disabled feature
///
if (largestLoop != null && largestLoop.contains(insn))
aNote.insnFlags |= InLoop;
///
//@olsen: disabled feature
///
// annotating based on thisOptimization will be done later
if (aNote.dirtyThis() && aNote.unconditional())
dirtyThis = true;
else if (aNote.dirtyThis() || aNote.fetchThis())
fetchThis = true;
///
allFlags |= aNote.insnFlags;
}
*/
}
//@olsen: disabled feature
/*
if (insn.branches())
branchesSeen = true;
*/
}
//@olsen: disabled feature
/*
if (methodIsInitializer()) {
// An inititalizer - either force the fetchThis, dirtyThis flags
// on or off.
if (env.doInitializerOptimization()) {
// turn on the fetchThis, dirtyThis flags to inhibit fetches
// and stores of this if enabled. We won't really insert the
// fetch/dirty, since it isn't needed.
fetchThis = true;
dirtyThis = true;
} else {
// Make sure that the fetchThis, dirtyThis flags are turned off
fetchThis = false;
dirtyThis = false;
}
}
*/
//^olsen: prepare for inheritance on PC classes
//@olsen: check for annotating of clone()
final String methodName = method.name().asString();
final String methodSig = method.signature().asString();
//^olsen: annotate persistence-capable root classes only
// until the JDO spec precisely defines how to treat
// user-defined clone methods in transient classes
final boolean implementsPersistence = ca.getImplementsPersistence();
if (false) {
System.out.println(" check for annotating clone()");//NOI18N
System.out.println(" methodName = " + methodName);//NOI18N
System.out.println(" methodSig = " + methodSig);//NOI18N
System.out.println(" implementsPersistence = "//NOI18N
+ implementsPersistence);
}
if (methodName.equals("clone")//NOI18N
&& methodSig.equals("()Ljava/lang/Object;")//NOI18N
&& implementsPersistence) {
//^olsen: rather scan for 'invokespecial clone()Ljava/lang/Object;'
// in instruction loop above
allFlags |= SuperClone;
}
//@olsen: disabled feature
/*
if (methodName.equals("clone") &&
methodSig.equals("()Ljava/lang/Object;") &&
ca.persistCapable()) {
allFlags |= FetchThis;
fetchThis = true;
}
*/
annotate = allFlags;
| void | checkMethod()Examine the method to determine what sort of annotations are needed
//@olsen: added printing output
env.message(
"checking method " + ca.userClassName()//NOI18N
+ "." + method.name().asString()//NOI18N
+ Descriptor.userMethodArgs(method.signature().asString()));
//@olsen: cosmetics
annotate = 0;
final CodeAttribute codeAttr = method.codeAttribute();
if (codeAttr == null) {
return;
}
//^olsen: make robust
/*
if (isAnnotated(codeAttr)) {
env.message("Method " + ca.userClassName() +
"." + method.name().asString() +
Descriptor.userMethodArgs(method.signature().asString()) +
" is already annotated.");
return;
}
*/
// look for certain special cases to avoid
//@olsen: cosmetics
if (avoidAnnotation()) {
return;
}
checkCode(codeAttr);
//@olsen: disabled feature
/*
if (!avoidAnnotation()) {
largestLoop = Loop.checkLoops(codeAttr.theCode());
checkCode(codeAttr);
} else if (methodIsPersistentFinalize()) {
annotate = MakeThisTransient;
}
*/
| private final void | copyStack(java.util.Stack fromStack, java.util.Stack toStack)
while (!toStack.empty())
toStack.pop();
// take advantage of Stack's inheritance from Vector
for (int i=0; i<fromStack.size(); i++)
toStack.addElement(fromStack.elementAt(i));
| private Insn | findArgDepositer(Insn currInsn, int argDepth)Attempt to locate the instruction which deposits to the top of stack
the 1 word stack argument to currInsn which is argDepth deep on the
stack (top of stack == 0).
If unable to determine this with confidence, return null.
Note that this method will not look back past a target.
Also, the operations performed by the dup2, dup_x1, dup_x2, dup2_x1,
dup2_x2 instructions are currently not understood by this method so
we don't attempt to chain back through these instructions.
Insn depositer = null;
for (Insn i = currInsn.prev(); argDepth >= 0; i = i.prev()) {
// At control flow branch/merge points, abort the search for the
// target operand.
if (i.branches() ||
((i instanceof InsnTarget) && ((InsnTarget)i).isBranchTarget()))
break;
int nArgs = i.nStackArgs();
int nResults = i.nStackResults();
if (argDepth - nResults < 0) {
// This instruction does deposit the value
// For now, don't return depositers other than opc_dup which
// deposit more than one value. These are the
// long/doubleinstructions (which can't be depositing a one
// word value) and the dupX variants
if (nResults > 1 && i.opcode() != opc_dup)
break;
depositer = i;
// consider special cases which may cause us to look further
switch (i.opcode()) {
case opc_dup:
if (argDepth == 0)
// keep going to find the real depositer at a greater depth
argDepth++;
break;
case opc_checkcast:
// keep going to find the real depositer
break;
default:
return i;
}
}
argDepth += (nArgs - nResults);
}
return depositer;
| private final com.sun.jdo.api.persistence.enhancer.impl.InsnNote | getNoteList(Insn insn)Find the note list for the specified instruction.
return (InsnNote)insnNotes.get(insn);
| private Insn | insnAnnotation(Insn insn)Generate annotations if needed for the instruction.
// The note list should be sorted in order of decreasing arg depth
int initialSingleRegs = 0;
//@olsen: ensured to use single note only (as instantiated)
/*
for (InsnNote note = getNoteList(insn);
note != null;
note = note.next()) { ... }
*/
InsnNote note = getNoteList(insn);
if (note == null)
return insn;
//@olsen: ensured to use single note only (as instantiated)
affirm(insn == note.insn);
affirm((note.next() == null),
"Number of annotation notes for instruction > 1.");//NOI18N
//@olsen: not needed to ensure: note.dirtyThis() && !method.isStatic()
final boolean fetch = (note.fetchPersistent() || note.fetchThis());
final boolean dirty = (note.dirtyPersistent() || note.dirtyThis());
//@olsen: added consistency check
affirm((fetch ^ dirty),
"Inconsistent fetch/dirty flags.");//NOI18N
//@olsen: added checks
final boolean dfgField = note.dfgFieldAccess();
final boolean pkField = note.pkFieldAccess();
//@olsen: added println() for debugging
if (false) {
final String targetClassName = note.targetClassName;
final String targetFieldName = note.targetFieldName;
//final String targetPCRootClass = note.targetPCRootClass;
System.out.println(" build annotation: "//NOI18N
+ targetClassName
+ "." + targetFieldName + " : "//NOI18N
+ (pkField ? "pk," : "!pk,")//NOI18N
+ (dfgField ? "dfg," : "!dfg,")//NOI18N
+ (fetch ? "fetch " : "dirty ")//NOI18N
+ (note.fetchPersistent()
? "persistent" : "this")//NOI18N
+ ";");//NOI18N
}
//@olsen: improved control flow
//@olsen: 4385427: do not enhance PK read access at all
if (pkField && fetch) {
return insn;
}
//@olsen: enhance for mediated access
//@olsen: enhance PK write as mediated access
//@olsen: added: mediated getfield/putfield insn annotation
if (pkField || !dfgField) {
//insn.prev().insert(Insn.create(opc_nop));
//@olsen: 4429769: drop putfield instruction on mediated write
// access; isolate the get/putfield instruction to allow
// to now be inserted by buildAccessAnnotation() itself
final Insn prev = insn.prev();
insn.remove();
//@olsen: changed not to return null
final AnnotationFragment frag1 = buildAccessAnnotation(note);
affirm(frag1, "Illegal annotation of PK or non-dfg field.");//NOI18N
//@olsen: 4429769, replace current instruction with fragment
//insn.prev().insert(frag1.annotation);
//noteStack(frag1.stackRequired - note.arg());
//return insn;
final Insn last = prev.insert(frag1.annotation);
noteStack(frag1.stackRequired - note.arg());
return last;
}
// do basic annotation
//@olsen: enhance for non-mediated access
final AnnotationFragment frag0 = buildBasicAnnotation(note);
//@olsen: changed not to return null
affirm(frag0, "Illegal annotation of dfg field.");//NOI18N
//if (frag0 != null) {
{
// Attempt to find an instruction where the argument is known
// to be on the top of stack
StackState state
= new StackState(note.arg(), note.sig(), insn.prev());
minimizeStack(state);
if (false) {
System.out.println(" state.argDepth = "//NOI18N
+ state.argDepth);
System.out.print(" state.insn = ");//NOI18N
state.insn.printInsn(System.out);
System.out.print(" insn = ");//NOI18N
insn.printInsn(System.out);
}
// generate the necessary instructions
Insn annotation = null;
if (state.argDepth == 0) {
// The value is on top of the stack - the dup in the basic
// annotation fragment will suffice
annotation = frag0.annotation;
noteStack(frag0.stackRequired);
} else if (state.argDepth == 1) {
// The value on top of the stack is one deep. Because the
// operand of interest is also a single word value we can
// simply execute a swap operation to get access to the
// operand on top of the stack
annotation = Insn.create(opc_swap);
annotation.append(frag0.annotation);
annotation.append(Insn.create(opc_swap));
// reduce the code fragment's stack requirements by
// the amount that minimizeStack reduced the stack depth,
// since that is the context in which the code fragment
// will run.
noteStack(frag0.stackRequired - (note.arg()-1));
} else {
// The value is hidden by 2 or more stack operands. Move
// the obscuring values into temporaries to get access to
// the value - put them back when done
Stack stackTypes = state.stackTypes;
int depth = state.argDepth;
int elem = stackTypes.size()-1;
int singleRegs = initialSingleRegs;
int doubleRegs = 0;
int regnums[] = new int[depth];
int regtotal = 0;
// Now, move values into temp registers
while (depth > 0) {
int elemType =
((Integer)stackTypes.elementAt(elem--)).intValue();
int elemSize = Descriptor.elementSize(elemType);
depth -= elemSize;
int reg = ((elemSize == 1)
? tmpReg(singleRegs++)
: tmpReg2(doubleRegs++));
regnums[regtotal++] = reg;
Insn store = InsnUtils.store(elemType, reg, pool);
if (annotation == null)
annotation = store;
else
annotation.append(store);
}
affirm((depth >= 0),
"Stack underflow while computing save registers");//NOI18N
annotation.append(frag0.annotation);
while (regtotal > 0)
annotation.append(InsnUtils.load(
((Integer)stackTypes.elementAt(++elem)).intValue(),
regnums[--regtotal], pool));
noteStack(frag0.stackRequired - note.arg());
}
state.insn.insert(annotation);
}
return insn;
| private final boolean | knownTypes(java.util.Stack stack, int nWords)
// take advantage of Stack's inheritance from Vector
for (int i=stack.size()-1; i>= 0 && nWords > 0; i--) {
int words = 0;
switch (((Integer)stack.elementAt(i)).intValue()) {
case T_UNKNOWN:
case T_WORD:
case T_TWOWORD:
return false;
case T_BOOLEAN:
case T_CHAR:
case T_FLOAT:
case T_BYTE:
case T_SHORT:
case T_INT:
case TC_OBJECT:
case TC_INTERFACE:
case TC_STRING:
words = 1;
case T_DOUBLE:
case T_LONG:
words = 2;
default:
break;
}
nWords -= words;
}
return true;
| private void | minimizeStack(com.sun.jdo.api.persistence.enhancer.impl.StackState state)Assume that after the execution of state.insn there is a word on
the stack which is state.argDepth words deep.
Scan backwards through the instruction sequence, attempting to
locate an instruction after which the argument is at a minimal
depth w.r.t. the top of stack. Update the state to indicate
progress.
Note that this method will not look back past a target.
Insn i = state.insn;
int argDepth = state.argDepth;
Stack argTypesStack = new Stack();
Stack resultTypesStack = new Stack();
Stack stackTypes = new Stack();
copyStack(state.stackTypes, stackTypes);
for (; argDepth > 0; i = i.prev()) {
// At control flow branch/merge points, abort the search for the
// target operand. The caller will have to make do with the best
// stack state computed thus far.
if (i.branches() ||
((i instanceof InsnTarget)
&& ((InsnTarget)i).isBranchTarget()))
break;
int nArgs = i.nStackArgs();
int nResults = i.nStackResults();
String argTypes = i.argTypes();
String resultTypes = i.resultTypes();
argDepth -= nResults;
// If the target argument was placed there by an instruction which
// deposited multiple results (one of the dup type instructions)
// then we don't have the smarts to figure out where it came from
// so just quit looking
if (argDepth < 0)
break;
argDepth += nArgs;
if (i.opcode() == opc_swap) {
Object x = stackTypes.pop();
Object y = stackTypes.pop();
stackTypes.push(x);
stackTypes.push(y);
} else {
// Make sure the arg types and result types stacks are empty
while (!argTypesStack.empty()) argTypesStack.pop();
while (!resultTypesStack.empty()) resultTypesStack.pop();
Descriptor.computeStackTypes(argTypes, argTypesStack);
Descriptor.computeStackTypes(resultTypes, resultTypesStack);
int expectWords = 0;
while (!resultTypesStack.empty())
expectWords += Descriptor.elementSize(
((Integer) resultTypesStack.pop()).intValue());
while (expectWords > 0)
expectWords -= Descriptor.elementSize(
((Integer) stackTypes.pop()).intValue());
if (expectWords < 0) {
// perhaps we ought to signal an exception, but returning
// will keep things going just fine.
return;
}
transferStackArgs(argTypesStack, stackTypes);
}
if (argDepth >= 0 && argDepth < state.argDepth &&
knownTypes(stackTypes, argDepth)) {
state.argDepth = argDepth;
state.insn = i.prev();
copyStack(stackTypes, state.stackTypes);
}
}
| boolean | needsAnnotation()Is any annotation needed for this method? The result of this
method isn't valid until after checkMethod has been run.
/* The largest loop contained within the method, or null. */
//@olsen: disabled feature
/*
private Loop largestLoop;
*/
// package accessors
return annotate != 0;
| private com.sun.jdo.api.persistence.enhancer.impl.InsnNote | noteGetFieldAnnotation(Insn insn)make note of annotations if needed for the getField instruction.
//@olsen: cosmetics
final InsnConstOp getFieldInsn = (InsnConstOp)insn;
final ConstFieldRef fieldRef = (ConstFieldRef)getFieldInsn.value();
final String fieldOf = fieldRef.className().asString();
//@olsen: changed to use JDOMetaData
final String fieldName
= fieldRef.nameAndType().name().asString();
final JDOMetaData meta = env.getJDOMetaData();
if (!meta.isPersistentField(fieldOf, fieldName))
return null;
//@olsen: disabled feature
/*
final ClassControl cc = env.findClass(fieldOf);
if (cc == null || !cc.persistCapable())
return null;
*/
//@olsen: added checks
final boolean dfgField
= meta.isDefaultFetchGroupField(fieldOf, fieldName);
final boolean pkField
= meta.isPrimaryKeyField(fieldOf, fieldName);
final int fieldIndex
= meta.getFieldNo(fieldOf, fieldName);
final String targetPCRootClass
= meta.getPersistenceCapableRootClass(fieldOf);
int flags = 0;
//@olsen: added variables
final String fieldSig = fieldRef.nameAndType().signature().asString();
// there's no field value on the stack yet
final int stackArgSize = 0;
//@olsen: added println() for debugging
if (false) {
System.out.println(" get field "//NOI18N
+ fieldOf + "." + fieldName//NOI18N
+ "[" + fieldIndex + "]"//NOI18N
+ "<" + fieldSig + ">"//NOI18N
+ " : p"//NOI18N
+ (dfgField ? ",dfg" : ",!dfg")//NOI18N
+ (pkField ? ",pk" : ",!pk")//NOI18N
+ ";");//NOI18N
}
Insn dep = findArgDepositer(insn, stackArgSize);
if (dep != null
&& dep.opcode() == opc_aload_0
&& !method.isStatic())
// This represents a fetch of "this"
flags |= FetchThis;
else
flags |= FetchPersistent;
//@olsen: added test
if (dfgField)
flags |= DFGField;
//@olsen: added test
if (pkField)
flags |= PKField;
//@olsen: changed to use JDOMetaData
return new InsnNote(insn, flags,
stackArgSize,
fieldSig, fieldOf, fieldName, fieldIndex,
targetPCRootClass);
//@olsen: disabled feature
/*
return new InsnNote(insn, flags, 0, "", cc.action());
*/
| private com.sun.jdo.api.persistence.enhancer.impl.InsnNote | notePutFieldAnnotation(Insn insn)Generate annotations if needed for the putField instruction.
//@olsen: cosmetics
final InsnConstOp putFieldInsn = (InsnConstOp)insn;
final ConstFieldRef fieldRef = (ConstFieldRef)putFieldInsn.value();
final String fieldOf = fieldRef.className().asString();
//@olsen: changed to use JDOMetaData
final String fieldName
= fieldRef.nameAndType().name().asString();
final JDOMetaData meta = env.getJDOMetaData();
if (!meta.isPersistentField(fieldOf, fieldName))
return null;
//@olsen: disabled feature
/*
final ClassControl cc = env.findClass(fieldOf);
if (cc == null || !cc.persistCapable())
return null;
*/
//@olsen: added checks
final boolean dfgField
= meta.isDefaultFetchGroupField(fieldOf, fieldName);
final boolean pkField
= meta.isPrimaryKeyField(fieldOf, fieldName);
final int fieldIndex
= meta.getFieldNo(fieldOf, fieldName);
final String targetPCRootClass
= meta.getPersistenceCapableRootClass(fieldOf);
int flags = 0;
//@olsen: added variables
final String fieldSig = fieldRef.nameAndType().signature().asString();
// size of field value on the stack
final int stackArgSize
= (fieldSig.equals("J") || fieldSig.equals("D")) ? 2 : 1;//NOI18N
//@olsen: added println() for debugging
if (false) {
System.out.println(" put field "//NOI18N
+ fieldOf + "." + fieldName//NOI18N
+ "[" + fieldIndex + "]"//NOI18N
+ "<" + fieldSig + ">"//NOI18N
+ " : p"//NOI18N
+ (dfgField ? ",dfg" : ",!dfg")//NOI18N
+ (pkField ? ",pk" : ",!pk")//NOI18N
+ ";");//NOI18N
}
Insn dep = findArgDepositer(insn, stackArgSize);
if (dep != null
&& dep.opcode() == opc_aload_0
&& !method.isStatic())
// This represents a dirtyfication of "this"
flags |= DirtyThis;
else
flags |= DirtyPersistent;
//@olsen: added test
if (dfgField)
flags |= DFGField;
//@olsen: added test
if (pkField)
flags |= PKField;
//@olsen: changed to use JDOMetaData
return new InsnNote(insn, flags,
stackArgSize,
fieldSig, fieldOf, fieldName, fieldIndex,
targetPCRootClass);
//@olsen: disabled feature
/*
return new InsnNote(insn, flags, stackArgSize, fieldSig, cc.action());
*/
| private void | noteStack(int stk)Note the following amount of stack used by a single annotation.
if (stk > annotationStack)
annotationStack = (short)stk;
| private int | tmpReg(int idx)Allocate a one word temporary register
if (tmpRegisters == null)
tmpRegisters = new Vector(3);
// allocate as many registers as necessary in order to
// make idx be a valid index
while (tmpRegisters.size() <= idx) {
final CodeAttribute codeAttr = method.codeAttribute();
final int reg = codeAttr.localsUsed();
tmpRegisters.addElement(new Integer(reg));
codeAttr.setLocalsUsed(reg+1);
}
return ((Integer)tmpRegisters.elementAt(idx)).intValue();
| private int | tmpReg2(int idx)Allocate a two word temporary register
if (tmpDoubleRegisters == null)
tmpDoubleRegisters = new Vector(3);
// allocated as many 2 register pairs as necessary in order to
// make idx be a valid index
while (tmpDoubleRegisters.size() <= idx) {
final CodeAttribute codeAttr = method.codeAttribute();
final int reg = codeAttr.localsUsed();
tmpDoubleRegisters.addElement(new Integer(reg));
codeAttr.setLocalsUsed(reg+2);
}
return ((Integer)tmpDoubleRegisters.elementAt(idx)).intValue();
| private final void | transferStackArgs(java.util.Stack fromStack, java.util.Stack toStack)
if (!fromStack.empty()) {
Object o = fromStack.pop();
transferStackArgs(fromStack, toStack);
toStack.push(o);
}
|
|