/*
* This file is part of the Jikes RVM project (http://jikesrvm.org).
*
* This file is licensed to You under the Eclipse Public License (EPL);
* You may not use this file except in compliance with the License. You
* may obtain a copy of the License at
*
* http://www.opensource.org/licenses/eclipse-1.0.php
*
* See the COPYRIGHT.txt file distributed with this work for information
* regarding copyright ownership.
*/
package org.jikesrvm.ppc;
import static org.jikesrvm.VM.NOT_REACHED;
import static org.jikesrvm.ppc.RegisterConstants.FIRST_VOLATILE_FPR;
import static org.jikesrvm.ppc.RegisterConstants.FIRST_VOLATILE_GPR;
import static org.jikesrvm.ppc.RegisterConstants.LAST_VOLATILE_FPR;
import static org.jikesrvm.ppc.RegisterConstants.LAST_VOLATILE_GPR;
import static org.jikesrvm.ppc.StackframeLayoutConstants.LOG_BYTES_IN_STACKSLOT;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_ALIGNMENT;
import static org.jikesrvm.ppc.StackframeLayoutConstants.STACKFRAME_HEADER_SIZE;
import static org.jikesrvm.runtime.Reflection.REFLECTION_FPRS_BITS;
import static org.jikesrvm.runtime.Reflection.REFLECTION_GPRS_BITS;
import org.jikesrvm.VM;
import org.jikesrvm.classloader.RVMMethod;
import org.jikesrvm.classloader.TypeReference;
import org.jikesrvm.runtime.Memory;
import org.jikesrvm.runtime.Reflection;
import org.vmmagic.unboxed.Word;
import org.vmmagic.unboxed.WordArray;
/**
* Machine dependent portion of Reflective method invoker.
*/
public abstract class MachineReflection {
/**
* Determine number/type of registers/spills required to call specified method.
* See also: Compiler.loadParameters()
*/
public static int countParameters(RVMMethod method) {
int GPRs = 0;
int FPRs = 0;
int Spills = 0;
int gp = FIRST_VOLATILE_GPR.value();
int fp = FIRST_VOLATILE_FPR.value();
if (!method.isStatic()) {
if (gp > LAST_VOLATILE_GPR.value()) {
Spills++;
} else {
GPRs++;
gp++;
}
}
for (TypeReference t : method.getParameterTypes()) {
if (t.isLongType()) {
if (VM.BuildFor64Addr) {
if (gp > LAST_VOLATILE_GPR.value()) {
Spills++;
} else {
GPRs++;
gp++;
}
} else {
if (gp > LAST_VOLATILE_GPR.value()) {
Spills += 2;
} else {
GPRs++;
gp++;
if (gp > LAST_VOLATILE_GPR.value()) {
Spills++;
} else {
GPRs++;
gp++;
}
}
}
} else if (t.isFloatType()) {
if (fp > LAST_VOLATILE_FPR.value()) {
Spills++;
} else {
FPRs++;
fp++;
}
} else if (t.isDoubleType()) {
if (fp > LAST_VOLATILE_FPR.value()) {
Spills += VM.BuildFor64Addr ? 1 : 2;
} else {
FPRs++;
fp++;
}
} else { // t is object, int, short, char, byte, or boolean
if (gp > LAST_VOLATILE_GPR.value()) {
Spills++;
} else {
GPRs++;
gp++;
}
}
}
// spills[] carries burden of doubleword aligning stack frame
if (VM.BuildFor32Addr) {
int frameSize = (Spills << LOG_BYTES_IN_STACKSLOT) + STACKFRAME_HEADER_SIZE;
frameSize = Memory.alignUp(frameSize, STACKFRAME_ALIGNMENT);
Spills = (frameSize - STACKFRAME_HEADER_SIZE) >> LOG_BYTES_IN_STACKSLOT;
}
// hack to return triple
return (Spills << (REFLECTION_FPRS_BITS + REFLECTION_GPRS_BITS)) |
(FPRs << REFLECTION_GPRS_BITS) |
GPRs;
}
/**
* Collect parameters into arrays of registers/spills, as required to call specified method.
*/
public static void packageParameters(RVMMethod method, Object thisArg, Object[] otherArgs, WordArray GPRs,
double[] FPRs, byte[] FPRmeta, WordArray Spills) {
int GPR = GPRs.length();
int FPR = FPRs.length;
int Spill = Spills.length();
int gp = FIRST_VOLATILE_GPR.value();
int fp = FIRST_VOLATILE_FPR.value();
if (!method.isStatic()) {
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, Reflection.unwrapObject(thisArg).toWord());
} else {
gp++;
GPRs.set(--GPR, Reflection.unwrapObject(thisArg).toWord());
}
}
TypeReference[] types = method.getParameterTypes();
for (int i = 0; i < types.length; i++) {
TypeReference t = types[i];
if (t.isLongType()) {
long l = Reflection.unwrapLong(otherArgs[i]);
if (VM.BuildFor64Addr) {
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, Word.fromLong(l));
} else {
gp++;
GPRs.set(--GPR, Word.fromLong(l));
}
} else {
Word hi = Word.fromIntZeroExtend((int) (l >>> 32));
Word lo = Word.fromIntZeroExtend((int) l);
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, hi);
Spills.set(--Spill, lo);
} else {
gp++;
GPRs.set(--GPR, hi);
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, lo);
} else {
gp++;
GPRs.set(--GPR, lo);
}
}
}
} else if (t.isFloatType()) {
float f = Reflection.unwrapFloat(otherArgs[i]);
if (fp > LAST_VOLATILE_FPR.value()) {
Spills.set(--Spill, Word.fromIntZeroExtend(Float.floatToIntBits(f)));
} else {
fp++;
FPRs[--FPR] = f;
}
} else if (t.isDoubleType()) {
if (fp > LAST_VOLATILE_FPR.value()) {
double d = Reflection.unwrapDouble(otherArgs[i]);
long l = Double.doubleToLongBits(d);
if (VM.BuildFor64Addr) {
Spills.set(--Spill, Word.fromLong(l));
} else {
Spills.set(--Spill, Word.fromIntZeroExtend((int) (l >>> 32)));
Spills.set(--Spill, Word.fromIntZeroExtend((int) l));
}
} else {
fp++;
FPRs[--FPR] = Reflection.unwrapDouble(otherArgs[i]);
}
} else if (t.isBooleanType()) {
Word val = Word.fromIntZeroExtend(Reflection.unwrapBooleanAsInt(otherArgs[i]));
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, val);
} else {
gp++;
GPRs.set(--GPR, val);
}
} else if (t.isByteType()) {
Word val = Word.fromIntZeroExtend(Reflection.unwrapByte(otherArgs[i]));
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, val);
} else {
gp++;
GPRs.set(--GPR, val);
}
} else if (t.isCharType()) {
Word val = Word.fromIntZeroExtend(Reflection.unwrapChar(otherArgs[i]));
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, val);
} else {
gp++;
GPRs.set(--GPR, val);
}
} else if (t.isShortType()) {
Word val = Word.fromIntZeroExtend(Reflection.unwrapShort(otherArgs[i]));
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, val);
} else {
gp++;
GPRs.set(--GPR, val);
}
} else if (t.isIntType()) {
Word val = Word.fromIntZeroExtend(Reflection.unwrapInt(otherArgs[i]));
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, val);
} else {
gp++;
GPRs.set(--GPR, val);
}
} else if (!t.isPrimitiveType()) {
Word val = Reflection.unwrapObject(otherArgs[i]).toWord();
if (gp > LAST_VOLATILE_GPR.value()) {
Spills.set(--Spill, val);
} else {
gp++;
GPRs.set(--GPR, val);
}
} else {
if (VM.VerifyAssertions) VM._assert(NOT_REACHED);
}
}
}
}