Skip to content

Commit

Permalink
Merge pull request #75 from jwharm/jdk21
Browse files Browse the repository at this point in the history
Port to JDK 21
  • Loading branch information
jwharm authored Oct 25, 2023
2 parents cb95fed + 61e8fa9 commit 9d38044
Show file tree
Hide file tree
Showing 34 changed files with 650 additions and 505 deletions.
6 changes: 3 additions & 3 deletions buildSrc/src/main/groovy/java-gi.library-conventions.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ dependencies {
}

group = 'io.github.jwharm.javagi'
version = '0.7.2'
version = '0.8.0-SNAPSHOT'

java {
if (! System.getenv('CI')) {
withJavadocJar()
}
withSourcesJar()
toolchain {
languageVersion = JavaLanguageVersion.of(20)
languageVersion = JavaLanguageVersion.of(21)
}
}

Expand All @@ -64,7 +64,7 @@ tasks.named('javadoc') {
if (System.getenv('CI')) {
enabled = false
}
options.addStringOption('source', '20')
options.addStringOption('source', '21')
options.addBooleanOption('-enable-preview', true)
options.addStringOption('Xdoclint:none', '-quiet')
options.encoding = 'UTF-8'
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,12 +125,13 @@ protected void generateArrayConstructor(SourceWriter writer) throws IOException

writer.write(" " + javaName + "[] array = new " + javaName + "[(int) length];\n");
writer.write(" long bytesSize = " + layout + ".byteSize();\n");
writer.write(" MemorySegment segment = address.reinterpret(bytesSize * length);\n");
writer.write(" for (int i = 0; i < length; i++) {\n");

if ("utf8".equals(type.name)) {
writer.write(" array[i] = new " + javaName + "(Interop.getStringFrom(address.get(" + layout + ", i * bytesSize), free));\n");
writer.write(" array[i] = new " + javaName + "(Interop.getStringFrom(segment.get(" + layout + ", i * bytesSize), free));\n");
} else {
writer.write(" array[i] = new " + javaName + "(address.get(" + layout + ", i * bytesSize));\n");
writer.write(" array[i] = new " + javaName + "(segment.get(" + layout + ", i * bytesSize));\n");
}

writer.write(" }\n");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ public void generate(SourceWriter writer) throws IOException {
writer.write("public class " + javaName + " extends io.github.jwharm.javagi.base.Bitfield {\n");
writer.increaseIndent();

generateMemoryLayout(writer);
generateGType(writer);

// Filter duplicate members
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,21 +43,16 @@ public interface CallableType {
* an out parameter, or a pointer to a primitive value)
*/
default boolean allocatesMemory() {
if (getThrows() != null) {
return true;
}
if (getReturnValue().allocatesMemory()) {
return true;
}
if (getParameters() != null) {
if (getParameters().parameterList.stream().anyMatch(
p -> (p.array != null)
|| (p.type != null && p.type.isActuallyAnArray())
|| (p.type != null && "java.lang.String".equals(p.type.qualifiedJavaType))
|| (p.isOutParameter())
|| (p.isAliasForPrimitive() && p.type.isPointer())
)) {
return true;
}
return getParameters().parameterList.stream().anyMatch(Parameter::allocatesMemory);
}
ReturnValue rv = getReturnValue();
return getThrows() != null
|| rv.array != null
|| (this instanceof Closure && rv.type != null && "java.lang.String".equals(rv.type.qualifiedJavaType));
return false;
}

default boolean generateFunctionDescriptor(SourceWriter writer) throws IOException {
Expand All @@ -75,12 +70,6 @@ default boolean generateFunctionDescriptor(SourceWriter writer) throws IOExcepti
} else {
writer.write("of(");
writer.write(Conversions.getValueLayout(returnValue.type));

// Unbounded valuelayout for Strings, otherwise we cannot read an utf8 string from the returned pointer
if (returnValue.type != null && "java.lang.String".equals(returnValue.type.qualifiedJavaType)) {
writer.write(".asUnbounded()");
}

if (parameters != null || this instanceof Signal) {
writer.write(", ");
}
Expand All @@ -106,14 +95,6 @@ default boolean generateFunctionDescriptor(SourceWriter writer) throws IOExcepti
}
first = false;
writer.write(Conversions.getValueLayout(p.type));

// Unbounded valuelayout for String callback/out parameters,
// otherwise we cannot read the utf8 string to create a Java String
if ((this instanceof Closure || p.isOutParameter())
&& p.type != null
&& "java.lang.String".equals(p.type.qualifiedJavaType)) {
writer.write(".asUnbounded()");
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -92,11 +92,11 @@ public void generate(SourceWriter writer) throws IOException {
writer.write(interfaces + " {\n");
writer.increaseIndent();

generateMemoryAddressConstructor(writer);
generateEnsureInitialized(writer);
generateGType(writer);
generateMemoryLayout(writer);
generateParentAccessor(writer);
generateMemoryAddressConstructor(writer);
generateConstructors(writer);
generateMethodsAndSignals(writer);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@

public interface Closure extends CallableType {

@Override
default boolean allocatesMemory() {
ReturnValue rv = getReturnValue();
return CallableType.super.allocatesMemory()
|| rv.type != null && "java.lang.String".equals(rv.type.qualifiedJavaType);
}

default void generateFunctionalInterface(SourceWriter writer, String javaName) throws IOException {
ReturnValue returnValue = getReturnValue();
Parameters parameters = getParameters();
Expand Down Expand Up @@ -97,7 +104,7 @@ default void generateFunctionalInterface(SourceWriter writer, String javaName) t
writer.write("MethodHandle _handle = Interop.upcallHandle(MethodHandles.lookup(), " + javaName + ".class, _fdesc);\n");

// Create and return upcall stub
writer.write("return Linker.nativeLinker().upcallStub(_handle.bindTo(this), _fdesc, SegmentScope.global());\n");
writer.write("return Linker.nativeLinker().upcallStub(_handle.bindTo(this), _fdesc, Arena.global());\n");

writer.decreaseIndent();
writer.write("}\n");
Expand Down Expand Up @@ -150,7 +157,7 @@ default void generateUpcallMethod(SourceWriter writer, String methodName, String
// Is memory allocated?
boolean hasScope = allocatesMemory();
if (hasScope) {
writer.write("try (Arena _arena = Arena.openConfined()) {\n");
writer.write("try (Arena _arena = Arena.ofConfined()) {\n");
writer.increaseIndent();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public void generate(SourceWriter writer) throws IOException {
}

// @Deprecated
if ("1".equals(deprecated) || hasVaListParameter()) {
if ("1".equals(deprecated)) {
writer.write("@Deprecated\n");
}

Expand Down Expand Up @@ -102,7 +102,7 @@ public void generateNamed(SourceWriter writer) throws IOException {
}

// @Deprecated
if ("1".equals(deprecated) || hasVaListParameter()) {
if ("1".equals(deprecated)) {
writer.write("@Deprecated\n");
}

Expand Down
5 changes: 0 additions & 5 deletions buildSrc/src/main/java/io/github/jwharm/javagi/model/Doc.java
Original file line number Diff line number Diff line change
Expand Up @@ -126,11 +126,6 @@ public void generate(SourceWriter writer, boolean signalDeclaration, boolean ful
}
}

// VaList parameter = deprecated
if (parent instanceof Method m && m.hasVaListParameter()) {
writeDoc(writer, "Support for va_list will be dropped in the next release of Java-GI", "@deprecated");
}

// Property setters
if (parent instanceof Property p) {
writeDoc(writer, p.name + " the value for the {@code " + p.propertyName + "} property", "@param");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,6 @@ public void generate(SourceWriter writer) throws IOException {
}

generateGType(writer);
generateMemoryLayout(writer);

writer.write("\n");
writer.write("private final int value;\n");
Expand Down
43 changes: 25 additions & 18 deletions buildSrc/src/main/java/io/github/jwharm/javagi/model/Field.java
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,11 @@ public void generate(SourceWriter writer) throws IOException {
}
writer.write(") {\n");

// Allocator for array field getters
if (allocatesMemory()) {
writer.write(" Arena _arena = Arena.ofAuto();\n");
}

// Read the memory segment of an embedded field from the struct (not a pointer)
if ((type != null) && (!type.isPointer()) && (type.isClass() || type.isInterface())) {
writer.write(" long _offset = getMemoryLayout().byteOffset(MemoryLayout.PathElement.groupElement(\"" + this.fieldName + "\"));\n");
Expand All @@ -141,10 +146,9 @@ public void generate(SourceWriter writer) throws IOException {
} else {
String memoryType = getMemoryType();
if ("ARRAY".equals(memoryType)) memoryType = "MemorySegment";
writer.write(" var _scope = getAllocatedMemorySegment().scope();\n");
writer.write(" var _result = (" + memoryType + ") getMemoryLayout()\n");
writer.write(" .varHandle(MemoryLayout.PathElement.groupElement(\"" + this.fieldName + "\"))\n");
writer.write(" .get(getAllocatedMemorySegment());\n");
writer.write(" .get(handle());\n");
writer.write(" return ");
marshalNativeToJava(writer, "_result", false);
writer.write(";\n");
Expand All @@ -159,12 +163,15 @@ public void generate(SourceWriter writer) throws IOException {
writer.write(" * @param " + this.name + " The new value for the field {@code " + this.fieldName + "}\n");
writer.write(" */\n");
writer.write("public void " + setter + "(");
// Arena parameter
if (allocatesMemory()) {
writer.write("Arena _arena, ");
}
writeTypeAndName(writer);
writer.write(") {\n");
writer.write(" var _arena = SegmentAllocator.nativeAllocator(getAllocatedMemorySegment().scope());\n");
writer.write(" getMemoryLayout()\n");
writer.write(" .varHandle(MemoryLayout.PathElement.groupElement(\"" + this.fieldName + "\"))\n");
writer.write(" .set(getAllocatedMemorySegment(), ");
writer.write(" .set(handle(), ");
// Check for null values
if (checkNull()) {
writer.write("(" + this.name + " == null ? MemorySegment.NULL : ");
Expand Down Expand Up @@ -198,10 +205,10 @@ public void generate(SourceWriter writer) throws IOException {
// Generate method handle
String className = ((Record) parent).javaName;
writer.write("MethodHandle _handle = Interop.upcallHandle(MethodHandles.lookup(), " + className + ".class, \"" + upcallName + "\", _fdesc);\n");
writer.write("MemorySegment _address = Linker.nativeLinker().upcallStub(_handle.bindTo(this), _fdesc, SegmentScope.global());\n");
writer.write("MemorySegment _address = Linker.nativeLinker().upcallStub(_handle.bindTo(this), _fdesc, Arena.global());\n");
writer.write("getMemoryLayout()\n");
writer.write(" .varHandle(MemoryLayout.PathElement.groupElement(\"" + this.fieldName + "\"))\n");
writer.write(" .set(getAllocatedMemorySegment(), ");
writer.write(" .set(handle(), ");
writer.write("(method == null ? MemorySegment.NULL : _address));\n");

writer.decreaseIndent();
Expand Down Expand Up @@ -229,7 +236,7 @@ public String getMemoryLayoutString() {
|| "java.lang.String".equals(type.qualifiedJavaType)
|| "java.lang.foreign.MemorySegment".equals(type.qualifiedJavaType)
|| type.isCallback()) {
return "ValueLayout.ADDRESS.asUnbounded().withName(\"" + this.fieldName + "\")";
return "ValueLayout.ADDRESS.withName(\"" + this.fieldName + "\")";
}

// Bitfields and enumerations are integers
Expand Down Expand Up @@ -273,7 +280,7 @@ public String getMemoryLayoutString() {

// Arrays with non-fixed size
if (array != null) {
return "ValueLayout.ADDRESS.asUnbounded().withName(\"" + this.fieldName + "\")";
return "ValueLayout.ADDRESS.withName(\"" + this.fieldName + "\")";
}

// Callbacks
Expand Down Expand Up @@ -328,17 +335,17 @@ public String getMemoryType(Type type) {
*/
public int getSize(String memoryType) {
return switch(memoryType) {
case "boolean" -> 32; // treated as an integer
case "byte" -> 8;
case "char" -> 8;
case "short" -> 16;
case "int" -> 32;
case "long" -> 64; // java long is 64-bits
case "float" -> 32;
case "double" -> 64;
case "MemorySegment" -> 64; // 64-bits pointer
case "boolean" -> 4; // treated as an integer
case "byte" -> 1;
case "char" -> 1;
case "short" -> 2;
case "int" -> 4;
case "long" -> 8; // java long is 64-bits
case "float" -> 4;
case "double" -> 8;
case "MemorySegment" -> 8; // 64-bits pointer
case "ARRAY" -> Integer.parseInt(array.fixedSize) * getSize(getMemoryType(array.type));
default -> 64;
default -> 8;
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -197,7 +197,7 @@ public void generate(SourceWriter writer) throws IOException {
// Generate try-with-resources?
boolean hasScope = allocatesMemory();
if (hasScope) {
writer.write("try (Arena _arena = Arena.openConfined()) {\n");
writer.write("try (Arena _arena = Arena.ofConfined()) {\n");
writer.increaseIndent();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ public boolean isArrayLengthParameter() {
* (instance param, gerror, user_data or array length), or primitive values.
* @return true iff this parameter is nullable, is user-specified, and is not a primitive value
*/
@Override
public boolean checkNull() {
return (! notnull)
&& (! (isInstanceParameter() || isErrorParameter()
Expand All @@ -211,6 +212,13 @@ public boolean checkNull() {
&& super.checkNull();
}

@Override
public boolean allocatesMemory() {
return super.allocatesMemory()
|| isOutParameter()
|| (isAliasForPrimitive() && type.isPointer());
}

/**
* Generate code to do pre-processing of the parameter before the function call. This will
* generate a null check for NotNull parameters, and generate pointer allocation logic for
Expand Down Expand Up @@ -308,7 +316,8 @@ public void generatePostprocessing(SourceWriter writer) throws IOException {
} else if (array.type.isPrimitive && (! array.type.isBoolean())) {
// Array of primitive values
writer.write("if (" + name + " != null) " + name + ".set(");
writer.write("MemorySegment.ofAddress(_" + name + "Pointer.get(ValueLayout.ADDRESS, 0).address(), " + len + " * " + valuelayout + ".byteSize(), _arena.scope()).toArray(" + valuelayout + "));\n");
writer.write("_" + name + "Pointer.get(ValueLayout.ADDRESS, 0).reinterpret("
+ len + " * " + valuelayout + ".byteSize(), _arena, null).toArray(" + valuelayout + "));\n");
} else {
// Array of proxy objects
writer.write("if (" + name + " != null) {\n");
Expand Down Expand Up @@ -350,14 +359,14 @@ public void generatePostprocessing(SourceWriter writer) throws IOException {

public void generateUpcallPreprocessing(SourceWriter writer) throws IOException {
if (isAliasForPrimitive() && type.isPointer()) {
writer.write("MemorySegment %sParam = MemorySegment.ofAddress(%s.address(), %s.byteSize(), %s.scope());\n"
.formatted(name, name, Conversions.getValueLayoutPlain(type), name));
writer.write("MemorySegment %sParam = %s.reinterpret(%s.byteSize(), _arena, null);\n"
.formatted(name, name, Conversions.getValueLayoutPlain(type)));
String typeStr = Conversions.getValueLayoutPlain(type.girElementInstance.type);
writer.write(type.qualifiedJavaType + " _" + name + "Alias = new " + type.qualifiedJavaType + "(" + name + "Param.get(" + typeStr + ", 0));\n");
} else if (isOutParameter()) {
if (type != null) {
writer.write("MemorySegment %sParam = MemorySegment.ofAddress(%s.address(), %s.byteSize(), %s.scope());\n"
.formatted(name, name, Conversions.getValueLayoutPlain(type), name));
writer.write("MemorySegment %sParam = %s.reinterpret(%s.byteSize(), _arena, null);\n"
.formatted(name, name, Conversions.getValueLayoutPlain(type)));
String typeStr = type.qualifiedJavaType;
if (type.isPrimitive) typeStr = Conversions.primitiveClassName(typeStr);
writer.write("Out<" + typeStr + "> _" + name + "Out = new Out<>(");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@ public void generate(SourceWriter writer) throws IOException {
writeTypeAndName(writer);
writer.write(") {\n");
writer.increaseIndent();
writer.write("org.gnome.gobject.Value _value = org.gnome.gobject.Value.allocate();\n");
writer.write("_value.init(" + gTypeDeclaration + ");\n");
if (array != null) {
writer.write("SegmentAllocator _arena = SegmentAllocator.nativeAllocator(SegmentScope.auto());\n");
if (allocatesMemory()) {
writer.write("Arena _arena = getArena();\n");
writer.write("org.gnome.gobject.Value _value = org.gnome.gobject.Value.allocate(_arena);\n");
} else {
writer.write("org.gnome.gobject.Value _value = org.gnome.gobject.Value.allocate(getArena());\n");
}
writer.write("_value.init(" + gTypeDeclaration + ");\n");
writer.write(getValueSetter("_value", gTypeDeclaration, name) + ";\n");
writer.write("addBuilderProperty(\"" + propertyName + "\", _value);\n");
writer.write("return (S) this;\n");
Expand Down
Loading

0 comments on commit 9d38044

Please sign in to comment.