Skip to content

Commit

Permalink
Calculate size of bitfields when generating MemoryLayout, and hide bi…
Browse files Browse the repository at this point in the history
…tfield getter/setter methods
  • Loading branch information
jwharm committed Jul 20, 2024
1 parent 701e0cf commit 54828b9
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,12 +109,30 @@ private PartialStatement generateFieldLayouts(List<Field> fieldList,
"valueLayout", ValueLayout.class
);
int size = 0;
for (Field field : fieldList) {
if (size > 0) stmt.add(",\n");

// Get the byte size of the field, in bytes
int bitfieldPosition = 0;
for (int i = 0; i < fieldList.size(); i++) {
Field field = fieldList.get(i);
// Get the size of the field, in bytes
int s = field.getSize(longAsInt);

// Bitfield?
int bits = field.bits();
if (bits > 0) {
bitfieldPosition += bits;
boolean last = (i + 1 == fieldList.size()
|| fieldList.get(i + 1).bits() == -1);

if (last || bitfieldPosition > (s * 8)) {
if (size > 0) stmt.add(",\n");
size += s;
stmt.add("$memoryLayout:T.paddingLayout(" + s + ") /* bitfield */");
bitfieldPosition = last ? 0 : bits;
}
continue;
}

if (size > 0) stmt.add(",\n");

// Calculate padding (except for union layouts)
if (!isUnion) {
// If the previous field had a smaller byte-size than this one,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.lang.foreign.Arena;
import java.lang.foreign.MemorySegment;
import java.util.stream.Stream;

import com.squareup.javapoet.*;
import io.github.jwharm.javagi.configuration.ClassNames;
Expand Down Expand Up @@ -149,6 +150,7 @@ public TypeSpec generate() {

private void generateField(Field f) {
if (f.isDisguised()) return;
if (f.bits() != -1) return;
FieldGenerator generator = new FieldGenerator(f);
Callback cb = f.callback();

Expand Down Expand Up @@ -217,6 +219,12 @@ private MethodSpec constructor(boolean arenaParameter) {
return spec.build();
}

private Stream<Field> streamAccessibleFields() {
return rec.fields().stream()
.filter(not(Field::isDisguised))
.filter(f -> f.bits() == -1);
}

private MethodSpec constructorWithParameters(boolean arenaParameter) {
var spec = MethodSpec.constructorBuilder()
.addJavadoc("Allocate a new $T with the fields set to the provided values.\n",
Expand All @@ -228,7 +236,7 @@ private MethodSpec constructorWithParameters(boolean arenaParameter) {
Arena.class);
spec.addJavadoc("\n");

rec.fields().stream().filter(not(Field::isDisguised)).forEach(f ->
streamAccessibleFields().forEach(f ->
spec.addJavadoc("@param $1L $2L for the field {@code $1L}\n",
toJavaIdentifier(f.name()),
f.callback() == null ? "value" : "callback function")
Expand All @@ -251,7 +259,7 @@ private MethodSpec constructorWithParameters(boolean arenaParameter) {
spec.addStatement("this($T.ofAuto())", Arena.class);

// Copy the parameter values into the instance fields
rec.fields().stream().filter(not(Field::isDisguised)).forEach(f -> {
streamAccessibleFields().forEach(f -> {
if (f.allocatesMemory() && arenaParameter)
spec.addStatement("$L$L($L, arena)",
f.callback() == null ? "write" : "override",
Expand Down Expand Up @@ -304,8 +312,7 @@ private boolean noNewConstructor() {
}

private boolean hasFieldSetters() {
return rec.fields().stream()
.anyMatch(not(f -> f.isDisguised() || f.callback() != null));
return streamAccessibleFields().anyMatch(f -> f.callback() == null);
}

private MethodSpec allocateWithParameters() {
Expand All @@ -317,16 +324,15 @@ private MethodSpec allocateWithParameters() {
""", rec.typeName());

// Javadoc for parameters and return value
rec.fields().stream().filter(not(Field::isDisguised)).forEach(f ->
streamAccessibleFields().forEach(f ->
spec.addJavadoc("@param $1L $2L for the field {@code $1L}\n",
toJavaIdentifier(f.name()),
f.callback() == null ? "value" : "callback function")
);
spec.addJavadoc("@return a new {@link $T} with the fields set to the provided values\n",
rec.typeName());

String paramTypes = rec.fields().stream()
.filter(not(Field::isDisguised))
String paramTypes = streamAccessibleFields()
.map(f -> new TypedValueGenerator(f).getType().toString() + ", ")
.collect(joining());
spec.addJavadoc("@deprecated Replaced by {@link $1T#$1T($2L$3T)}\n",
Expand All @@ -337,7 +343,7 @@ private MethodSpec allocateWithParameters() {
spec.addModifiers(Modifier.PUBLIC, Modifier.STATIC)
.returns(rec.typeName())
.addParameter(Arena.class, "arena");
rec.fields().stream().filter(not(Field::isDisguised)).forEach(f ->
streamAccessibleFields().forEach(f ->
spec.addParameter(
// Override the type of long values
f.anyType() instanceof Type t && t.isLong()
Expand All @@ -346,8 +352,7 @@ private MethodSpec allocateWithParameters() {
toJavaIdentifier(f.name()))
);

String params = rec.fields().stream()
.filter(not(Field::isDisguised))
String params = streamAccessibleFields()
.map(f -> toJavaIdentifier(f.name()) + ", ")
.collect(joining());

Expand Down

0 comments on commit 54828b9

Please sign in to comment.