jpcsp.Allegrex.compiler.CompilerParameterReader.java Source code

Java tutorial

Introduction

Here is the source code for jpcsp.Allegrex.compiler.CompilerParameterReader.java

Source

/*
This file is part of jpcsp.
    
Jpcsp 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.
    
Jpcsp 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 Jpcsp.  If not, see <http://www.gnu.org/licenses/>.
 */
package jpcsp.Allegrex.compiler;

import static jpcsp.Allegrex.Common._sp;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;

import jpcsp.ParameterReader;

/**
 * @author gid15
 *
 */
public class CompilerParameterReader extends ParameterReader {
    final protected ICompilerContext compilerContext;
    private boolean hasErrorPointer = false;
    private int currentParameterIndex = 0;
    private int currentStackPopIndex = 0;
    final private int[] currentStackPop = new int[10];

    public CompilerParameterReader(ICompilerContext compilerContext) {
        super(null, null);
        this.compilerContext = compilerContext;
    }

    private void loadParameterIntFromMemory(int index) {
        compilerContext.memRead32(_sp, (index - maxParameterInGprRegisters) << 2);
    }

    protected void loadParameterIntFromRegister(int index) {
        compilerContext.loadRegister(firstParameterInGpr + index);
    }

    private void loadParameterIntAt(int index) {
        if (index >= maxParameterInGprRegisters) {
            loadParameterIntFromMemory(index);
        } else {
            loadParameterIntFromRegister(index);
        }
    }

    private void loadParameterFloatAt(int index) {
        if (index >= maxParameterInFprRegisters) {
            throw (new UnsupportedOperationException());
        }
        compilerContext.loadFRegister(firstParameterInFpr + index);
    }

    private void loadParameterLongAt(int index) {
        if ((index % 2) != 0) {
            throw (new RuntimeException("Parameter misalignment"));
        }
        loadParameterIntAt(index);
        compilerContext.getMethodVisitor().visitInsn(Opcodes.I2L);
        compilerContext.getMethodVisitor().visitLdcInsn(0xFFFFFFFFL);
        compilerContext.getMethodVisitor().visitInsn(Opcodes.LAND);
        loadParameterIntAt(index + 1);
        compilerContext.getMethodVisitor().visitInsn(Opcodes.I2L);
        compilerContext.loadImm(32);
        compilerContext.getMethodVisitor().visitInsn(Opcodes.LSHL);
        compilerContext.getMethodVisitor().visitInsn(Opcodes.LADD);
    }

    public void loadNextInt() {
        loadParameterIntAt(moveParameterIndex(1));
    }

    public void loadNextFloat() {
        loadParameterFloatAt(moveParameterIndexFloat(1));
    }

    public void loadNextLong() {
        loadParameterLongAt(moveParameterIndex(2));
    }

    public void skipNextInt() {
        moveParameterIndex(1);
    }

    public void skipNextFloat() {
        moveParameterIndexFloat(1);
    }

    public void skipNextLong() {
        moveParameterIndex(2);
    }

    public void rewindPreviousInt() {
        moveParameterIndex(-1);
    }

    public void popAllStack(int additionalCount) {
        final MethodVisitor mv = compilerContext.getMethodVisitor();

        while (additionalCount >= 2) {
            mv.visitInsn(Opcodes.POP2);
            additionalCount -= 2;
        }

        if (additionalCount > 0) {
            mv.visitInsn(Opcodes.POP);
        }

        for (int i = currentStackPopIndex - 1; i >= 0; i--) {
            mv.visitInsn(currentStackPop[i]);
        }
    }

    public boolean hasErrorPointer() {
        return hasErrorPointer;
    }

    public void setHasErrorPointer(boolean hasErrorPointer) {
        this.hasErrorPointer = hasErrorPointer;
    }

    public int getCurrentParameterIndex() {
        return currentParameterIndex;
    }

    public void incrementCurrentParameterIndex() {
        currentParameterIndex++;
    }

    public void incrementCurrentStackSize(int size) {
        if (size == 1 && currentStackPopIndex > 0 && currentStackPop[currentStackPopIndex - 1] == Opcodes.POP) {
            // Merge previous POP with this one into a POP2
            currentStackPop[currentStackPopIndex - 1] = Opcodes.POP2;
        } else {
            // When size == 2 (e.g. for a "long" value), do not merge with a previous POP,
            // use an own POP2 for this "long" value.
            // Otherwise, VerifyError would be raised with message
            // "Attempt to split long or double on the stack"
            while (size >= 2) {
                currentStackPop[currentStackPopIndex++] = Opcodes.POP2;
                size -= 2;
            }
            if (size > 0) {
                currentStackPop[currentStackPopIndex++] = Opcodes.POP;
            }
        }
    }

    public void incrementCurrentStackSize() {
        incrementCurrentStackSize(1);
    }
}