jaspex.speculation.InjectOverloadsClassVisitor.java Source code

Java tutorial

Introduction

Here is the source code for jaspex.speculation.InjectOverloadsClassVisitor.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.speculation;

import jaspex.ClassFilter;

import java.io.IOException;
import java.util.Set;
import java.util.TreeSet;

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

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import asmlib.InfoClass;
import asmlib.InfoMethod;
import asmlib.Type;

/** ClassVisitor que cria overloads para todos os mtodos directamente herdados de superclasses
  * no-transactificveis.
  **/
public class InjectOverloadsClassVisitor extends ClassVisitor {

    @SuppressWarnings("unused")
    private static final Logger Log = LoggerFactory.getLogger(InjectOverloadsClassVisitor.class);
    private final InfoClass _currentClass;

    public InjectOverloadsClassVisitor(ClassVisitor cv, InfoClass currentClass) {
        super(Opcodes.ASM4, cv);
        _currentClass = currentClass;
    }

    @Override
    public void visitEnd() {
        if (_currentClass.isInterface())
            injectInterfaceOverloads();
        else
            checkOverloads();
        cv.visitEnd();
    }

    // Fazer overload a todos os mtodos que so herdados de superclasses no-transactificveis
    private void checkOverloads() {
        // Se superclasse pode ser transactificada, ento no  necessrio adicionar mais overloads
        if (_currentClass.superclassType().equals(Type.OBJECT)
                || ClassFilter.isTransactifiable(_currentClass.superclassType())) {
            return;
        }

        try {
            asmlib.Util.populateSuperclasses(_currentClass);
        } catch (java.io.IOException e) {
            throw new Error(e);
        }

        // Mtodos classe actual
        Set<InfoMethod> existingMethods = new TreeSet<InfoMethod>(
                new InfoMethod.InfoMethodNameDescOnlyComparator());
        existingMethods.addAll(_currentClass.methods());

        InfoClass infoClass = _currentClass.superclass();
        while (!infoClass.type().equals(Type.OBJECT)) {
            for (InfoMethod m : infoClass.methods()) {
                if (m.isCtor() || m.isStaticCtor())
                    continue;

                // Se mtodo no existe na classe actual, nem foi j overloaded,
                // injectar um overload
                if (!existingMethods.contains(m)) {
                    // Se  um mtodo abstracto, no precisamos de fazer overload,
                    // mesmo que depois exista uma implementao concreta numa superclasse
                    if (!m.isAbstract()) {
                        injectOverload(m);
                    }

                    existingMethods.add(m);
                }
            }
            infoClass = infoClass.superclass();
        }
    }

    private void injectOverload(InfoMethod method) {
        MethodVisitor mv = cv.visitMethod(method.access() & ~ACC_SYNCHRONIZED & ~ACC_NATIVE,
                method.name() + "$transactional", method.desc(), method.signature(), method.exceptions());
        mv.visitCode();
        // Contador de posies de argumentos
        int pos = 0;
        if (!method.isStatic())
            mv.visitVarInsn(ALOAD, pos++);
        for (Type argType : method.argumentTypes()) {
            mv.visitVarInsn(argType.getLoadInsn(), pos);
            pos += argType.getNumberSlots();
        }
        mv.visitMethodInsn(method.isStatic() ? INVOKESTATIC : INVOKESPECIAL, method.infoClass().type().asmName(),
                method.name(), method.desc());
        mv.visitInsn(method.returnType().getReturnInsn());
        mv.visitMaxs(0, 0);
        mv.visitEnd();
    }

    /** Caso especial para interfaces:
      * interface InterfaceA extends java.lang.Iterable { }
      * public class NewSpecExample82 {
      *   public static InterfaceA getInterfaceAImpl() { return null; }
      *   public static void main(String[] args) { getInterfaceAImpl().iterator(); }
      * }
      *
      * Neste caso tm que ser injectados as verses $speculative dos mtodos de Iterarable, porque a
      * chamada a iterator() ser substituida por uma chamada a iterator$speculative(), que dever estar
      * na interface, j que  uma interface transactificada!
      **/
    void injectInterfaceOverloads() {
        // Nota: Mtodos so colocados num set primeiro para evitar repeties
        Set<InfoMethod> injected = new TreeSet<InfoMethod>(new InfoMethod.InfoMethodNameDescOnlyComparator());

        // Para cada superinterface que seja no-transactificvel
        for (Type superifaceType : _currentClass.interfaceTypes()) {
            if (ClassFilter.isTransactifiable(superifaceType))
                continue;

            // Populamos completamente a sua lista de mtodos
            InfoClass superiface = null;
            try {
                superiface = InfoClass.fromType(superifaceType);
                asmlib.Util.populateSuperinterfaces(superiface);
            } catch (IOException e) {
                throw new Error(e);
            }

            // E vemos se algum dos seus mtodos ou de suas superinterfaces
            // no esto listados na interface actual
            for (InfoMethod m : superiface.allMethods()) {
                if ((_currentClass.getAllMethod(m.name(), m.desc()) == null) && !injected.contains(m)) {
                    // Se no est listado, fazemos a sua injeco
                    cv.visitMethod(m.access(), m.name() + "$transactional", m.desc(), m.signature(), m.exceptions())
                            .visitEnd();
                    injected.add(m);
                }
            }
        }
    }

}