diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CSourceCodeWriter.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CSourceCodeWriter.java index b4f22367d1c5..bfd3bb73ee80 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CSourceCodeWriter.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CSourceCodeWriter.java @@ -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; @@ -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; @@ -108,11 +106,11 @@ public void includeFiles(List 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); } @@ -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); } @@ -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)) { @@ -184,83 +182,82 @@ public Path writeFile(String fileName) { return outputFile; } - public static String toCTypeName(ResolvedJavaMethod method, ResolvedJavaType type, Optional 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) { diff --git a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java index a2c4793124db..2b26bbb14ae7 100644 --- a/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java +++ b/substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java @@ -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; @@ -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; @@ -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("/*"); @@ -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(); @@ -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()); @@ -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) {