Skip to content

Commit c0ab369

Browse files
Fix signature and return type in generated header files.
1 parent 00db562 commit c0ab369

File tree

2 files changed

+82
-92
lines changed

2 files changed

+82
-92
lines changed

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/c/codegen/CSourceCodeWriter.java

Lines changed: 56 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,12 @@
2525
package com.oracle.svm.hosted.c.codegen;
2626

2727
import static com.oracle.svm.core.util.VMError.shouldNotReachHere;
28-
import static com.oracle.svm.core.util.VMError.shouldNotReachHereUnexpectedInput;
2928
import static com.oracle.svm.hosted.NativeImageOptions.CStandards.C11;
3029
import static com.oracle.svm.hosted.NativeImageOptions.CStandards.C99;
3130

3231
import java.io.BufferedWriter;
3332
import java.io.IOException;
33+
import java.lang.reflect.AnnotatedType;
3434
import java.nio.channels.ClosedByInterruptException;
3535
import java.nio.charset.StandardCharsets;
3636
import java.nio.file.Files;
@@ -40,12 +40,10 @@
4040
import java.util.Arrays;
4141
import java.util.Collections;
4242
import java.util.List;
43-
import java.util.Optional;
4443

4544
import org.graalvm.nativeimage.c.function.CFunctionPointer;
4645
import org.graalvm.nativeimage.c.function.InvokeCFunctionPointer;
47-
import org.graalvm.word.SignedWord;
48-
import org.graalvm.word.UnsignedWord;
46+
import org.graalvm.nativeimage.c.type.CTypedef;
4947

