package com.oracle.truffle.llvm.runtime.types;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import com.oracle.truffle.llvm.runtime.CommonNodeFactory;
import com.oracle.truffle.llvm.runtime.GetStackSpaceFactory;
import com.oracle.truffle.llvm.runtime.NodeFactory;
import com.oracle.truffle.llvm.runtime.datalayout.DataLayout;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMNode;
import com.oracle.truffle.llvm.runtime.types.visitors.TypeVisitor;
public final class FunctionType extends Type {
private Type returnType;
private final Type[] argumentTypes;
private final boolean isVarargs;
private FunctionType(Type returnType, Type[] argumentTypes, boolean isVarargs) {
this.returnType = returnType;
this.argumentTypes = argumentTypes;
this.isVarargs = isVarargs;
}
public static FunctionType create(Type returnType, Type arg0, boolean isVarargs) {
return new FunctionType(returnType, new Type[]{arg0}, isVarargs);
}
public FunctionType(Type returnType, TypeArrayBuilder argumentTypes, boolean isVarargs) {
this(returnType, getRawTypeArray(argumentTypes), isVarargs);
}
public FunctionType(Type returnType, int numArguments, boolean isVarargs) {
this(returnType, new Type[numArguments], isVarargs);
}
public static FunctionType copy(FunctionType type) {
return new FunctionType(type.returnType, type.argumentTypes.clone(), type.isVarargs);
}
public void setArgumentType(int idx, Type type) {
verifyCycleFree(type);
argumentTypes[idx] = type;
}
public List<Type> getArgumentTypes() {
return Collections.unmodifiableList(Arrays.asList(argumentTypes));
}
public Type getArgumentType(int idx) {
return argumentTypes[idx];
}
public int getNumberOfArguments() {
return argumentTypes.length;
}
public Type getReturnType() {
CompilerAsserts.neverPartOfCompilation();
return returnType;
}
public void setReturnType(Type returnType) {
CompilerAsserts.neverPartOfCompilation();
verifyCycleFree(returnType);
this.returnType = returnType;
}
public boolean isVarargs() {
return isVarargs;
}
@Override
public long getBitSize() {
return 0;
}
@Override
public void accept(TypeVisitor visitor) {
visitor.visit(this);
}
@Override
public int getAlignment(DataLayout targetDataLayout) {
if (targetDataLayout != null) {
return targetDataLayout.getBitAlignment(this) / Byte.SIZE;
} else {
return Long.BYTES;
}
}
@Override
public long getSize(DataLayout targetDataLayout) {
return LLVMNode.ADDRESS_SIZE_IN_BYTES;
}
@Override
@TruffleBoundary
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(getReturnType()).append(" (");
for (int i = 0; i < argumentTypes.length; i++) {
if (i > 0) {
sb.append(", ");
}
sb.append(argumentTypes[i]);
}
if (isVarargs) {
if (argumentTypes.length > 0) {
sb.append(", ");
}
sb.append("...");
}
sb.append(")");
return sb.toString();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(argumentTypes);
result = prime * result + (isVarargs ? 1231 : 1237);
result = prime * result + ((getReturnType() == null) ? 0 : getReturnType().hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
FunctionType other = (FunctionType) obj;
if (!Arrays.equals(argumentTypes, other.argumentTypes)) {
return false;
}
if (isVarargs != other.isVarargs) {
return false;
}
if (getReturnType() == null) {
if (other.getReturnType() != null) {
return false;
}
} else if (!getReturnType().equals(other.getReturnType())) {
return false;
}
return true;
}
@Override
public LLVMExpressionNode createNullConstant(NodeFactory nodeFactory, DataLayout dataLayout, GetStackSpaceFactory stackFactory) {
return CommonNodeFactory.createSimpleConstantNoArray(null, this);
}
}