jaspex.transactifier.ChangeFieldAccessMethodVisitor.java Source code

Java tutorial

Introduction

Here is the source code for jaspex.transactifier.ChangeFieldAccessMethodVisitor.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.util.*;

import jaspex.ClassFilter;
import jaspex.Options;
import jaspex.speculation.CommonTypes;
import jaspex.speculation.newspec.SpeculationSkiplist;
import jaspex.stm.ExternalAccessHelper;

import org.objectweb.asm.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

import asmlib.*;
import asmlib.Type;

public class ChangeFieldAccessMethodVisitor extends MethodVisitor {

    private static final Logger Log = LoggerFactory.getLogger(ChangeFieldAccessMethodVisitor.class);

    private final InfoClass _currentClass;
    private final boolean _active;

    public ChangeFieldAccessMethodVisitor(int access, String name, String desc, String signature,
            String[] exceptions, ClassVisitor cv, InfoClass currentClass, Boolean JDKClass) {
        super(Opcodes.ASM4, cv.visitMethod(access, name, desc, signature, exceptions));
        _currentClass = currentClass;
        // FIXME: Crappy workaround. <clinit>, mesmo dentro de uma especulao, faz sempre escrita normal,
        // com a espectativa de que no depende de nada que seja estado especulativo.
        // A alternativa antiga era fazer as escritas especulativas, e rezar para que no fosse feito o
        // abort da transaco que acidentalmente tinha feito o trigger do <clinit>. Nenhuma das duas
        // opes  soluo, mas talvez esta seja mais "prtica".
        _active = !(name.equals("<clinit>") /*&& JDKClass*/);
    }

    @Override
    public void visitFieldInsn(int opcode, String owner, String name, String desc) {
        if (!_active) {
            mv.visitFieldInsn(opcode, owner, name, desc);
            return;
        }

        Type ownerClass = Type.fromAsm(owner);
        // Classe que contm o StaticFieldBase e os offsets
        Type offsetAccessClass = ownerClass;
        Type sfbAccessClass = ownerClass;

        Type fieldType = Type.fromBytecode(desc);
        Type simpleType = fieldType.isPrimitive() ? fieldType : Type.OBJECT;
        String simpleTypeName = jaspex.transactifier.ChangeArrayAccessMethodVisitor.getName(simpleType);

        if (!ClassFilter.isTransactifiable(ownerClass)) {
            offsetAccessClass = ExternalAccessHelper.typeToExternalAccess(ownerClass);
            sfbAccessClass = offsetAccessClass;
        }

        // Determinar se field  final
        InfoField targetField = ownerClass.equals(_currentClass.type()) ? _currentClass.getField(name, fieldType)
                : null;
        if (targetField == null)
            targetField = getField(ownerClass, name, fieldType);

        // No fazer transactificao de fields final
        if (targetField.isFinal()) {
            mv.visitFieldInsn(opcode, owner, name, desc);
            return;
        }

        // Permitir a utilizao da SpeculationSkiplist para ignorar a transactificao de fields
        if (SpeculationSkiplist.skipFieldTx(ownerClass, name, fieldType)) {
            logSkip(fieldType, ownerClass, name);
            mv.visitFieldInsn(opcode, owner, name, desc);
            return;
        }

        if (!ClassFilter.isTransactifiable(targetField.infoClass().type())) {
            /*if (!Options.FASTMODE) {
               Log.debug("Field " + ownerClass.commonName() + "." + name + " belongs to "
                  + "non-transactional class " + targetField.infoClass().name().commonName()
                  + ", patching access to offset");
            }*/
            offsetAccessClass = ExternalAccessHelper.typeToExternalAccess(targetField.infoClass().type());
        }

        if (opcode == PUTFIELD) {
            // Avisar o DelayGetFutureMethodVisitor que isto  um store inlined
            mv.visitMethodInsn(INVOKESTATIC, CommonTypes.MARKER_BEFOREINLINEDSTORE, "normalStoreDummy", "()V");

            mv.visitFieldInsn(GETSTATIC, offsetAccessClass.asmName(), "$offset_" + name, "I");
            mv.visitInsn(I2L);
            mv.visitMethodInsn(INVOKESTATIC, CommonTypes.TRANSACTION.asmName(), "store" + simpleTypeName,
                    "(" + Type.OBJECT.bytecodeName() + simpleType.bytecodeName() + "J)V");
        } else if (opcode == GETFIELD) {
            mv.visitInsn(DUP);
            mv.visitFieldInsn(GETFIELD, ownerClass.asmName(), name, desc);
            mv.visitFieldInsn(GETSTATIC, offsetAccessClass.asmName(), "$offset_" + name, "I");
            mv.visitMethodInsn(INVOKESTATIC, CommonTypes.TRANSACTION.asmName(), "load" + simpleTypeName, "("
                    + Type.OBJECT.bytecodeName() + simpleType.bytecodeName() + "I)" + simpleType.bytecodeName());
            if (!fieldType.isPrimitive())
                mv.visitTypeInsn(CHECKCAST, fieldType.asmName());
        } else if (opcode == PUTSTATIC) {
            // Avisar o DelayGetFutureMethodVisitor que isto  um store inlined
            mv.visitMethodInsn(INVOKESTATIC, CommonTypes.MARKER_BEFOREINLINEDSTORE, "staticStoreDummy", "()V");

            if (Options.STATICWORKAROUND) {
                mv.visitFieldInsn(GETSTATIC, sfbAccessClass.asmName(), "$staticFieldBase",
                        CommonTypes.STATICFIELDBASE.bytecodeName());
                mv.visitFieldInsn(GETSTATIC, offsetAccessClass.asmName(), "$offset_" + name, "I");
                mv.visitInsn(I2L);
                mv.visitMethodInsn(INVOKESTATIC, CommonTypes.TRANSACTION.asmName(), "store" + simpleTypeName,
                        "(" + simpleType.bytecodeName() + CommonTypes.STATICFIELDBASE.bytecodeName() + "J)V");
            } else {
                mv.visitFieldInsn(GETSTATIC, sfbAccessClass.asmName(), "$staticFieldBase",
                        Type.OBJECT.bytecodeName());
                asmlib.Util.swap(mv, Type.OBJECT, fieldType);
                mv.visitFieldInsn(GETSTATIC, offsetAccessClass.asmName(), "$offset_" + name, "I");
                mv.visitInsn(I2L);
                mv.visitMethodInsn(INVOKESTATIC, CommonTypes.TRANSACTION.asmName(), "store" + simpleTypeName,
                        "(" + Type.OBJECT.bytecodeName() + simpleType.bytecodeName() + "J)V");
            }
        } else if (opcode == GETSTATIC) {
            mv.visitFieldInsn(GETSTATIC, sfbAccessClass.asmName(), "$staticFieldBase",
                    Options.STATICWORKAROUND ? CommonTypes.STATICFIELDBASE.bytecodeName()
                            : Type.OBJECT.bytecodeName());
            mv.visitFieldInsn(GETSTATIC, ownerClass.asmName(), name, desc);
            mv.visitFieldInsn(GETSTATIC, offsetAccessClass.asmName(), "$offset_" + name, "I");
            mv.visitMethodInsn(INVOKESTATIC, CommonTypes.TRANSACTION.asmName(), "load" + simpleTypeName,
                    "(" + (Options.STATICWORKAROUND ? CommonTypes.STATICFIELDBASE.bytecodeName()
                            : Type.OBJECT.bytecodeName()) + simpleType.bytecodeName() + "I)"
                            + simpleType.bytecodeName());
            if (!fieldType.isPrimitive())
                mv.visitTypeInsn(CHECKCAST, fieldType.asmName());
        } else {
            throw new AssertionError("Unexpected opcode");
        }
    }