5048
import com.oracle.svm.core.util.InterruptImageBuilding;
5149
import com.oracle.svm.core.util.UserError;
@@ -108,11 +106,11 @@ public void includeFiles(List<String> headerFiles) {
108106
if (headerFile.startsWith("<") && headerFile.endsWith(">")) {
109107
headerFileName = headerFile.substring(1, headerFile.length() - 1);
110108
Path headerFilePath = Paths.get(headerFileName);
111-
appendln("#include " + "<" + headerFilePath.toString() + ">");
109+
appendln("#include " + "<" + headerFilePath + ">");
112110
} else if (headerFile.startsWith("\"") && headerFile.endsWith("\"")) {
113111
headerFileName = headerFile.substring(1, headerFile.length() - 1);
114112
Path headerFilePath = Paths.get(headerFileName);
115-
appendln("#include " + "\"" + headerFilePath.toString() + "\"");
113+
appendln("#include " + "\"" + headerFilePath + "\"");
116114
} else {
117115
throw UserError.abort("Header file name must be surrounded by <...> or \"...\": %s", headerFile);
118116
}
@@ -130,7 +128,7 @@ public CSourceCodeWriter printf(String firstArg, String secondArg, String thirdA
130128
}
131129

132130
public CSourceCodeWriter indents() {
133-
assert currentLine.length() == 0 : "indenting in the middle of a line";
131+
assert currentLine.isEmpty() : "indenting in the middle of a line";
134132
for (int i = 0; i < indentLevel; i++) {
135133
append(INDENT4);
136134
}
@@ -167,7 +165,7 @@ public CSourceCodeWriter append(String str) {
167165
}
168166

169167
public Path writeFile(String fileName) {
170-
assert currentLine.length() == 0 : "last line not finished";
168+
assert currentLine.isEmpty() : "last line not finished";
171169

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

187-
public static String toCTypeName(ResolvedJavaMethod method, ResolvedJavaType type, Optional<String> useSiteTypedef, boolean isConst, boolean isUnsigned, MetaAccessProvider metaAccess,
188-
NativeLibraries nativeLibs) {
189-
boolean isNumericInteger = type.getJavaKind().isNumericInteger();
190-
UserError.guarantee(isNumericInteger || !isUnsigned,
191-
"Only integer types can be unsigned. %s is not an integer type in %s", type, method);
192-
193-
boolean isUnsignedWord = metaAccess.lookupJavaType(UnsignedWord.class).isAssignableFrom(type);
194-
boolean isSignedWord = metaAccess.lookupJavaType(SignedWord.class).isAssignableFrom(type);
195-
boolean isWord = isUnsignedWord || isSignedWord;
196-
boolean isObject = type.getJavaKind() == JavaKind.Object && !isWord;
197-
UserError.guarantee(isObject || !isConst,
198-
"Only pointer types can be const. %s in method %s is not a pointer type.", type, method);
199-
200-
if (useSiteTypedef.isPresent()) {
201-
return (isConst ? "const " : "") + useSiteTypedef.get();
202-
} else if (isNumericInteger) {
203-
return toCIntegerType(type, isUnsigned);
204-
} else if (isUnsignedWord) {
205-
return "size_t";
206-
} else if (isSignedWord) {
207-
return "ssize_t";
208-
} else if (isObject) {
185+
public static String toCTypeName(ResolvedJavaMethod method, ResolvedJavaType type, AnnotatedType annotatedType, boolean isConst, MetaAccessProvider metaAccess, NativeLibraries nativeLibs) {
186+
CTypedef typeDef = annotatedType.getAnnotation(CTypedef.class);
187+
if (typeDef != null) {
188+
return (isConst ? "const " : "") + typeDef.name();
189+
}
190+
191+
JavaKind kind = type.getJavaKind();
192+
if (kind.isObject() && !nativeLibs.isIntegerType(type)) {
209193
return (isConst ? "const " : "") + cTypeForObject(type, metaAccess, nativeLibs);
210-
} else {
211-
switch (type.getJavaKind()) {
212-
case Double:
213-
return "double";
214-
case Float:
215-
return "float";
216-
case Void:
217-
return "void";
218-
default:
219-
throw shouldNotReachHereUnexpectedInput(type.getJavaKind()); // ExcludeFromJacocoGeneratedReport
220-
}
221194
}
195+
196+
UserError.guarantee(!isConst, "Only pointer types can be const. %s in method %s is not a pointer type.", type, method);
197+
return cTypeForPrimitive(method, type, annotatedType, nativeLibs);
222198
}
223199

224200
private static String cTypeForObject(ResolvedJavaType type, MetaAccessProvider metaAccess, NativeLibraries nativeLibs) {
225201
ElementInfo elementInfo = nativeLibs.findElementInfo(type);
226-
if (elementInfo instanceof PointerToInfo) {
227-
PointerToInfo pointerToInfo = (PointerToInfo) elementInfo;
202+
if (elementInfo instanceof PointerToInfo pointerToInfo) {
228203
return (pointerToInfo.getTypedefName() != null ? pointerToInfo.getTypedefName() : pointerToInfo.getName() + "*");
229-
} else if (elementInfo instanceof StructInfo) {
230-
StructInfo structInfo = (StructInfo) elementInfo;
204+
} else if (elementInfo instanceof StructInfo structInfo) {
231205
return structInfo.getTypedefName() != null ? structInfo.getTypedefName() : structInfo.getName() + "*";
232206
} else if (elementInfo instanceof EnumInfo) {
233207
return elementInfo.getName();
234-
} else if (isFunctionPointer(metaAccess, type)) {
235-
return InfoTreeBuilder.getTypedefName(type) != null ? InfoTreeBuilder.getTypedefName(type) : "void *";
208+
} else if (isFunctionPointer(metaAccess, type) && InfoTreeBuilder.getTypedefName(type) != null) {
209+
return InfoTreeBuilder.getTypedefName(type);
210+
} else {
211+
return "void *";
236212
}
237-
return "void *";
238213
}
239214

240-
private static String toCIntegerType(ResolvedJavaType type, boolean isUnsigned) {
215+
private static String cTypeForPrimitive(ResolvedJavaMethod method, ResolvedJavaType type, AnnotatedType annotatedType, NativeLibraries nativeLibs) {
241216
boolean c11Compatible = NativeImageOptions.getCStandard().compatibleWith(C11);
242217
String prefix = "";
243-
if (isUnsigned) {
218+
if (isUnsigned(annotatedType)) {
244219
prefix = c11Compatible ? "u" : "unsigned ";
245220
}
246-
switch (type.getJavaKind()) {
247-
case Boolean:
248-
if (NativeImageOptions.getCStandard().compatibleWith(CStandards.C99)) {
249-
return "bool";
250-
} else {
251-
return "int";
252-
}
221+
222+
JavaKind javaKind = type.getJavaKind();
223+
switch (javaKind) {
253224
case Byte:
254225
return prefix + (c11Compatible ? "int8_t" : "char");
255-
case Char:
256226
case Short:
227+
case Char:
257228
return prefix + (c11Compatible ? "int16_t" : "short");
258229
case Int:
259230
return prefix + (c11Compatible ? "int32_t" : "int");
260231
case Long:
261232
return prefix + (c11Compatible ? "int64_t" : "long long int");
262233
}
263-
throw VMError.shouldNotReachHere("All types integer types should be covered. Got " + type.getJavaKind());
234+
235+
UserError.guarantee(prefix.isEmpty(), "Only integer types can be annotated with @%s. %s in method %s is not an integer type.",
236+
org.graalvm.nativeimage.c.type.CUnsigned.class.getSimpleName(), type, method);
237+
switch (javaKind) {
238+
case Boolean:
239+
if (NativeImageOptions.getCStandard().compatibleWith(CStandards.C99)) {
240+
return "bool";
241+
} else {
242+
return "int";
243+
}
244+
case Float:
245+
return "float";
246+
case Double:
247+
return "double";
248+
case Void:
249+
return "void";
250+
case Object:
251+
/* SignedWord or UnsignedWord. */
252+
assert nativeLibs.isIntegerType(type);
253+
return nativeLibs.isSigned(type) ? "ssize_t" : "size_t";
254+
default:
255+
throw VMError.shouldNotReachHere("Unexpected Java kind " + javaKind);
256+
}
257+
}
258+
259+
private static boolean isUnsigned(AnnotatedType type) {
260+
return type.isAnnotationPresent(org.graalvm.nativeimage.c.type.CUnsigned.class) || type.isAnnotationPresent(com.oracle.svm.core.c.CUnsigned.class);
264261
}
265262

266263
private static boolean isFunctionPointer(MetaAccessProvider metaAccess, ResolvedJavaType type) {

substratevm/src/com.oracle.svm.hosted/src/com/oracle/svm/hosted/image/NativeImage.java

Lines changed: 26 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import java.util.List;
4848
import java.util.Locale;
4949
import java.util.Map;
50-
import java.util.Optional;
5150
import java.util.Set;
5251
import java.util.stream.Collectors;
5352

@@ -58,8 +57,6 @@
5857
import org.graalvm.nativeimage.c.function.CEntryPoint.Publish;
5958
import org.graalvm.nativeimage.c.function.CFunctionPointer;
6059
import org.graalvm.nativeimage.c.type.CConst;
61-
import org.graalvm.nativeimage.c.type.CTypedef;
62-
import org.graalvm.nativeimage.c.type.CUnsigned;
6360

6461
import com.oracle.graal.pointsto.meta.AnalysisMethod;
6562
import com.oracle.graal.pointsto.meta.AnalysisType;
@@ -325,14 +322,16 @@ private static int sortMethodsByFileNameAndPosition(HostedMethod stub1, HostedMe
325322
return rm1Line - rm2Line;
326323
}
327324

328-
private static boolean isUnsigned(AnnotatedType type) {
329-
var legacyCUnsigned = com.oracle.svm.core.c.CUnsigned.class;
330-
return type.isAnnotationPresent(CUnsigned.class) || type.isAnnotationPresent(legacyCUnsigned);
331-
}
325+
private void writeMethodHeader(HostedMethod stubMethod, CSourceCodeWriter writer, boolean dynamic) {
326+
assert Modifier.isStatic(stubMethod.getModifiers()) : "Published methods that go into the header must be static.";
327+
328+
/*
329+
* Get the target method that will be invoked by the stub. We need its signature because the
330+
* stub signature has different types (primitive instead of object types) and no metadata.
331+
*/
332+
HostedMethod targetMethod = metaAccess.lookupJavaMethod(getMethod(stubMethod));
332333

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

347-
AnnotatedType annotatedReturnType = getAnnotatedReturnType(m);
348-
writer.append(CSourceCodeWriter.toCTypeName(m,
349-
m.getSignature().getReturnType(),
350-
Optional.ofNullable(annotatedReturnType.getAnnotation(CTypedef.class)).map(CTypedef::name),
351-
false,
352-
isUnsigned(annotatedReturnType),
353-
metaAccess, nativeLibs));
346+
var signature = targetMethod.getSignature();
347+
writer.append(CSourceCodeWriter.toCTypeName(targetMethod, signature.getReturnType(), getAnnotatedReturnType(stubMethod), false, metaAccess, nativeLibs));
354348
writer.append(" ");
355349

356350
String symbolName = cEntryPointData.getSymbolName();
@@ -362,19 +356,20 @@ private void writeMethodHeader(HostedMethod m, CSourceCodeWriter writer, boolean
362356
}
363357
writer.append("(");
364358

365-
String sep = "";
366-
AnnotatedType[] annotatedParameterTypes = getAnnotatedParameterTypes(m);
367-
Parameter[] parameters = m.getParameters();
368-
assert parameters != null;
369-
for (int i = 0; i < m.getSignature().getParameterCount(false); i++) {
370-
writer.append(sep);
371-
sep = ", ";
372-
writer.append(CSourceCodeWriter.toCTypeName(m,
373-
m.getSignature().getParameterType(i),
374-
Optional.ofNullable(annotatedParameterTypes[i].getAnnotation(CTypedef.class)).map(CTypedef::name),
375-
annotatedParameterTypes[i].isAnnotationPresent(CConst.class),
376-
isUnsigned(annotatedParameterTypes[i]),
377-
metaAccess, nativeLibs));
359+
/* Write the signature. */
360+
int numParams = signature.getParameterCount(false);
361+
AnnotatedType[] annotatedTypes = getAnnotatedParameterTypes(stubMethod);
362+
Parameter[] parameters = targetMethod.getParameters();
363+
assert annotatedTypes.length == numParams;
364+
assert parameters.length == numParams;
365+
366+
for (int i = 0; i < numParams; i++) {
367+
if (i > 0) {
368+
writer.append(", ");
369+
}
370+
371+
boolean isConst = annotatedTypes[i].isAnnotationPresent(CConst.class);
372+
writer.append(CSourceCodeWriter.toCTypeName(targetMethod, signature.getParameterType(i), annotatedTypes[i], isConst, metaAccess, nativeLibs));
378373
if (parameters[i].isNamePresent()) {
379374
writer.append(" ");
380375
writer.append(parameters[i].getName());
@@ -396,14 +391,12 @@ private AnnotatedType[] getAnnotatedParameterTypes(HostedMethod hostedMethod) {
396391

397392
private Method getMethod(HostedMethod hostedMethod) {
398393
AnalysisMethod entryPoint = CEntryPointCallStubSupport.singleton().getMethodForStub(((CEntryPointCallStubMethod) hostedMethod.wrapped.wrapped));
399-
Method method;
400394
try {
401-
method = entryPoint.getDeclaringClass().getJavaClass().getDeclaredMethod(entryPoint.getName(),
395+
return entryPoint.getDeclaringClass().getJavaClass().getDeclaredMethod(entryPoint.getName(),
402396
MethodType.fromMethodDescriptorString(entryPoint.getSignature().toMethodDescriptor(), imageClassLoader).parameterArray());
403397
} catch (NoSuchMethodException e) {
404398
throw shouldNotReachHere(e);
405399
}
406-
return method;
407400
}
408401

409402
private boolean shouldWriteHeader(HostedMethod method) {

0 commit comments

Comments
 (0)