/*
* Copyright (c) 2018, 2020, Oracle and/or its affiliates.
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are
* permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of
* conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided
* with the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written
* permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
* GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.oracle.truffle.llvm.runtime.debug.type;
import com.oracle.truffle.api.CompilerDirectives;
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
public class LLVMSourceFunctionType extends LLVMSourceType {
private final List<LLVMSourceType> types;
@TruffleBoundary
public LLVMSourceFunctionType(List<LLVMSourceType> types) {
// function type do not require size or offset information since there are no concrete
// values of them in C/C++/Fortran. they are only used as basis for function pointers
super(0L, 0L, 0L, null);
assert types != null;
this.types = types;
setName(() -> {
CompilerDirectives.transferToInterpreter();
StringBuilder nameBuilder = new StringBuilder(getReturnType().getName()).append("(");
final List<LLVMSourceType> params = getParameterTypes();
if (params.size() > 0) {
nameBuilder.append(params.get(0).getName());
}
for (int i = 1; i < params.size(); i++) {
nameBuilder.append(", ").append(params.get(i).getName());
}
if (!isVarArgs()) {
nameBuilder.append(")");
} else if (getParameterTypes().size() == 0) {
nameBuilder.append("...)");
} else {
nameBuilder.append(", ...)");
}
return nameBuilder.toString();
});
}
@TruffleBoundary
public LLVMSourceType getReturnType() {
if (types.size() > 0) {
return types.get(0);
} else {
return LLVMSourceType.VOID;
}
}
@TruffleBoundary
public int getNumberOfParameters() {
return Math.max(0, types.size() - 1);
}
@TruffleBoundary
public List<LLVMSourceType> getParameterTypes() {
if (types.size() <= 1) {
return Collections.emptyList();
} else {
return types.subList(1, types.size() - (isVarArgs() ? 1 : 0));
}
}
@TruffleBoundary
public boolean isVarArgs() {
return types.size() > 1 && types.get(types.size() - 1) == LLVMSourceType.VOID;
}
@Override
public LLVMSourceType getOffset(long newOffset) {
return this;
}
Helper class used to carry information about function argument locations in source code and
bitcode when they mismatch. Cases where that could happen is when the compiler desugars
structs, examples:
struct Point { double x; double y; };
void func (struct Point p); -> void func(double px, double py);
/**
* Helper class used to carry information about function argument locations in source code and
* bitcode when they mismatch. Cases where that could happen is when the compiler desugars
* structs, examples:
*
* <pre>
* struct Point { double x; double y; };
* void func (struct Point p); -> void func(double px, double py);
* </pre>
*/
public static final class SourceArgumentInformation {
private final int bitcodeArgIndex;
private final int sourceArgIndex;
private final int offset;
private final int size;
private static final SourceArgumentInformation INVALID = new SourceArgumentInformation(-1, -1, -1, -1);
Params: - bitcodeArgIndex – Argument location in bitcode.
- sourceArgIndex – Argument location in source code.
- offset – The offset in bits of the bitcode argument in the source code (e.g. in a
struct).
- size – The size of the argument type in bits.
/**
* @param bitcodeArgIndex Argument location in bitcode.
* @param sourceArgIndex Argument location in source code.
* @param offset The offset in bits of the bitcode argument in the source code (e.g. in a
* struct).
* @param size The size of the argument type in bits.
*/
SourceArgumentInformation(int bitcodeArgIndex, int sourceArgIndex, int offset, int size) {
this.bitcodeArgIndex = bitcodeArgIndex;
this.sourceArgIndex = sourceArgIndex;
this.offset = offset;
this.size = size;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
SourceArgumentInformation that = (SourceArgumentInformation) o;
return bitcodeArgIndex == that.bitcodeArgIndex &&
sourceArgIndex == that.sourceArgIndex &&
offset == that.offset &&
size == that.size;
}
@Override
public int hashCode() {
return Objects.hash(bitcodeArgIndex, sourceArgIndex, offset, size);
}
@Override
public String toString() {
return "SourceArgumentInformation(" +
"bcArgIdx=" + bitcodeArgIndex +
", srcArgIdx=" + sourceArgIndex +
", offset=" + offset +
", size=" + size +
')';
}
public long getBitcodeArgIndex() {
return this.bitcodeArgIndex;
}
public int getSourceArgIndex() {
return this.sourceArgIndex;
}
Returns: The member offset in bits.
/**
* @return The member offset in bits.
*/
public int getOffset() {
return this.offset;
}
Returns: The argument type size in bits.
/**
* @return The argument type size in bits.
*/
public int getSize() {
return this.size;
}
}
List carrying information for function arguments that mismatch between the source code and
the bitcode. It is expected for arguments that do not have any mismatches to have a null
entry here. This list can be null if there's no debugging information (or no recognizable
debugging information, e.g. due to a missing implementation) associated with the function.
/**
* List carrying information for function arguments that mismatch between the source code and
* the bitcode. It is expected for arguments that do not have any mismatches to have a null
* entry here. This list can be null if there's no debugging information (or no recognizable
* debugging information, e.g. due to a missing implementation) associated with the function.
*/
private ArrayList<SourceArgumentInformation> sourceArgumentInformationList;
Add information for an argument at the location equal to its bitcode location, any arguments in between shall be set to null (see the sourceArgumentInformationList
). Nulls representing non-mismatching arguments that come after the last mismatching argument are dealt with in getSourceArgumentInformation
. /**
* Add information for an argument at the location equal to its bitcode location, any arguments
* in between shall be set to null (see the
* {@link LLVMSourceFunctionType#sourceArgumentInformationList}). Nulls representing
* non-mismatching arguments that come after the last mismatching argument are dealt with in
* {@link LLVMSourceFunctionType#getSourceArgumentInformation}.
*/
public void attachSourceArgumentInformation(int bitcodeArgIndex, int sourceArgIndex, int offset, int size) {
if (sourceArgumentInformationList == null) {
sourceArgumentInformationList = new ArrayList<>();
}
ensureCapacity(sourceArgumentInformationList, bitcodeArgIndex + 1);
if (sourceArgumentInformationList.get(bitcodeArgIndex) == null) {
sourceArgumentInformationList.set(bitcodeArgIndex, new SourceArgumentInformation(bitcodeArgIndex, sourceArgIndex, offset, size));
} else {
// do not override existing info
sourceArgumentInformationList.set(bitcodeArgIndex, SourceArgumentInformation.INVALID);
}
}
private static void ensureCapacity(ArrayList<?> list, int capacity) {
for (int diff = capacity - list.size(); diff > 0; diff--) {
list.add(null);
}
}
public SourceArgumentInformation getSourceArgumentInformation(int index) {
if (sourceArgumentInformationList == null || index >= sourceArgumentInformationList.size()) {
return null;
}
SourceArgumentInformation info = sourceArgumentInformationList.get(index);
if (SourceArgumentInformation.INVALID.equals(info)) {
return null;
}
return info;
}
}