package com.oracle.truffle.llvm.parser.model.functions;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import com.oracle.truffle.api.CompilerAsserts;
import com.oracle.truffle.llvm.parser.LLVMParserRuntime;
import com.oracle.truffle.llvm.parser.metadata.MDAttachment;
import com.oracle.truffle.llvm.parser.metadata.MDString;
import com.oracle.truffle.llvm.parser.metadata.MDSubprogram;
import com.oracle.truffle.llvm.parser.metadata.MetadataAttachmentHolder;
import com.oracle.truffle.llvm.parser.metadata.debuginfo.SourceFunction;
import com.oracle.truffle.llvm.parser.model.SymbolImpl;
import com.oracle.truffle.llvm.parser.model.attributes.AttributesCodeEntry;
import com.oracle.truffle.llvm.parser.model.attributes.AttributesGroup;
import com.oracle.truffle.llvm.parser.model.blocks.InstructionBlock;
import com.oracle.truffle.llvm.parser.model.enums.Linkage;
import com.oracle.truffle.llvm.parser.model.enums.Visibility;
import com.oracle.truffle.llvm.parser.model.symbols.constants.Constant;
import com.oracle.truffle.llvm.parser.model.visitors.FunctionVisitor;
import com.oracle.truffle.llvm.parser.model.visitors.SymbolVisitor;
import com.oracle.truffle.llvm.runtime.CommonNodeFactory;
import com.oracle.truffle.llvm.runtime.GetStackSpaceFactory;
import com.oracle.truffle.llvm.runtime.LLVMFunction;
import com.oracle.truffle.llvm.runtime.datalayout.DataLayout;
import com.oracle.truffle.llvm.runtime.debug.scope.LLVMSourceLocation;
import com.oracle.truffle.llvm.runtime.nodes.api.LLVMExpressionNode;
import com.oracle.truffle.llvm.runtime.types.FunctionType;
import com.oracle.truffle.llvm.runtime.types.Type;
import com.oracle.truffle.llvm.runtime.types.symbols.LLVMIdentifier;
public final class FunctionDefinition extends FunctionSymbol implements Constant, MetadataAttachmentHolder {
public static final InstructionBlock[] EMPTY = new InstructionBlock[0];
private final List<FunctionParameter> parameters = new ArrayList<>();
private final Visibility visibility;
private List<MDAttachment> mdAttachments = null;
private SourceFunction sourceFunction = SourceFunction.DEFAULT;
private InstructionBlock[] blocks = EMPTY;
private int currentBlock = 0;
private FunctionDefinition(FunctionType type, String name, Linkage linkage, Visibility visibility, AttributesCodeEntry paramAttr, int index) {
super(type, name, linkage, paramAttr, index);
this.visibility = visibility;
}
public FunctionDefinition(FunctionType type, Linkage linkage, Visibility visibility, AttributesCodeEntry paramAttr, int index) {
this(type, LLVMIdentifier.UNKNOWN, linkage, visibility, paramAttr, index);
}
@Override
public boolean hasAttachedMetadata() {
return mdAttachments != null;
}
@Override
public List<MDAttachment> getAttachedMetadata() {
if (mdAttachments == null) {
mdAttachments = new ArrayList<>(1);
}
return mdAttachments;
}
public String getSourceName() {
final String scopeName = sourceFunction.getName();
return SourceFunction.DEFAULT_SOURCE_NAME.equals(scopeName) ? null : scopeName;
}
public String getDisplayName() {
if (mdAttachments != null && mdAttachments.size() > 0) {
for (MDAttachment mdAttachment : mdAttachments) {
if (mdAttachment.getValue() instanceof MDSubprogram) {
MDSubprogram mdSubprogram = (MDSubprogram) mdAttachment.getValue();
if (mdSubprogram.getName() instanceof MDString) {
return ((MDString) mdSubprogram.getName()).getString();
}
}
}
}
return getSourceName();
}
@Override
public void replace(SymbolImpl oldValue, SymbolImpl newValue) {
}
@Override
public void accept(SymbolVisitor visitor) {
visitor.visit(this);
}
public void accept(FunctionVisitor visitor) {
for (InstructionBlock block : blocks) {
visitor.visit(block);
}
}
public void allocateBlocks(int count) {
blocks = new InstructionBlock[count];
for (int i = 0; i < count; i++) {
blocks[i] = new InstructionBlock(i);
}
}
public FunctionParameter createParameter(Type t) {
final int argIndex = parameters.size();
final AttributesGroup attrGroup = getParameterAttributesGroup(argIndex);
final FunctionParameter parameter = new FunctionParameter(t, attrGroup, argIndex);
parameters.add(parameter);
return parameter;
}
public InstructionBlock generateBlock() {
return blocks[currentBlock++];
}
public InstructionBlock getBlock(long idx) {
CompilerAsserts.neverPartOfCompilation();
return blocks[(int) idx];
}
public List<InstructionBlock> getBlocks() {
CompilerAsserts.neverPartOfCompilation();
return Arrays.asList(blocks);
}
public List<FunctionParameter> getParameters() {
CompilerAsserts.neverPartOfCompilation();
return parameters;
}
public void nameBlock(int index, String argName) {
blocks[index].setName(argName);
}
public void onAfterParse() {
blocks = EMPTY;
currentBlock = 0;
mdAttachments = null;
sourceFunction.clearLocals();
parameters.clear();
}
@Override
public int hashCode() {
CompilerAsserts.neverPartOfCompilation();
return super.hashCode();
}
@Override
public boolean equals(Object obj) {
CompilerAsserts.neverPartOfCompilation();
return super.equals(obj);
}
@Override
public String toString() {
CompilerAsserts.neverPartOfCompilation();
return String.format("%s %s {...}", getType(), getName());
}
public LLVMSourceLocation getLexicalScope() {
return sourceFunction != null ? sourceFunction.getLexicalScope() : null;
}
public SourceFunction getSourceFunction() {
return sourceFunction;
}
public void setSourceFunction(SourceFunction sourceFunction) {
this.sourceFunction = sourceFunction;
}
@Override
public boolean isExported() {
return Linkage.isExported(getLinkage(), visibility);
}
@Override
public boolean isOverridable() {
return Linkage.isOverridable(getLinkage(), visibility);
}
@Override
public boolean isExternal() {
return Linkage.isExternal(getLinkage());
}
@Override
public LLVMExpressionNode createNode(LLVMParserRuntime runtime, DataLayout dataLayout, GetStackSpaceFactory stackFactory) {
LLVMFunction value = runtime.lookupFunction(getName());
return CommonNodeFactory.createLiteral(value, getType());
}
}