Skip to content

Commit

Permalink
Free boxed types
Browse files Browse the repository at this point in the history
  • Loading branch information
jwharm committed Aug 6, 2023
1 parent 00289f4 commit 704da89
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 19 deletions.
56 changes: 43 additions & 13 deletions glib/main/java/io/github/jwharm/javagi/interop/MemoryCleaner.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import io.github.jwharm.javagi.base.Proxy;
import org.gnome.glib.GLib;
import org.gnome.glib.Type;
import org.gnome.gobject.TypeClass;
import org.gnome.gobject.TypeInstance;
import org.gnome.gobject.TypeInterface;
Expand Down Expand Up @@ -66,9 +67,11 @@ public static void register(Proxy proxy) {
Cached cached = references.get(address);
if (cached == null) {
var cleanable = CLEANER.register(proxy, new StructFinalizer(address));
references.put(address, new Cached(false, 1, null, cleanable));
references.put(address, new Cached(false, 1, null,
null, cleanable));
} else {
references.put(address, new Cached(false, cached.references + 1, cached.freeFunc, cached.cleanable));
references.put(address, new Cached(false, cached.references + 1, cached.freeFunc,
cached.boxedType, cached.cleanable));
}
}
}
Expand All @@ -83,7 +86,22 @@ public static void setFreeFunc(MemorySegment address, String freeFunc) {
synchronized (references) {
Cached cached = references.get(address);
if (cached != null)
references.put(address, new Cached(cached.owned, cached.references, freeFunc, cached.cleanable));
references.put(address, new Cached(cached.owned, cached.references, freeFunc,
cached.boxedType, cached.cleanable));
}
}

/**
* For a boxed type, {@code g_boxed_free(type, pointer)} will be used as cleanup function.
* @param address the memory address
* @param boxedType the boxed type
*/
public static void setBoxedType(MemorySegment address, Type boxedType) {
synchronized (references) {
Cached cached = references.get(address);
if (cached != null)
references.put(address, new Cached(cached.owned, cached.references, cached.freeFunc,
boxedType, cached.cleanable));
}
}

Expand All @@ -96,7 +114,8 @@ public static void takeOwnership(MemorySegment address) {
synchronized (references) {
Cached cached = references.get(address);
if (cached != null)
references.put(address, new Cached(true, cached.references, cached.freeFunc, cached.cleanable));
references.put(address, new Cached(true, cached.references, cached.freeFunc,
cached.boxedType, cached.cleanable));
}
}

Expand All @@ -109,7 +128,8 @@ public static void yieldOwnership(MemorySegment address) {
synchronized (references) {
Cached cached = references.get(address);
if (cached != null)
references.put(address, new Cached(false, cached.references, cached.freeFunc, cached.cleanable));
references.put(address, new Cached(false, cached.references, cached.freeFunc,
cached.boxedType, cached.cleanable));
}
}

Expand All @@ -131,7 +151,7 @@ public static void free(MemorySegment address) {
* @param references the numnber of references (active Proxy objects) for this address
* @param freeFunc an (optional) specialized function that will release the native memory
*/
private record Cached(boolean owned, int references, String freeFunc, Cleaner.Cleanable cleanable) {}
private record Cached(boolean owned, int references, String freeFunc, Type boxedType, Cleaner.Cleanable cleanable) {}

/**
* This callback is run by the {@link Cleaner} when a struct or union instance has become unreachable, to free the
Expand All @@ -150,7 +170,8 @@ public void run() {

// When other references exist, decrease the refcount
if (cached.references > 1) {
references.put(address, new Cached(cached.owned, cached.references - 1, cached.freeFunc, cached.cleanable));
references.put(address, new Cached(cached.owned, cached.references - 1,
cached.freeFunc, cached.boxedType, cached.cleanable));
return;
}

Expand All @@ -169,13 +190,22 @@ public void run() {
return;
}

// Run specialized free function
try {
Interop.downcallHandle(
cached.freeFunc,
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS),
false
).invokeExact(address);
if (cached.boxedType != null) {
// free boxed type
Interop.downcallHandle(
"g_boxed_free",
FunctionDescriptor.ofVoid(ValueLayout.JAVA_LONG, ValueLayout.ADDRESS),
false
).invokeExact(cached.boxedType.getValue(), address);
} else {
// Run specialized free function
Interop.downcallHandle(
cached.freeFunc,
FunctionDescriptor.ofVoid(ValueLayout.ADDRESS),
false
).invokeExact(address);
}
} catch (Throwable e) {
throw new AssertionError("Unexpected exception occured: ", e);
}
Expand Down
18 changes: 15 additions & 3 deletions src/bld/java/io/github/jwharm/javagi/model/RegisteredType.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public abstract class RegisteredType extends GirElement {
public final String javaName;
public final String parentClass;
public final String cType;
public final String getType;
public String getType;
public final String version;
public final String qualifiedName;

Expand Down Expand Up @@ -281,12 +281,12 @@ protected void generateMemoryAddressConstructor(SourceWriter writer) throws IOEx
writer.write("public " + javaName + "(MemorySegment address) {\n");
writer.increaseIndent();
writer.write("super(address);\n");
generateSetFreeFunc(writer, "this");
generateSetFreeFunc(writer, "this", null);
writer.decreaseIndent();
writer.write("}\n");
}

public void generateSetFreeFunc(SourceWriter writer, String identifier) throws IOException {
public void generateSetFreeFunc(SourceWriter writer, String identifier, String classname) throws IOException {
if (! (this instanceof Record || this instanceof Union)) {
return;
}
Expand All @@ -303,8 +303,20 @@ public void generateSetFreeFunc(SourceWriter writer, String identifier) throws I

String cIdentifier = Conversions.literal("java.lang.String", method.cIdentifier);
writer.write("MemoryCleaner.setFreeFunc(" + identifier + ".handle(), " + cIdentifier + ");\n");
return;
}
}

if (this instanceof Record && getType != null) {
writer.write("MemoryCleaner.setFreeFunc(" + identifier + ".handle(), \"g_boxed_free\");\n");
writer.write("MemoryCleaner.setBoxedType(" + identifier + ".handle(), ");
if (classname != null) {
writer.write(classname + ".getType()");
} else {
writer.write("getType()");
}
writer.write(");\n");
}
}

protected void generateParentAccessor(SourceWriter writer) throws IOException {
Expand Down
3 changes: 2 additions & 1 deletion src/bld/java/io/github/jwharm/javagi/model/ReturnValue.java
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,8 @@ public void generateReturnStatement(SourceWriter writer) throws IOException {

RegisteredType rt = type.girElementInstance;
if (rt != null) {
rt.generateSetFreeFunc(writer, "_instance");
String classname = type.qualifiedJavaType;
rt.generateSetFreeFunc(writer, "_instance", classname);
}

writer.decreaseIndent();
Expand Down
12 changes: 10 additions & 2 deletions src/bld/java/io/github/jwharm/javagi/patches/CairoPatch.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,20 @@

import io.github.jwharm.javagi.generator.Patch;
import io.github.jwharm.javagi.model.Repository;
import io.github.jwharm.javagi.model.Record;

public class CairoPatch implements Patch {

@Override
public void patch(Repository repo) {
// Incompletely defined
removeFunction(repo, "image_surface_create");

// Remove the glib:get-type attributes from the cairo types.
// The cairo bindings don't have the get-type methods.
for (var entry : repo.namespace.registeredTypeMap.entrySet()) {
var registeredType = entry.getValue();
if (registeredType instanceof Record rec) {
rec.getType = null;
}
}
}
}

0 comments on commit 704da89

Please sign in to comment.