package org.graalvm.compiler.nodes.spi;
import static jdk.vm.ci.services.Services.IS_BUILDING_NATIVE_IMAGE;
import org.graalvm.compiler.api.replacements.Snippet;
import jdk.vm.ci.meta.JavaKind;
import jdk.vm.ci.meta.Local;
import jdk.vm.ci.meta.LocalVariableTable;
import jdk.vm.ci.meta.ResolvedJavaMethod;
public class SnippetParameterInfo {
public SnippetParameterInfo(ResolvedJavaMethod method) {
assert method.getAnnotation(Snippet.class) != null : method + " must be annotated with @" + Snippet.class.getSimpleName();
int parameterCount = method.getSignature().getParameterCount(method.hasReceiver());
if (parameterCount > Integer.SIZE) {
throw new UnsupportedOperationException("too many arguments");
}
this.count = parameterCount;
int constant = 0;
int varargs = 0;
int nonNull = 0;
int offset = method.hasReceiver() ? 1 : 0;
for (int i = offset; i < count; i++) {
int bit = 1 << i;
if (method.getParameterAnnotation(Snippet.ConstantParameter.class, i - offset) != null) {
constant |= bit;
}
if (method.getParameterAnnotation(Snippet.VarargsParameter.class, i - offset) != null) {
varargs |= bit;
}
if (method.getParameterAnnotation(Snippet.NonNullParameter.class, i - offset) != null) {
nonNull |= bit;
}
assert ((constant & bit) == 0) || ((varargs & bit) == 0) : "Parameter cannot be annotated with both @" + Snippet.ConstantParameter.class.getSimpleName() + " and @" +
Snippet.VarargsParameter.class.getSimpleName();
}
if (method.hasReceiver()) {
assert (constant & 1) == 0;
constant |= 1;
}
this.constantParametersBits = constant;
this.varargsParametersBits = varargs;
this.nonNullParametersBits = nonNull;
if (IS_BUILDING_NATIVE_IMAGE) {
initNames(method, count);
} else {
assert initNames(method, count);
}
}
private final int count;
private final int constantParametersBits;
private final int varargsParametersBits;
private final int nonNullParametersBits;
public int getParameterCount() {
return count;
}
public boolean isConstantParameter(int paramIdx) {
return ((constantParametersBits >>> paramIdx) & 1) != 0;
}
public boolean isVarargsParameter(int paramIdx) {
return ((varargsParametersBits >>> paramIdx) & 1) != 0;
}
public boolean isNonNullParameter(int paramIdx) {
return ((nonNullParametersBits >>> paramIdx) & 1) != 0;
}
public String getParameterName(int paramIdx) {
if (names != null) {
return names[paramIdx];
}
return null;
}
String[] names;
private boolean initNames(ResolvedJavaMethod method, int parameterCount) {
names = new String[parameterCount];
int offset = 0;
if (method.hasReceiver()) {
names[0] = "this";
offset = 1;
}
ResolvedJavaMethod.Parameter[] params = method.getParameters();
if (params != null) {
for (int i = offset; i < names.length; i++) {
if (params[i - offset].isNamePresent()) {
names[i] = params[i - offset].getName();
}
}
} else {
int slotIdx = 0;
LocalVariableTable localVariableTable = method.getLocalVariableTable();
if (localVariableTable != null) {
for (int i = 0; i < names.length; i++) {
Local local = localVariableTable.getLocal(slotIdx, 0);
if (local != null) {
names[i] = local.getName();
}
JavaKind kind = method.getSignature().getParameterKind(i);
slotIdx += kind.getSlotCount();
}
}
}
return true;
}
public void clearNames() {
names = null;
}
}