jaspex.transactifier.AddObjectMethodsClassVisitor.java Source code

Java tutorial

Introduction

Here is the source code for jaspex.transactifier.AddObjectMethodsClassVisitor.java

Source

/*
 * jaspex-mls: a Java Software Speculative Parallelization Framework
 * Copyright (C) 2015 Ivo Anjo <ivo.anjo@ist.utl.pt>
 *
 * This file is part of jaspex-mls.
 *
 * jaspex-mls is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * jaspex-mls 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with jaspex-mls.  If not, see <http://www.gnu.org/licenses/>.
 */

package jaspex.transactifier;

import java.io.IOException;

import jaspex.ClassFilter;

import org.objectweb.asm.*;
import static org.objectweb.asm.Opcodes.*;

import asmlib.*;
import asmlib.Type;

/** ClassVisitor que adiciona toString() e hashCode() a todas as classes "top-level"
  * da hierarquia (que sejam subclasses de Object ou de classes no-transaccionais),
  * para que estes mtodos possam ser chamados transaccionalmente.
  **/
public class AddObjectMethodsClassVisitor extends ClassVisitor {

    private boolean _injectToString = false;
    private boolean _injectHashCode = false;

    public AddObjectMethodsClassVisitor(ClassVisitor cv, InfoClass currentClass) {
        super(Opcodes.ASM4, cv);

        if (currentClass.isInterface())
            return;

        if (currentClass.superclassType().equals(Type.OBJECT)) {
            _injectHashCode = true;
            _injectToString = true;
            return;
        }

        // Verificar se superclasse no-transactificvel tem toString/hashCode
        // Se no tiver, esta classe dever inserir copias dele, c.c. sero mais
        // tarde adicionados overrides pelo InjectOverloadsClassVisitor
        if (!ClassFilter.isTransactifiable(currentClass.superclassType())) {
            // Popular superclasses, se necessrio
            if (currentClass.superclass() == null) {
                try {
                    asmlib.Util.populateSuperclasses(currentClass);
                } catch (IOException e) {
                    throw new Error(e);
                }
            }

            InfoClass superclass = currentClass.superclass();
            boolean foundToString = false;
            boolean foundHashCode = false;
            while (!superclass.type().equals(Type.OBJECT)) {
                if (!foundToString) {
                    foundToString = superclass.getMethod("toString", "()Ljava/lang/String;") != null;
                }
                if (!foundHashCode) {
                    foundHashCode = superclass.getMethod("hashCode", "()I") != null;
                }
                superclass = superclass.superclass();
            }

            _injectToString = !foundToString;
            _injectHashCode = !foundHashCode;
        }
    }

    @Override
    public MethodVisitor visitMethod(int access, String name, String desc, String signature, String[] exceptions) {
        String fullName = name + desc;
        if (fullName.equals("toString()Ljava/lang/String;"))
            _injectToString = false;
        if (fullName.equals("hashCode()I"))
            _injectHashCode = false;
        return cv.visitMethod(access, name, desc, signature, exceptions);
    }

    @Override
    public void visitEnd() {
        if (_injectToString) {
            // toString completamente transaccional usando o jaspex.Builtin.StringBuilder_*
            // Funciona porque apenas o hashCode() pode causar especulaes, e portanto no
            // pode haver concorrncia no acesso ao StringBuilder, j que ser sempre a mesma
            // thread/task a executar o cdigo que se segue  chamada do hashCode
            /*
            @Override
            public String toString() {
               String hashCode = Integer.toHexString(hashCode());
               Object stringBuilder = jaspex.Builtin.StringBuilder_new();
               jaspex.Builtin.StringBuilder_append(stringBuilder, getClass().getName());
               jaspex.Builtin.StringBuilder_append(stringBuilder, '@');
               jaspex.Builtin.StringBuilder_append(stringBuilder, hashCode);
               return jaspex.Builtin.StringBuilder_toString(stringBuilder);
            }
             */
            MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "toString", "()Ljava/lang/String;", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            // Chamada depois  corrigida pelo ChangeObjectMethodsMethodVisitor
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "hashCode", "()I");
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "toHexString", "(I)Ljava/lang/String;");
            mv.visitVarInsn(ASTORE, 1);
            mv.visitMethodInsn(INVOKESTATIC, "jaspex/Builtin", "StringBuilder_new", "()Ljava/lang/Object;");
            mv.visitVarInsn(ASTORE, 2);
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
            mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Class", "getName", "()Ljava/lang/String;");
            mv.visitMethodInsn(INVOKESTATIC, "jaspex/Builtin", "StringBuilder_append",
                    "(Ljava/lang/Object;Ljava/lang/String;)V");
            mv.visitVarInsn(ALOAD, 2);
            mv.visitIntInsn(BIPUSH, '@');
            mv.visitMethodInsn(INVOKESTATIC, "jaspex/Builtin", "StringBuilder_append", "(Ljava/lang/Object;C)V");
            mv.visitVarInsn(ALOAD, 2);
            mv.visitVarInsn(ALOAD, 1);
            mv.visitMethodInsn(INVOKESTATIC, "jaspex/Builtin", "StringBuilder_append",
                    "(Ljava/lang/Object;Ljava/lang/String;)V");
            mv.visitVarInsn(ALOAD, 2);
            mv.visitMethodInsn(INVOKESTATIC, "jaspex/Builtin", "StringBuilder_toString",
                    "(Ljava/lang/Object;)Ljava/lang/String;");
            mv.visitInsn(ARETURN);
            mv.visitMaxs(2, 3);
            mv.visitEnd();
        }

        if (_injectHashCode) {
            MethodVisitor mv = cv.visitMethod(ACC_PUBLIC, "hashCode", "()I", null, null);
            mv.visitCode();
            mv.visitVarInsn(ALOAD, 0);
            mv.visitMethodInsn(INVOKESTATIC, "java/lang/System", "identityHashCode", "(Ljava/lang/Object;)I");
            mv.visitInsn(IRETURN);
            mv.visitMaxs(1, 1);
            mv.visitEnd();
        }

        cv.visitEnd();
    }

}