    private static InfoField getField(Type ownerClass, String fieldName, Type fieldType) {
        try {
            // Tentar encontrar field apenas na ownerClass
            // Nota: Se a classe j estava cached, este passo j inclui os abaixo
            InfoClass infoClass = getInfoClass(ownerClass);
            InfoField infoField = infoClass.getAllField(fieldName, fieldType);
            if (infoField != null)
                return infoField;

            // Procurar field nas suas superclasses
            asmlib.Util.populateSuperclasses(infoClass);
            infoField = infoClass.getAllField(fieldName, fieldType);
            if (infoField != null)
                return infoField;

            // Se no foi encontrado at agora, deve ser um field herdado de uma interface.
            // Fields herdados de interfaces so sempre final.
            if (Options.FASTMODE) {
                return new InfoField(ACC_FINAL, fieldName, fieldType, null, null, null);
            } else {
                // Verificar assumptions, mesmo assim
                InfoClass ic = infoClass;
                while (!ic.type().equals(Type.OBJECT)) {
                    asmlib.Util.populateSuperinterfaces(ic);
                    ic = ic.superclass();
                }
                infoField = infoClass.getAllField(fieldName, fieldType);
                // Se este assert falhar com uma NPE, ou h um bug na asmlib,
                // ou falta contemplar algum caso
                assert (infoField.isFinal());
                return infoField;
            }
        } catch (java.io.IOException e) {
            throw new Error(e);
        }
    }

    private static final Map<Type, InfoClass> infoClassCache = new HashMap<Type, InfoClass>();

    private static InfoClass getInfoClass(Type type) throws java.io.IOException {
        InfoClass infoClass = infoClassCache.get(type);
        if (infoClass == null) {
            infoClass = InfoClass.fromType(type);
            infoClassCache.put(type, infoClass);
        }
        return infoClass;
    }

    private static Set<String> _skippedFields;

    private static void logSkip(Type fieldType, Type ownerClass, String name) {
        if (!Log.isDebugEnabled())
            return;

        String field = fieldType.commonName() + " " + ownerClass.commonName() + "." + name;

        if (_skippedFields == null)
            _skippedFields = new HashSet<String>();
        if (_skippedFields.add(field)) {
            Log.debug("Skipping transactification of accesses to field " + field);
        }
    }

}