Created
May 7, 2020 15:47
-
-
Save mcimadamore/5f002d8177e05780f068dd7874a5020b to your computer and use it in GitHub Desktop.
A simple jextract API plugin to generate all struct layouts in a given header file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import jdk.incubator.foreign.GroupLayout; | |
import jdk.incubator.foreign.MemoryLayout; | |
import jdk.incubator.foreign.SequenceLayout; | |
import jdk.incubator.foreign.ValueLayout; | |
import jdk.incubator.jextract.Declaration; | |
import jdk.incubator.jextract.JextractTask; | |
import java.nio.file.Files; | |
import java.nio.file.Path; | |
import java.nio.file.Paths; | |
/** | |
* Simple jextract API plugin to generate all struct layouts in a given header file. For simplicity, | |
* all layouts are considered to be little endian. Use like this: | |
* <blockquote><pre>{@code | |
* $ <PANAMA_JDK>/bin/java --add-modules jdk.incubator.jextract src/JStruct.java <header-file> | |
* }</pre></blockquote> | |
*/ | |
public class JStruct { | |
public static void main(String[] args) { | |
if (args.length == 0) { | |
System.err.println("Expected header file"); | |
System.exit(2); | |
} | |
Path header = Paths.get(args[0]); | |
if (!Files.isReadable(header)) { | |
System.err.println("Cannot read header file: " + args[0]); | |
System.exit(2); | |
} | |
var task = JextractTask.newTask(false, header); | |
Path builtinInc = Paths.get(System.getProperty("java.home"), "conf", "jextract"); | |
var decl = task.parse("-I" + builtinInc); | |
decl.accept(new StructPrinter(), null); | |
} | |
static class StructPrinter implements Declaration.Visitor<Void, Void> { | |
static String ALIGN_STR = " "; | |
int align = 0; | |
void indent() { | |
print(ALIGN_STR.substring(0, align)); | |
} | |
void incrAlign() { | |
align += 4; | |
} | |
void decrAlign() { | |
align -= 4; | |
} | |
void print(String s) { | |
System.out.print(s); | |
} | |
@Override | |
public Void visitScoped(Declaration.Scoped d, Void aVoid) { | |
if (d.layout().isPresent()) { | |
printLayout(d.name(), d.layout().get()); | |
} else { | |
d.members().stream() | |
.filter(m -> m instanceof Declaration.Scoped) | |
.forEach(m -> m.accept(this, null)); | |
} | |
return null; | |
} | |
protected void printLayout(String elementName, MemoryLayout layout) { | |
print("MemoryLayout " + elementName + "$LAYOUT = "); | |
printLayout(layout); | |
print(";\n\n"); | |
} | |
private void printLayout(MemoryLayout l) { | |
if (l instanceof ValueLayout) { | |
String valueLayout = switch ((int)l.byteSize()) { | |
case 1 -> "MemoryLayouts.BITS_8_LE"; | |
case 2 -> "MemoryLayouts.BITS_16_LE"; | |
case 4 -> "MemoryLayouts.BITS_32_LE"; | |
case 8 -> "MemoryLayouts.BITS_64_LE"; | |
default -> "MemoryLayout.ofValueBits(" + l.bitSize() + ", ByteOrder.LITTLE_ENDIAN)"; | |
}; | |
print(valueLayout); | |
} else if (l instanceof SequenceLayout) { | |
print("MemoryLayout.ofSequence("); | |
if (((SequenceLayout) l).elementCount().isPresent()) { | |
print(((SequenceLayout) l).elementCount().getAsLong() + ", "); | |
} | |
printLayout(((SequenceLayout) l).elementLayout()); | |
print(")"); | |
} else if (l instanceof GroupLayout) { | |
if (((GroupLayout) l).isStruct()) { | |
print("MemoryLayout.ofStruct(\n"); | |
} else { | |
print("MemoryLayout.ofUnion(\n"); | |
} | |
incrAlign(); | |
String delim = ""; | |
for (MemoryLayout e : ((GroupLayout) l).memberLayouts()) { | |
print(delim); | |
indent(); | |
printLayout(e); | |
delim = ",\n"; | |
} | |
print("\n"); | |
decrAlign(); | |
indent(); | |
print(")"); | |
} else { | |
//padding | |
print("MemoryLayout.ofPaddingBits(" + l.bitSize() + ")"); | |
} | |
if (l.name().isPresent()) { | |
print(".withName(\"" + l.name().get() + "\")"); | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment