/*
* 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.ia32;
import static org.jikesrvm.ia32.ArchConstants.SSE2_FULL;
import static org.jikesrvm.ia32.RegisterConstants.NUM_PARAMETER_FPRS;
import static org.jikesrvm.ia32.RegisterConstants.NUM_PARAMETER_GPRS;
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.Magic;
import org.vmmagic.pragma.UnpreemptibleNoWarn;
import org.vmmagic.unboxed.Word;
import org.vmmagic.unboxed.WordArray;
/**
* Machine dependent portion of Reflective method invoker.
*/
public abstract class MachineReflection {
/**
* Determines number/type of registers and parameters required to
* call specified method.
* Unlike the PowerPC code we count all the parameters, not just the
* ones that spill. This allow us to make enough space on the stack
* following the calling convention.
*
* @param method the method whose parameters to count
* @return number of parameters, gprs and frps encoded in a triple
*/
public static int countParameters(RVMMethod method) {
int GPRs = 0;
int FPRs = 0;
int parameters = 0; // parameters size in 32-bits quant.
int gp = NUM_PARAMETER_GPRS; // 0, 1, 2
int fp = NUM_PARAMETER_FPRS; // 0-8
if (!method.isStatic()) {
if (gp > 0) {
GPRs++;
gp--;
}
parameters++;
}
for (TypeReference t : method.getParameterTypes()) {
if (t.isLongType()) {
if (gp > 0) {
GPRs++;
gp--;
if (VM.BuildFor32Addr && gp > 0) {
GPRs++;
gp--;
}
}
parameters += 2;
} else if (t.isFloatType()) {
if (fp > 0) {
FPRs++;
fp--;
}
parameters++;
} else if (t.isDoubleType()) {
if (fp > 0) {
FPRs++;
fp--;
}
parameters += 2;
} else { // t is object, int, short, char, byte, or boolean
if (gp > 0) {
GPRs++;
gp--;
}
parameters++;
}
}
// hack to return triple
return (parameters << (REFLECTION_FPRS_BITS + REFLECTION_GPRS_BITS)) |
(FPRs << REFLECTION_GPRS_BITS) |
GPRs;
}
/**
* Collects parameters into arrays of registers/spills, as required to
* call specified method.
*
* @param method method whose parameters are to be packaged
* @param thisArg the receiver argument
* @param otherArgs all other arguments (primitives are boxed)
* @param GPRs space for GPRs (empty array if none needed)
* @param FPRs space for FPRs (empty array if none needed)
* @param FPRmeta meta-data for FPRs ({@code null} if no SSE2)
* @param Parameters more space for parameters. Refer to the source code
* to get all the details.
*
* @see #countParameters(RVMMethod) more machine-specific details
*/
@UnpreemptibleNoWarn("GC is disabled as Objects are turned into Words." +
"avoid preemption but still allow calls to preemptible unboxing routines")
public static void packageParameters(RVMMethod method, Object thisArg, Object[] otherArgs, WordArray GPRs,
double[] FPRs, byte[] FPRmeta, WordArray Parameters) {
int GPR = 0;
int FPR = SSE2_FULL ? 0 : FPRs.length;
int parameter = 0;
int gp = NUM_PARAMETER_GPRS; // 0, 1, 2
int fp = NUM_PARAMETER_FPRS; // 0-8
if (!method.isStatic()) {
Word val = Magic.objectAsAddress(thisArg).toWord();
if (gp > 0) {
gp--;
GPRs.set(GPR++, val);
}
Parameters.set(parameter++, val);
}
TypeReference[] types = method.getParameterTypes();
for (int i = 0; i < types.length; i++) {
TypeReference t = types[i];
if (!t.isPrimitiveType()) {
Word val = Magic.objectAsAddress(otherArgs[i]).toWord();
if (gp > 0) {
gp--;
GPRs.set(GPR++, val);
}
Parameters.set(parameter++, val);
} else if (t.isLongType()) {
long l = (Long)otherArgs[i];
if (VM.BuildFor32Addr) {
if (gp > 0) {
gp--;
GPRs.set(GPR++, Word.fromIntZeroExtend((int) (l >>> 32)));
if (gp > 0) {
gp--;
GPRs.set(GPR++, Word.fromIntZeroExtend((int) (l)));
}
}
Parameters.set(parameter++, Word.fromIntZeroExtend((int) (l >>> 32)));
Parameters.set(parameter++, Word.fromIntZeroExtend((int) l));
} else {
Word val = Word.fromLong(l);
if (gp > 0) {
gp--;
GPRs.set(GPR++, val);
}
Parameters.set(parameter++, val);
Parameters.set(parameter++, val);
}
} else if (t.isFloatType()) {
if (fp > 0) {
fp--;
if (SSE2_FULL) {
FPRs[FPR] = (Float)otherArgs[i];
FPRmeta[FPR] = 0x0;
FPR++;
} else {
FPRs[--FPR] = (Float)otherArgs[i];
}
}
float f = (Float)otherArgs[i];
Parameters.set(parameter++, Word.fromIntZeroExtend(Float.floatToIntBits(f)));
} else if (t.isDoubleType()) {
if (VM.BuildFor32Addr) {
if (fp > 0) {
fp--;
if (SSE2_FULL) {
FPRs[FPR] = (Double)otherArgs[i];
FPRmeta[FPR] = 0x1;
FPR++;
} else {
FPRs[--FPR] = (Double)otherArgs[i];
}
}
double d = (Double)otherArgs[i];
long l = Double.doubleToLongBits(d);
Parameters.set(parameter++, Word.fromIntZeroExtend((int) (l >>> 32)));
Parameters.set(parameter++, Word.fromIntZeroExtend((int) l));
} else {
if (fp > 0) {
fp--;
if (SSE2_FULL) {
FPRs[FPR] = (Double)otherArgs[i];
FPRmeta[FPR] = 0x1;
FPR++;
} else {
FPRs[--FPR] = (Double)otherArgs[i];
}
}
double d = (Double)otherArgs[i];
long l = Double.doubleToLongBits(d);
Word val = Word.fromLong(l);
Parameters.set(parameter++, val);
Parameters.set(parameter++, val);
}
} else if (t.isBooleanType()) {
boolean b = (Boolean)otherArgs[i];
Word val = Word.fromIntZeroExtend(b ? 1 : 0);
if (gp > 0) {
gp--;
GPRs.set(GPR++, val);
}
Parameters.set(parameter++, val);
} else if (t.isCharType()) {
char c = (Character)otherArgs[i];
Word val = Word.fromIntZeroExtend(c);
if (gp > 0) {
gp--;
GPRs.set(GPR++, val);
}
Parameters.set(parameter++, val);
} else {
if (VM.VerifyAssertions) VM._assert(t.isByteType() || t.isShortType() || t.isIntType());
int x = ((Number)otherArgs[i]).intValue();
Word val = Word.fromIntZeroExtend(x);
if (gp > 0) {
gp--;
GPRs.set(GPR++, val);
}
Parameters.set(parameter++, val);
}
}
}
}