/*
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);
}
}