Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,12 @@
package com.oracle.svm.hosted.c.codegen;

import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
import static com.oracle.svm.core.util.VMError.shouldNotReachHereUnexpectedInput;
import static com.oracle.svm.hosted.NativeImageOptions.CStandards.C11;
import static com.oracle.svm.hosted.NativeImageOptions.CStandards.C99;

import java.io.BufferedWriter;
import java.io.IOException;
import java.lang.reflect.AnnotatedType;
import java.nio.channels.ClosedByInterruptException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
Expand All @@ -40,12 +40,10 @@
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.graalvm.nativeimage.c.function.CFunctionPointer;
import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer;
import org.graalvm.word.SignedWord;
import org.graalvm.word.UnsignedWord;
import org.graalvm.nativeimage.c.type.CTypedef;

import com.oracle.svm.core.util.InterruptImageBuilding;
import com.oracle.svm.core.util.UserError;
Expand Down Expand Up @@ -108,11 +106,11 @@ public void includeFiles(List<String> headerFiles) {
if (headerFile.startsWith("<") && headerFile.endsWith(">")) {
headerFileName = headerFile.substring(1, headerFile.length() - 1);
Path headerFilePath = Paths.get(headerFileName);
appendln("#include " + "<" + headerFilePath.toString() + ">");
appendln("#include " + "<" + headerFilePath + ">");
} else if (headerFile.startsWith("\"") && headerFile.endsWith("\"")) {
headerFileName = headerFile.substring(1, headerFile.length() - 1);
Path headerFilePath = Paths.get(headerFileName);
appendln("#include " + "\"" + headerFilePath.toString() + "\"");
appendln("#include " + "\"" + headerFilePath + "\"");
} else {
throw UserError.abort("Header file name must be surrounded by <...> or \"...\": %s", headerFile);
}
Expand All @@ -130,7 +128,7 @@ public CSourceCodeWriter printf(String firstArg, String secondArg, String thirdA
}

public CSourceCodeWriter indents() {
assert currentLine.length() == 0 : "indenting in the middle of a line";
assert currentLine.isEmpty() : "indenting in the middle of a line";
for (int i = 0; i < indentLevel; i++) {
append(INDENT4);
}
Expand Down Expand Up @@ -167,7 +165,7 @@ public CSourceCodeWriter append(String str) {
}

public Path writeFile(String fileName) {
assert currentLine.length() == 0 : "last line not finished";
assert currentLine.isEmpty() : "last line not finished";

Path outputFile = tempDirectory.resolve(fileName);
try (BufferedWriter writer = Files.newBufferedWriter(outputFile, StandardCharsets.UTF_8)) {
Expand All @@ -184,83 +182,82 @@ public Path writeFile(String fileName) {
return outputFile;
}

public static String toCTypeName(ResolvedJavaMethod method, ResolvedJavaType type, Optional<String> useSiteTypedef, boolean isConst, boolean isUnsigned, MetaAccessProvider metaAccess,
NativeLibraries nativeLibs) {
boolean isNumericInteger = type.getJavaKind().isNumericInteger();
UserError.guarantee(isNumericInteger || !isUnsigned,
"Only integer types can be unsigned. %s is not an integer type in %s", type, method);

boolean isUnsignedWord = metaAccess.lookupJavaType(UnsignedWord.class).isAssignableFrom(type);
boolean isSignedWord = metaAccess.lookupJavaType(SignedWord.class).isAssignableFrom(type);
boolean isWord = isUnsignedWord || isSignedWord;
boolean isObject = type.getJavaKind() == JavaKind.Object && !isWord;
UserError.guarantee(isObject || !isConst,
"Only pointer types can be const. %s in method %s is not a pointer type.", type, method);

if (useSiteTypedef.isPresent()) {
return (isConst ? "const " : "") + useSiteTypedef.get();
} else if (isNumericInteger) {
return toCIntegerType(type, isUnsigned);
} else if (isUnsignedWord) {
return "size_t";
} else if (isSignedWord) {
return "ssize_t";
} else if (isObject) {
public static String toCTypeName(ResolvedJavaMethod method, ResolvedJavaType type, AnnotatedType annotatedType, boolean isConst, MetaAccessProvider metaAccess, NativeLibraries nativeLibs) {
CTypedef typeDef = annotatedType.getAnnotation(CTypedef.class);
if (typeDef != null) {
return (isConst ? "const " : "") + typeDef.name();
}

JavaKind kind = type.getJavaKind();
if (kind.isObject() && !nativeLibs.isIntegerType(type)) {
return (isConst ? "const " : "") + cTypeForObject(type, metaAccess, nativeLibs);
} else {
switch (type.getJavaKind()) {
case Double:
return "double";
case Float:
return "float";
case Void:
return "void";
default:
throw shouldNotReachHereUnexpectedInput(type.getJavaKind()); // ExcludeFromJacocoGeneratedReport
}
}

UserError.guarantee(!isConst, "Only pointer types can be const. %s in method %s is not a pointer type.", type, method);
return cTypeForPrimitive(method, type, annotatedType, nativeLibs);
}

private static String cTypeForObject(ResolvedJavaType type, MetaAccessProvider metaAccess, NativeLibraries nativeLibs) {
ElementInfo elementInfo = nativeLibs.findElementInfo(type);
if (elementInfo instanceof PointerToInfo) {
PointerToInfo pointerToInfo = (PointerToInfo) elementInfo;
if (elementInfo instanceof PointerToInfo pointerToInfo) {
return (pointerToInfo.getTypedefName() != null ? pointerToInfo.getTypedefName() : pointerToInfo.getName() + "*");
} else if (elementInfo instanceof StructInfo) {
StructInfo structInfo = (StructInfo) elementInfo;
} else if (elementInfo instanceof StructInfo structInfo) {
return structInfo.getTypedefName() != null ? structInfo.getTypedefName() : structInfo.getName() + "*";
} else if (elementInfo instanceof EnumInfo) {
return elementInfo.getName();
} else if (isFunctionPointer(metaAccess, type)) {
return InfoTreeBuilder.getTypedefName(type) != null ? InfoTreeBuilder.getTypedefName(type) : "void *";
} else if (isFunctionPointer(metaAccess, type) && InfoTreeBuilder.getTypedefName(type) != null) {
return InfoTreeBuilder.getTypedefName(type);
} else {
return "void *";
}
return "void *";
}

private static String toCIntegerType(ResolvedJavaType type, boolean isUnsigned) {
private static String cTypeForPrimitive(ResolvedJavaMethod method, ResolvedJavaType type, AnnotatedType annotatedType, NativeLibraries nativeLibs) {
boolean c11Compatible = NativeImageOptions.getCStandard().compatibleWith(C11);
String prefix = "";
if (isUnsigned) {
if (isUnsigned(annotatedType)) {
prefix = c11Compatible ? "u" : "unsigned ";
}
switch (type.getJavaKind()) {
case Boolean:
if (NativeImageOptions.getCStandard().compatibleWith(CStandards.C99)) {
return "bool";
} else {
return "int";
}

JavaKind javaKind = type.getJavaKind();
switch (javaKind) {
case Byte:
return prefix + (c11Compatible ? "int8_t" : "char");
case Char:
case Short:
case Char:
return prefix + (c11Compatible ? "int16_t" : "short");
case Int:
return prefix + (c11Compatible ? "int32_t" : "int");
case Long:
return prefix + (c11Compatible ? "int64_t" : "long long int");
}
throw VMError.shouldNotReachHere("All types integer types should be covered. Got " + type.getJavaKind());

UserError.guarantee(prefix.isEmpty(), "Only integer types can be annotated with @%s. %s in method %s is not an integer type.",
org.graalvm.nativeimage.c.type.CUnsigned.class.getSimpleName(), type, method);
switch (javaKind) {
case Boolean:
if (NativeImageOptions.getCStandard().compatibleWith(CStandards.C99)) {
return "bool";
} else {
return "int";
}
case Float:
return "float";
case Double:
return "double";
case Void:
return "void";
case Object:
/* SignedWord or UnsignedWord. */
assert nativeLibs.isIntegerType(type);
return nativeLibs.isSigned(type) ? "ssize_t" : "size_t";
default:
throw VMError.shouldNotReachHere("Unexpected Java kind " + javaKind);
}
}

private static boolean isUnsigned(AnnotatedType type) {
return type.isAnnotationPresent(org.graalvm.nativeimage.c.type.CUnsigned.class) || type.isAnnotationPresent(com.oracle.svm.core.c.CUnsigned.class);
}

private static boolean isFunctionPointer(MetaAccessProvider metaAccess, ResolvedJavaType type) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

Expand All @@ -58,8 +57,6 @@
import org.graalvm.nativeimage.c.function.CEntryPoint.Publish;
import org.graalvm.nativeimage.c.function.CFunctionPointer;
import org.graalvm.nativeimage.c.type.CConst;
import org.graalvm.nativeimage.c.type.CTypedef;
import org.graalvm.nativeimage.c.type.CUnsigned;

import com.oracle.graal.pointsto.meta.AnalysisMethod;
import com.oracle.graal.pointsto.meta.AnalysisType;
Expand Down Expand Up @@ -317,14 +314,16 @@ private static int sortMethodsByFileNameAndPosition(HostedMethod stub1, HostedMe
return rm1Line - rm2Line;
}

private static boolean isUnsigned(AnnotatedType type) {
var legacyCUnsigned = com.oracle.svm.core.c.CUnsigned.class;
return type.isAnnotationPresent(CUnsigned.class) || type.isAnnotationPresent(legacyCUnsigned);
}
private void writeMethodHeader(HostedMethod stubMethod, CSourceCodeWriter writer, boolean dynamic) {
assert Modifier.isStatic(stubMethod.getModifiers()) : "Published methods that go into the header must be static.";

/*
* Get the target method that will be invoked by the stub. We need its signature because the
* stub signature has different types (primitive instead of object types) and no metadata.
*/
HostedMethod targetMethod = metaAccess.lookupJavaMethod(getMethod(stubMethod));

private void writeMethodHeader(HostedMethod m, CSourceCodeWriter writer, boolean dynamic) {
assert Modifier.isStatic(m.getModifiers()) : "Published methods that go into the header must be static.";
CEntryPointData cEntryPointData = (CEntryPointData) m.getWrapped().getNativeEntryPointData();
CEntryPointData cEntryPointData = (CEntryPointData) stubMethod.getWrapped().getNativeEntryPointData();
String docComment = cEntryPointData.getDocumentation();
if (docComment != null && !docComment.isEmpty()) {
writer.appendln("/*");
Expand All @@ -336,13 +335,8 @@ private void writeMethodHeader(HostedMethod m, CSourceCodeWriter writer, boolean
writer.append("typedef ");
}

AnnotatedType annotatedReturnType = getAnnotatedReturnType(m);
writer.append(CSourceCodeWriter.toCTypeName(m,
m.getSignature().getReturnType(),
Optional.ofNullable(annotatedReturnType.getAnnotation(CTypedef.class)).map(CTypedef::name),
false,
isUnsigned(annotatedReturnType),
metaAccess, nativeLibs));
var signature = targetMethod.getSignature();
writer.append(CSourceCodeWriter.toCTypeName(targetMethod, signature.getReturnType(), getAnnotatedReturnType(stubMethod), false, metaAccess, nativeLibs));
writer.append(" ");

String symbolName = cEntryPointData.getSymbolName();
Expand All @@ -354,19 +348,20 @@ private void writeMethodHeader(HostedMethod m, CSourceCodeWriter writer, boolean
}
writer.append("(");

String sep = "";
AnnotatedType[] annotatedParameterTypes = getAnnotatedParameterTypes(m);
Parameter[] parameters = m.getParameters();
assert parameters != null;
for (int i = 0; i < m.getSignature().getParameterCount(false); i++) {
writer.append(sep);
sep = ", ";
writer.append(CSourceCodeWriter.toCTypeName(m,
m.getSignature().getParameterType(i),
Optional.ofNullable(annotatedParameterTypes[i].getAnnotation(CTypedef.class)).map(CTypedef::name),
annotatedParameterTypes[i].isAnnotationPresent(CConst.class),
isUnsigned(annotatedParameterTypes[i]),
metaAccess, nativeLibs));
/* Write the signature. */
int numParams = signature.getParameterCount(false);
AnnotatedType[] annotatedTypes = getAnnotatedParameterTypes(stubMethod);
Parameter[] parameters = targetMethod.getParameters();
assert annotatedTypes.length == numParams;
assert parameters.length == numParams;

for (int i = 0; i < numParams; i++) {
if (i > 0) {
writer.append(", ");
}

boolean isConst = annotatedTypes[i].isAnnotationPresent(CConst.class);
writer.append(CSourceCodeWriter.toCTypeName(targetMethod, signature.getParameterType(i), annotatedTypes[i], isConst, metaAccess, nativeLibs));
if (parameters[i].isNamePresent()) {
writer.append(" ");
writer.append(parameters[i].getName());
Expand All @@ -388,14 +383,12 @@ private AnnotatedType[] getAnnotatedParameterTypes(HostedMethod hostedMethod) {

private Method getMethod(HostedMethod hostedMethod) {
AnalysisMethod entryPoint = CEntryPointCallStubSupport.singleton().getMethodForStub(((CEntryPointCallStubMethod) hostedMethod.wrapped.wrapped));
Method method;
try {
method = entryPoint.getDeclaringClass().getJavaClass().getDeclaredMethod(entryPoint.getName(),
return entryPoint.getDeclaringClass().getJavaClass().getDeclaredMethod(entryPoint.getName(),
MethodType.fromMethodDescriptorString(entryPoint.getSignature().toMethodDescriptor(), imageClassLoader).parameterArray());
} catch (NoSuchMethodException e) {
throw shouldNotReachHere(e);
}
return method;
}

private boolean shouldWriteHeader(HostedMethod method) {
Expand Down