package org.deuce.transform.asm.method;
import java.util.concurrent.atomic.AtomicInteger;
import org.deuce.Atomic;
import org.deuce.objectweb.asm.AnnotationVisitor;
import org.deuce.objectweb.asm.Label;
import org.deuce.objectweb.asm.MethodAdapter;
import org.deuce.objectweb.asm.MethodVisitor;
import org.deuce.objectweb.asm.Opcodes;
import org.deuce.objectweb.asm.Type;
import org.deuce.objectweb.asm.commons.Method;
import org.deuce.transaction.AbortTransactionException;
import org.deuce.transaction.Context;
import org.deuce.transaction.ContextDelegator;
import org.deuce.transaction.TransactionException;
import org.deuce.transform.asm.type.TypeCodeResolver;
import org.deuce.transform.asm.type.TypeCodeResolverFactory;
public class AtomicMethod extends MethodAdapter implements Opcodes{
final static public String ATOMIC_DESCRIPTOR = Type.getDescriptor(Atomic.class);
final static private AtomicInteger ATOMIC_BLOCK_COUNTER = new AtomicInteger(0);
private Integer retries = Integer.getInteger("org.deuce.transaction.retries", Integer.MAX_VALUE);
private String metainf = "";//Integer.getInteger("org.deuce.transaction.retries", Integer.MAX_VALUE);
final private String className;
final private String methodName;
final private TypeCodeResolver returnReolver;
final private TypeCodeResolver[] argumentReolvers;
final private boolean isStatic;
final private int variablesSize;
final private Method newMethod;
public AtomicMethod(MethodVisitor mv, String className, String methodName,
String descriptor, Method newMethod, boolean isStatic) {
super(mv);
this.className = className;
this.methodName = methodName;
this.newMethod = newMethod;
this.isStatic = isStatic;
Type returnType = Type.getReturnType(descriptor);
Type[] argumentTypes = Type.getArgumentTypes(descriptor);
returnReolver = TypeCodeResolverFactory.getReolver(returnType);
argumentReolvers = new TypeCodeResolver[ argumentTypes.length];
for( int i=0; i< argumentTypes.length ; ++i) {
argumentReolvers[ i] = TypeCodeResolverFactory.getReolver( argumentTypes[ i]);
}
variablesSize = variablesSize( argumentReolvers, isStatic);
}
@Override
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
final AnnotationVisitor visitAnnotation = super.visitAnnotation(desc, visible);
if( AtomicMethod.ATOMIC_DESCRIPTOR.equals(desc)){
return new AnnotationVisitor(){
public void visit(String name, Object value) {
if( name.equals("retries"))
AtomicMethod.this.retries = (Integer)value;
if( name.equals("metainf"))
AtomicMethod.this.metainf = (String)value;
visitAnnotation.visit(name, value);
}
public AnnotationVisitor visitAnnotation(String name, String desc) {
return visitAnnotation.visitAnnotation(name, desc);
}
public AnnotationVisitor visitArray(String name) {
return visitAnnotation.visitArray(name);
}
public void visitEnd() {
visitAnnotation.visitEnd();
}
public void visitEnum(String name, String desc, String value) {
visitAnnotation.visitEnum(name, desc, value);
}
};
}
return visitAnnotation;
}
/**
public static boolean foo(Object s) throws IOException{
Throwable throwable = null;
Context context = ContextDelegator.getInstance();
boolean commit = true;
boolean result = true;
for( int i=10 ; i>0 ; --i)
{
context.init(atomicBlockId, metainf);
try
{
result = foo(s,context);
}
catch( AbortTransactionException ex)
{
context.rollback();
throw ex;
}
catch( TransactionException ex)
{
commit = false;
}
catch( Throwable ex)
{
throwable = ex;
}
if( commit )
{
if( context.commit()){
if( throwable != null)
throw (IOException)throwable;
return result;
}
}
else
{
context.rollback();
commit = true;
}
}
throw new TransactionException();
}
*/
@Override
public void visitCode() {
final int indexIndex = variablesSize; // i
final int contextIndex = indexIndex + 1; // context
final int throwableIndex = contextIndex + 1;
final int commitIndex = throwableIndex + 1;
final int exceptionIndex = commitIndex + 1;
final int resultIndex = exceptionIndex + 1;
Label l0 = new Label();
Label l1 = new Label();
Label l25 = new Label();
mv.visitTryCatchBlock(l0, l1, l25, AbortTransactionException.ABORT_TRANSACTION_EXCEPTION_INTERNAL); // try{
Label l2 = new Label();
mv.visitTryCatchBlock(l0, l1, l2, TransactionException.TRANSACTION_EXCEPTION_INTERNAL); // try{
Label l3 = new Label();
mv.visitTryCatchBlock(l0, l1, l3, Type.getInternalName( Throwable.class)); // try{
Label l4 = new Label(); // Throwable throwable = null;
mv.visitLabel(l4);
mv.visitInsn(ACONST_NULL);
mv.visitVarInsn(ASTORE, throwableIndex);
Label l5 = getContext(contextIndex); // Context context = ContextDelegator.getInstance();
Label l6 = new Label(); // boolean commit = true;
mv.visitLabel(l6);
mv.visitInsn(ICONST_1);
mv.visitVarInsn(ISTORE, commitIndex);
Label l7 = new Label(); // ... result = null;
mv.visitLabel(l7);
if( returnReolver != null)
{
mv.visitInsn( returnReolver.nullValueCode());
mv.visitVarInsn( returnReolver.storeCode(), resultIndex);
}
Label l8 = new Label(); // for( int i=10 ; ... ; ...)
mv.visitLabel(l8);
mv.visitLdcInsn( retries);
mv.visitVarInsn(ISTORE, indexIndex);
Label l9 = new Label();
mv.visitLabel(l9);
Label l10 = new Label();
mv.visitJumpInsn(GOTO, l10);
Label l11 = new Label(); // context.init(atomicBlockId, metainf);
mv.visitLabel(l11);
mv.visitVarInsn(ALOAD, contextIndex);
mv.visitLdcInsn(ATOMIC_BLOCK_COUNTER.getAndIncrement());
mv.visitLdcInsn(metainf);
mv.visitMethodInsn(INVOKEINTERFACE, Context.CONTEXT_INTERNAL, "init", "(ILjava/lang/String;)V");
/* result = foo( context, ...) */
mv.visitLabel(l0);
if( !isStatic) // load this id if not static
mv.visitVarInsn(ALOAD, 0);
// load the rest of the arguments
int local = isStatic ? 0 : 1;
for( int i=0 ; i < argumentReolvers.length ; ++i) {
mv.visitVarInsn(argumentReolvers[i].loadCode(), local);
local += argumentReolvers[i].localSize(); // move to the next argument
}
mv.visitVarInsn(ALOAD, contextIndex); // load the context
if( isStatic)
mv.visitMethodInsn(INVOKESTATIC, className, methodName, newMethod.getDescriptor()); // ... = foo( ...
else
mv.visitMethodInsn(INVOKEVIRTUAL, className, methodName, newMethod.getDescriptor()); // ... = foo( ...
if( returnReolver != null)
mv.visitVarInsn(returnReolver.storeCode(), resultIndex); // result = ...
mv.visitLabel(l1);
Label l12 = new Label();
mv.visitJumpInsn(GOTO, l12);
/*catch( AbortTransactionException ex)
{
throw ex;
}*/
mv.visitLabel(l25);
mv.visitVarInsn(ASTORE, exceptionIndex);
Label l27 = new Label();
mv.visitVarInsn(ALOAD, contextIndex);
mv.visitMethodInsn(INVOKEINTERFACE, Context.CONTEXT_INTERNAL, "rollback", "()V");
mv.visitLabel(l27);
mv.visitVarInsn(ALOAD, exceptionIndex);
mv.visitInsn(ATHROW);
Label l28 = new Label();
mv.visitLabel(l28);
mv.visitJumpInsn(GOTO, l12);
/*catch( TransactionException ex)
{
commit = false;
}*/
mv.visitLabel(l2);
mv.visitVarInsn(ASTORE, exceptionIndex);
Label l13 = new Label();
mv.visitLabel(l13);
mv.visitInsn(ICONST_0);
mv.visitVarInsn(ISTORE, commitIndex);
Label l14 = new Label();
mv.visitLabel(l14);
mv.visitJumpInsn(GOTO, l12);
/*catch( Throwable ex)
{
throwable = ex;
}*/
mv.visitLabel(l3);
mv.visitVarInsn(ASTORE, exceptionIndex);
Label l15 = new Label();
mv.visitLabel(l15);
mv.visitVarInsn(ALOAD, exceptionIndex);
mv.visitVarInsn(ASTORE, throwableIndex);
/*
* if( commit )
{
if( context.commit()){
if( throwable != null)
throw (IOException)throwable;
return result;
}
}
else
{
context.rollback();
commit = true;
}
*/
mv.visitLabel(l12); // if( commit )
mv.visitVarInsn(ILOAD, commitIndex);
Label l16 = new Label();
mv.visitJumpInsn(IFEQ, l16);
Label l17 = new Label(); // if( context.commit())
mv.visitLabel(l17);
mv.visitVarInsn(ALOAD, contextIndex);
mv.visitMethodInsn(INVOKEINTERFACE, Context.CONTEXT_INTERNAL, "commit", "()Z");
Label l18 = new Label();
mv.visitJumpInsn(IFEQ, l18);
// if( throwable != null)
// throw throwable;
Label l19 = new Label();
mv.visitLabel(l19);
mv.visitVarInsn(ALOAD, throwableIndex);
Label l20 = new Label();
mv.visitJumpInsn(IFNULL, l20);
Label l21 = new Label();
mv.visitLabel(l21);
mv.visitVarInsn(ALOAD, throwableIndex);
mv.visitInsn(ATHROW);
// return
mv.visitLabel(l20);
if( returnReolver == null) {
mv.visitInsn( RETURN); // return;
}
else {
mv.visitVarInsn(returnReolver.loadCode(), resultIndex); // return result;
mv.visitInsn(returnReolver.returnCode());
}
mv.visitJumpInsn(GOTO, l18);
// else
mv.visitLabel(l16); // context.rollback();
mv.visitVarInsn(ALOAD, contextIndex);
mv.visitMethodInsn(INVOKEINTERFACE, Context.CONTEXT_INTERNAL, "rollback", "()V");
mv.visitInsn(ICONST_1); // commit = true;
mv.visitVarInsn(ISTORE, commitIndex);
mv.visitLabel(l18); // for( ... ; i>0 ; --i)
mv.visitIincInsn(indexIndex, -1);
mv.visitLabel(l10);
mv.visitVarInsn(ILOAD, indexIndex);
mv.visitJumpInsn(IFGT, l11);
// throw new TransactionException("Failed to commit ...");
Label l23 = throwTransactionException();
/* locals */
Label l24 = new Label();
mv.visitLabel(l24);
mv.visitLocalVariable("throwable", "Ljava/lang/Throwable;", null, l5, l24, throwableIndex);
mv.visitLocalVariable("context", Context.CONTEXT_DESC, null, l6, l24, contextIndex);
mv.visitLocalVariable("commit", "Z", null, l7, l24, commitIndex);
if( returnReolver != null)
mv.visitLocalVariable("result", returnReolver.toString(), null, l8, l24, resultIndex);
mv.visitLocalVariable("i", "I", null, l9, l23, indexIndex);
mv.visitLocalVariable("ex", "Lorg/deuce/transaction/AbortTransactionException;", null, l27, l28, exceptionIndex);
mv.visitLocalVariable("ex", "Lorg/deuce/transaction/TransactionException;", null, l13, l14, exceptionIndex);
mv.visitLocalVariable("ex", "Ljava/lang/Throwable;", null, l15, l12, exceptionIndex);
mv.visitMaxs(6 + variablesSize, resultIndex + 2);
mv.visitEnd();
}
private Label getContext(final int contextIndex) {
Label label = new Label();
mv.visitLabel(label); // Context context = ContextDelegator.getInstance();
mv.visitMethodInsn(INVOKESTATIC, ContextDelegator.CONTEXT_DELEGATOR_INTERNAL, "getInstance", "()Lorg/deuce/transaction/Context;");
mv.visitVarInsn(ASTORE, contextIndex);
return label;
}
private Label throwTransactionException() {
Label label = new Label();
mv.visitLabel(label);
mv.visitTypeInsn(NEW, "org/deuce/transaction/TransactionException");
mv.visitInsn(DUP);
mv.visitLdcInsn("Failed to commit the transaction in the defined retries.");
mv.visitMethodInsn(INVOKESPECIAL, "org/deuce/transaction/TransactionException", "<init>", "(Ljava/lang/String;)V");
mv.visitInsn(ATHROW);
return label;
}
@Override
public void visitFrame(int type, int local, Object[] local2, int stack, Object[] stack2) {
}
@Override
public void visitIincInsn(int var, int increment) {
}
@Override
public void visitInsn(int opcode) {
}
@Override
public void visitIntInsn(int opcode, int operand) {
}
@Override
public void visitJumpInsn(int opcode, Label label) {
}
@Override
public void visitLabel(Label label) {
}
@Override
public void visitEnd() {
}
@Override
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
}
@Override
public void visitLdcInsn(Object cst) {
}
@Override
public void visitLineNumber(int line, Label start) {
}
@Override
public void visitLocalVariable(String name, String desc, String signature, Label start,
Label end, int index) {
}
@Override
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
}
@Override
public void visitMaxs(int maxStack, int maxLocals) {
}
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
}
@Override
public void visitMultiANewArrayInsn(String desc, int dims) {
}
@Override
public void visitTableSwitchInsn(int min, int max, Label dflt, Label[] labels) {
}
@Override
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
}
@Override
public void visitTypeInsn(int opcode, String type) {
}
@Override
public void visitVarInsn(int opcode, int var) {
}
public void setRetries(int retries) {
this.retries = retries;
}
private int variablesSize( TypeCodeResolver[] types, boolean isStatic) {
int i = isStatic ? 0 : 1;
for( TypeCodeResolver type : types) {
i += type.localSize();
}
return i;
}
}