diff --git a/src/main/java/org/openjdk/jextract/impl/ClassSourceBuilder.java b/src/main/java/org/openjdk/jextract/impl/ClassSourceBuilder.java index 051287ac..8808695e 100644 --- a/src/main/java/org/openjdk/jextract/impl/ClassSourceBuilder.java +++ b/src/main/java/org/openjdk/jextract/impl/ClassSourceBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -160,6 +160,15 @@ final void emitDefaultConstructor() { """, className); } + final void emitPrivateConstructor() { + appendIndentedLines(""" + + private %1$s() { + // Should not be called directly + } + """, className); + } + final void emitDocComment(Declaration decl) { emitDocComment(decl, ""); } @@ -200,11 +209,14 @@ String layoutString(Type type, long align) { return switch (type) { case Primitive p -> primitiveLayoutString(p, align); case Declared d when Utils.isEnum(d) -> layoutString(ClangEnumType.get(d.tree()).get(), align); - case Declared d when Utils.isStructOrUnion(d) -> alignIfNeeded(JavaName.getFullNameOrThrow(d.tree()) + ".layout()", ClangAlignOf.getOrThrow(d.tree()) / 8, align); - case Delegated d when d.kind() == Delegated.Kind.POINTER -> alignIfNeeded(runtimeHelperName() + ".C_POINTER", 8, align); + case Declared d when Utils.isStructOrUnion(d) -> + alignIfNeeded(JavaName.getFullNameOrThrow(d.tree()) + ".layout()", ClangAlignOf.getOrThrow(d.tree()) / 8, align); + case Delegated d when d.kind() == Delegated.Kind.POINTER -> + alignIfNeeded(sb.layoutUtilsName() + "C_POINTER", 8, align); case Delegated d -> layoutString(d.type(), align); - case Function _ -> alignIfNeeded(runtimeHelperName() + ".C_POINTER", 8, align); - case Array a -> String.format("MemoryLayout.sequenceLayout(%1$d, %2$s)", a.elementCount().orElse(0L), layoutString(a.elementType(), align)); + case Function _ -> alignIfNeeded(sb.layoutUtilsName() + "C_POINTER", 8, align); + case Array a -> + String.format("MemoryLayout.sequenceLayout(%1$d, %2$s)", a.elementCount().orElse(0L), layoutString(a.elementType(), align)); default -> throw new UnsupportedOperationException(); }; } @@ -243,16 +255,16 @@ String indentString(int size) { private String primitiveLayoutString(Primitive primitiveType, long align) { return switch (primitiveType.kind()) { - case Bool -> runtimeHelperName() + ".C_BOOL"; - case Char -> runtimeHelperName() + ".C_CHAR"; - case Short -> alignIfNeeded(runtimeHelperName() + ".C_SHORT", 2, align); - case Int -> alignIfNeeded(runtimeHelperName() + ".C_INT", 4, align); - case Long -> alignIfNeeded(runtimeHelperName() + ".C_LONG", TypeImpl.IS_WINDOWS ? 4 : 8, align); - case LongLong -> alignIfNeeded(runtimeHelperName() + ".C_LONG_LONG", 8, align); - case Float -> alignIfNeeded(runtimeHelperName() + ".C_FLOAT", 4, align); - case Double -> alignIfNeeded(runtimeHelperName() + ".C_DOUBLE", 8, align); + case Bool -> sb.layoutUtilsName() + "C_BOOL"; + case Char -> sb.layoutUtilsName() + "C_CHAR"; + case Short -> alignIfNeeded(sb.layoutUtilsName() + "C_SHORT", 2, align); + case Int -> alignIfNeeded(sb.layoutUtilsName() + "C_INT", 4, align); + case Long -> alignIfNeeded(sb.layoutUtilsName() + "C_LONG", TypeImpl.IS_WINDOWS ? 4 : 8, align); + case LongLong -> alignIfNeeded(sb.layoutUtilsName() + "C_LONG_LONG", 8, align); + case Float -> alignIfNeeded(sb.layoutUtilsName() + "C_FLOAT", 4, align); + case Double -> alignIfNeeded(sb.layoutUtilsName() + "C_DOUBLE", 8, align); case LongDouble -> TypeImpl.IS_WINDOWS ? - alignIfNeeded(runtimeHelperName() + ".C_LONG_DOUBLE", 8, align) : + alignIfNeeded(sb.layoutUtilsName() + "C_LONG_DOUBLE", 8, align) : paddingLayoutString(8, 0); case HalfFloat, Char16, WChar -> paddingLayoutString(2, 0); // unsupported case Float128, Int128 -> paddingLayoutString(16, 0); // unsupported @@ -262,7 +274,7 @@ private String primitiveLayoutString(Primitive primitiveType, long align) { private String alignIfNeeded(String layoutPrefix, long align, long expectedAlign) { return align > expectedAlign ? - String.format("%1$s.align(%2$s, %3$d)", runtimeHelperName(), layoutPrefix, expectedAlign) : + String.format("%3$salign(%1$s, %2$d)", layoutPrefix, expectedAlign, sourceFileBuilder().FFMUtilsName()) : layoutPrefix; } diff --git a/src/main/java/org/openjdk/jextract/impl/CommonBindingsBuilder.java b/src/main/java/org/openjdk/jextract/impl/CommonBindingsBuilder.java new file mode 100644 index 00000000..88c6746e --- /dev/null +++ b/src/main/java/org/openjdk/jextract/impl/CommonBindingsBuilder.java @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the LICENSE file that accompanied this code. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +package org.openjdk.jextract.impl; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Moving common layouts and static methods not relevant to component areas into a centralized location + */ + +final class CommonBindingsBuilder extends ClassSourceBuilder { + private CommonBindingsBuilder(SourceFileBuilder builder, String className, String runtimeHelperName) { + super(builder, "public final", Kind.CLASS, className, null, null, runtimeHelperName); + } + + public static void generate(SourceFileBuilder builder, String className, String runtimeHelperName) { + CommonBindingsBuilder cbd = new CommonBindingsBuilder(builder, className, runtimeHelperName); + cbd.appendBlankLine(); + cbd.classBegin(); + cbd.emitPrivateConstructor(); + cbd.appendBlankLine(); + cbd.emitPrimitiveTypes(); + cbd.classEnd(); + } + + public static void generate(SourceFileBuilder builder, String className, String runtimeHelperName, List libs, Boolean useSystemLoadLibrary) { + CommonBindingsBuilder cbd = new CommonBindingsBuilder(builder, className, runtimeHelperName); + cbd.appendBlankLine(); + cbd.classBegin(); + cbd.emitPrivateConstructor(); + cbd.emitCommonFinalFields(); + cbd.emitFirstHeaderPreamble(libs, useSystemLoadLibrary); + cbd.appendBlankLine(); + cbd.emitRuntimeHelperMethods(); + cbd.classEnd(); + } + + // emit basic primitive types + private void emitPrimitiveTypes() { + appendIndentedLines(""" + public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); + public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); + public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); + public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); + public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); + public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); + public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); + public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) + .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); + """); + if (TypeImpl.IS_WINDOWS) { + appendIndentedLines("public static final ValueLayout.OfInt C_LONG = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get(\"long\");"); + appendIndentedLines("public static final ValueLayout.OfDouble C_LONG_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get(\"double\");"); + } else { + appendIndentedLines("public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get(\"long\");"); + } + } + + void emitFirstHeaderPreamble(List libraries, boolean useSystemLoadLibrary) { + List lookups = new ArrayList<>(); + // if legacy library loading is selected, load libraries (if any) into current loader + if (useSystemLoadLibrary) { + appendBlankLine(); + appendIndentedLines(""" + + static { + """); + incrAlign(); + for (Options.Library lib : libraries) { + String method = lib.specKind() == Options.Library.SpecKind.PATH ? "load" : "loadLibrary"; + appendIndentedLines("System.%1$s(\"%2$s\");", method, lib.toQuotedName()); + } + decrAlign(); + appendIndentedLines(""" + } + """); + } else { + // otherwise, add a library lookup per library (if any) + libraries.stream() // add library lookups (if any) + .map(l -> l.specKind() == Options.Library.SpecKind.PATH ? + String.format("SymbolLookup.libraryLookup(\"%1$s\", LIBRARY_ARENA)", l.toQuotedName()) : + String.format("SymbolLookup.libraryLookup(System.mapLibraryName(\"%1$s\"), LIBRARY_ARENA)", l.toQuotedName())) + .collect(Collectors.toCollection(() -> lookups)); + } + + lookups.add("SymbolLookup.loaderLookup()"); // fallback to loader lookup + lookups.add("Linker.nativeLinker().defaultLookup()"); // fallback to native lookup + + // wrap all lookups (but the first) with ".or(...)" + List lookupCalls = new ArrayList<>(); + boolean isFirst = true; + for (String lookup : lookups) { + lookupCalls.add(isFirst ? lookup : String.format(".or(%1$s)", lookup)); + isFirst = false; + } + + // chain all the calls together into a combined symbol lookup + appendBlankLine(); + appendIndentedLines(lookupCalls.stream() + .collect(Collectors.joining(String.format("\n%1$s", indentString(2)), "static final SymbolLookup SYMBOL_LOOKUP = ", ";"))); + } + + private void emitCommonFinalFields() { + appendIndentedLines(""" + static final Arena LIBRARY_ARENA = Arena.ofAuto(); + static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); + + """); + } + private void emitRuntimeHelperMethods() { + appendIndentedLines(""" + static void traceDowncall(String name, Object... args) { + String traceArgs = Arrays.stream(args) + .map(Object::toString) + .collect(Collectors.joining(", ")); + System.out.printf("%s(%s)\\n", name, traceArgs); + } + + static MemorySegment findOrThrow(String symbol) { + return SYMBOL_LOOKUP.findOrThrow(symbol); + } + + static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { + try { + return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); + } catch (ReflectiveOperationException ex) { + throw new AssertionError(ex); + } + } + + static MemoryLayout align(MemoryLayout layout, long align) { + return switch (layout) { + case PaddingLayout p -> p; + case ValueLayout v -> v.withByteAlignment(align); + case GroupLayout g -> { + MemoryLayout[] alignedMembers = g.memberLayouts().stream() + .map(m -> align(m, align)).toArray(MemoryLayout[]::new); + yield g instanceof StructLayout ? + MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); + } + case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); + }; + } + """); + } +} diff --git a/src/main/java/org/openjdk/jextract/impl/FunctionalInterfaceBuilder.java b/src/main/java/org/openjdk/jextract/impl/FunctionalInterfaceBuilder.java index 8ef036c8..23896a25 100644 --- a/src/main/java/org/openjdk/jextract/impl/FunctionalInterfaceBuilder.java +++ b/src/main/java/org/openjdk/jextract/impl/FunctionalInterfaceBuilder.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -83,7 +83,7 @@ public interface %1$s { private void emitFunctionalFactory(String fiName) { appendIndentedLines(""" - private static final MethodHandle UP$MH = %1$s.upcallHandle(%2$s.%3$s.class, "apply", $DESC); + private static final MethodHandle UP$MH = %1$supcallHandle(%2$s.%3$s.class, "apply", $DESC); /** * Allocates a new upcall stub, whose implementation is defined by {@code fi}. @@ -92,7 +92,7 @@ private void emitFunctionalFactory(String fiName) { public static MemorySegment allocate(%2$s.%3$s fi, Arena arena) { return Linker.nativeLinker().upcallStub(UP$MH.bindTo(fi), $DESC, arena); } - """, runtimeHelperName(), className(), fiName); + """, sourceFileBuilder().FFMUtilsName(), className(), fiName); } private void emitInvoke() { diff --git a/src/main/java/org/openjdk/jextract/impl/HeaderFileBuilder.java b/src/main/java/org/openjdk/jextract/impl/HeaderFileBuilder.java index 5d6f16ee..5d640e6b 100644 --- a/src/main/java/org/openjdk/jextract/impl/HeaderFileBuilder.java +++ b/src/main/java/org/openjdk/jextract/impl/HeaderFileBuilder.java @@ -180,12 +180,12 @@ private void emitFunctionWrapper(String javaName, String nativeName, boolean nee private static class %1$s { public static final FunctionDescriptor DESC = %2$s; - public static final MemorySegment ADDR = %3$s.findOrThrow("%4$s"); + public static final MemorySegment ADDR = %4$sfindOrThrow("%3$s"); public static final MethodHandle HANDLE = Linker.nativeLinker().downcallHandle(ADDR, DESC); } """, holderClass, functionDescriptorString(1, decl.type()), - runtimeHelperName(), lookupName(decl)); + lookupName(decl), sourceFileBuilder().FFMUtilsName()); appendBlankLine(); emitDocComment(decl, "Function descriptor for:"); appendLines(""" @@ -213,8 +213,8 @@ private static class %1$s { public static %1$s %2$s(%3$s) { var mh$ = %4$s.HANDLE; try { - if (TRACE_DOWNCALLS) { - traceDowncall(%5$s); + if (%8$sTRACE_DOWNCALLS) { + %8$straceDowncall(%5$s); } %6$smh$.invokeExact(%7$s); } catch (Throwable ex$) { @@ -223,7 +223,8 @@ private static class %1$s { } """, retType, javaName, paramExprs(declType, finalParamNames, isVarArg), - holderClass, traceArgList, returnWithCast, paramList); + holderClass, traceArgList, returnWithCast, paramList, + sourceFileBuilder().FFMUtilsName()); } else { String invokerClassName = newHolderClassName(javaName); String paramExprs = paramExprs(declType, finalParamNames, isVarArg); @@ -232,19 +233,19 @@ private static class %1$s { appendLines(""" public static class %1$s { private static final FunctionDescriptor BASE_DESC = %2$s; - private static final MemorySegment ADDR = %3$s.findOrThrow("%4$s"); + private static final MemorySegment ADDR = %4$sfindOrThrow("%3$s"); private final MethodHandle handle; private final FunctionDescriptor descriptor; private final MethodHandle spreader; - private %5$s(MethodHandle handle, FunctionDescriptor descriptor, MethodHandle spreader) { + private %1$s(MethodHandle handle, FunctionDescriptor descriptor, MethodHandle spreader) { this.handle = handle; this.descriptor = descriptor; this.spreader = spreader; } """, invokerClassName, functionDescriptorString(2, decl.type()), - runtimeHelperName(), lookupName(decl), invokerClassName); + lookupName(decl), sourceFileBuilder().FFMUtilsName()); incrAlign(); appendBlankLine(); emitDocComment(decl, "Variadic invoker factory for:"); @@ -283,8 +284,8 @@ public FunctionDescriptor descriptor() { public %1$s apply(%2$s) { try { - if (TRACE_DOWNCALLS) { - traceDowncall(%3$s); + if (%6$sTRACE_DOWNCALLS) { + %6$straceDowncall(%3$s); } %4$s spreader.invokeExact(%5$s); } catch(IllegalArgumentException | ClassCastException ex$) { @@ -294,7 +295,8 @@ public FunctionDescriptor descriptor() { } } } - """, retType, paramExprs, traceArgList, returnWithCast, paramList); + """, retType, paramExprs, traceArgList, + returnWithCast, paramList, sourceFileBuilder().FFMUtilsName()); } decrAlign(); } @@ -307,91 +309,6 @@ void emitPointerTypedef(Declaration.Typedef typedefTree, String name) { emitPrimitiveTypedefLayout(name, Type.pointer(), typedefTree); } - void emitFirstHeaderPreamble(List libraries, boolean useSystemLoadLibrary) { - List lookups = new ArrayList<>(); - // if legacy library loading is selected, load libraries (if any) into current loader - if (useSystemLoadLibrary) { - appendBlankLine(); - appendIndentedLines(""" - - static { - """); - incrAlign(); - for (Options.Library lib : libraries) { - String method = lib.specKind() == Options.Library.SpecKind.PATH ? "load" : "loadLibrary"; - appendIndentedLines("System.%1$s(\"%2$s\");", method, lib.toQuotedName()); - } - decrAlign(); - appendIndentedLines(""" - } - """); - } else { - // otherwise, add a library lookup per library (if any) - libraries.stream() // add library lookups (if any) - .map(l -> l.specKind() == Options.Library.SpecKind.PATH ? - String.format("SymbolLookup.libraryLookup(\"%1$s\", LIBRARY_ARENA)", l.toQuotedName()) : - String.format("SymbolLookup.libraryLookup(System.mapLibraryName(\"%1$s\"), LIBRARY_ARENA)", l.toQuotedName())) - .collect(Collectors.toCollection(() -> lookups)); - } - - lookups.add("SymbolLookup.loaderLookup()"); // fallback to loader lookup - lookups.add("Linker.nativeLinker().defaultLookup()"); // fallback to native lookup - - // wrap all lookups (but the first) with ".or(...)" - List lookupCalls = new ArrayList<>(); - boolean isFirst = true; - for (String lookup : lookups) { - lookupCalls.add(isFirst ? lookup : String.format(".or(%1$s)", lookup)); - isFirst = false; - } - - // chain all the calls together into a combined symbol lookup - appendBlankLine(); - appendIndentedLines(lookupCalls.stream() - .collect(Collectors.joining(String.format("\n%1$s", indentString(2)), "static final SymbolLookup SYMBOL_LOOKUP = ", ";"))); - } - - void emitRuntimeHelperMethods() { - appendIndentedLines(""" - - static final Arena LIBRARY_ARENA = Arena.ofAuto(); - static final boolean TRACE_DOWNCALLS = Boolean.getBoolean("jextract.trace.downcalls"); - - static void traceDowncall(String name, Object... args) { - String traceArgs = Arrays.stream(args) - .map(Object::toString) - .collect(Collectors.joining(", ")); - System.out.printf("%s(%s)\\n", name, traceArgs); - } - - static MemorySegment findOrThrow(String symbol) { - return SYMBOL_LOOKUP.findOrThrow(symbol); - } - - static MethodHandle upcallHandle(Class fi, String name, FunctionDescriptor fdesc) { - try { - return MethodHandles.lookup().findVirtual(fi, name, fdesc.toMethodType()); - } catch (ReflectiveOperationException ex) { - throw new AssertionError(ex); - } - } - - static MemoryLayout align(MemoryLayout layout, long align) { - return switch (layout) { - case PaddingLayout p -> p; - case ValueLayout v -> v.withByteAlignment(align); - case GroupLayout g -> { - MemoryLayout[] alignedMembers = g.memberLayouts().stream() - .map(m -> align(m, align)).toArray(MemoryLayout[]::new); - yield g instanceof StructLayout ? - MemoryLayout.structLayout(alignedMembers) : MemoryLayout.unionLayout(alignedMembers); - } - case SequenceLayout s -> MemoryLayout.sequenceLayout(s.elementCount(), align(s.elementLayout(), align)); - }; - } - """); - } - private void emitGlobalGetter(String holderClass, String javaName, Declaration.Variable decl, String docHeader) { appendBlankLine(); @@ -515,19 +432,20 @@ private String emitVarHolderClass(Declaration.Variable var, String javaName) { appendIndentedLines(""" private static class %1$s { public static final %2$s LAYOUT = %3$s; - public static final MemorySegment SEGMENT = %4$s.findOrThrow("%5$s").reinterpret(LAYOUT.byteSize()); - %6$s - public static final long[] DIMS = { %7$s }; + public static final MemorySegment SEGMENT = %7$sfindOrThrow("%4$s").reinterpret(LAYOUT.byteSize()); + %5$s + public static final long[] DIMS = { %6$s }; } - """, mangledName, layoutType, layoutString(varType), runtimeHelperName(), - lookupName(var), accessHandle, dimsString); + """, mangledName, layoutType, layoutString(varType), lookupName(var), + accessHandle, dimsString, sourceFileBuilder().FFMUtilsName()); } else { appendIndentedLines(""" private static class %1$s { public static final %2$s LAYOUT = %3$s; - public static final MemorySegment SEGMENT = %4$s.findOrThrow("%5$s").reinterpret(LAYOUT.byteSize()); + public static final MemorySegment SEGMENT = %5$sfindOrThrow("%4$s").reinterpret(LAYOUT.byteSize()); } - """, mangledName, layoutType, layoutString(varType), runtimeHelperName(), lookupName(var)); + """, mangledName, layoutType, layoutString(varType), + lookupName(var), sourceFileBuilder().FFMUtilsName()); } incrAlign(); appendBlankLine(); @@ -567,15 +485,15 @@ private void emitConstant(Class javaType, String constantName, Object value, public static %1$s %2$s() { class Holder { static final %1$s %2$s - = %3$s.LIBRARY_ARENA.allocateFrom("%4$s"); + = %4$sLIBRARY_ARENA.allocateFrom("%3$s"); } return Holder.%2$s; } """, javaType.getSimpleName(), constantName, - runtimeHelperName(), - Utils.quote(Objects.toString(value))); + Utils.quote(Objects.toString(value)), + sourceFileBuilder().FFMUtilsName()); } else { appendLines(""" private static final %1$s %2$s = %3$s; diff --git a/src/main/java/org/openjdk/jextract/impl/SourceFileBuilder.java b/src/main/java/org/openjdk/jextract/impl/SourceFileBuilder.java index 0d55f0f5..f42a3249 100644 --- a/src/main/java/org/openjdk/jextract/impl/SourceFileBuilder.java +++ b/src/main/java/org/openjdk/jextract/impl/SourceFileBuilder.java @@ -49,10 +49,26 @@ public String className() { return className; } + public String getPackageName(){ + return packageName; + } + + public String layoutUtilsName() { + return getPackageName().isEmpty() ? ToplevelBuilder.LAYOUT_UTILS + "." : ""; + } + + public String FFMUtilsName() { + return getPackageName().isEmpty() ? ToplevelBuilder.FFM_UTILS + "." : ""; + } + public static SourceFileBuilder newSourceFile(String packageName, String className) { SourceFileBuilder sfb = new SourceFileBuilder(packageName, className); sfb.emitPackagePrefix(); sfb.emitImportSection(); + if (!className.equals(ToplevelBuilder.FFM_UTILS) && !className.equals(ToplevelBuilder.LAYOUT_UTILS) + && !packageName.isEmpty()) { + sfb.emitStaticImportSection(); + } return sfb; } @@ -81,9 +97,16 @@ void emitImportSection() { import static java.lang.foreign.ValueLayout.*; import static java.lang.foreign.MemoryLayout.PathElement.*; + """); } + void emitStaticImportSection() { + appendLines(String.format(""" + import static %1$s.FFMUtils.*; + import static %1$s.LayoutUtils.*; + """, packageName)); + } // Internal generation helpers (used by other builders) diff --git a/src/main/java/org/openjdk/jextract/impl/ToplevelBuilder.java b/src/main/java/org/openjdk/jextract/impl/ToplevelBuilder.java index 7893c63b..a0833ea7 100644 --- a/src/main/java/org/openjdk/jextract/impl/ToplevelBuilder.java +++ b/src/main/java/org/openjdk/jextract/impl/ToplevelBuilder.java @@ -41,12 +41,15 @@ */ class ToplevelBuilder implements OutputFactory.Builder { private static final int DECLS_PER_HEADER_CLASS = Integer.getInteger("jextract.decls.per.header", 1000); - public static final String PREV_SUFFIX = "#{PREV_SUFFIX}"; + private static final String PREV_SUFFIX = "#{PREV_SUFFIX}"; private static final String SUFFIX = "#{SUFFIX}"; + public static final String LAYOUT_UTILS = "LayoutUtils"; + public static final String FFM_UTILS = "FFMUtils"; private int declCount; private final List headerBuilders = new ArrayList<>(); private final List otherBuilders = new ArrayList<>(); + private final List commonUtilsBuilders = new ArrayList<>(); private HeaderFileBuilder lastHeader; private final ClassDesc headerDesc; @@ -55,35 +58,25 @@ class ToplevelBuilder implements OutputFactory.Builder { this.headerDesc = ClassDesc.of(packageName, headerClassName); SourceFileBuilder sfb = SourceFileBuilder.newSourceFile(packageName, headerClassName); headerBuilders.add(sfb); - lastHeader = createFirstHeader(sfb, libs, useSystemLoadLibrary); + lastHeader = createFirstHeader(sfb); + generateCommonBindings(libs, useSystemLoadLibrary); } - private static HeaderFileBuilder createFirstHeader(SourceFileBuilder sfb, List libs, boolean useSystemLoadLibrary) { - HeaderFileBuilder first = new HeaderFileBuilder(sfb, String.format("%1$s#{SUFFIX}",sfb.className()), null, sfb.className()); + private void generateCommonBindings(List libs, boolean useSystemLoadLibrary) { + var sfb = SourceFileBuilder.newSourceFile(packageName(), LAYOUT_UTILS); + commonUtilsBuilders.add(sfb); + CommonBindingsBuilder.generate(sfb, LAYOUT_UTILS, mainHeaderClassName()); + + sfb = SourceFileBuilder.newSourceFile(packageName(), FFM_UTILS); + commonUtilsBuilders.add(sfb); + CommonBindingsBuilder.generate(sfb, FFM_UTILS, mainHeaderClassName(), libs, useSystemLoadLibrary); + } + + private static HeaderFileBuilder createFirstHeader(SourceFileBuilder sfb) { + HeaderFileBuilder first = new HeaderFileBuilder(sfb, String.format("%1$s%2$s", sfb.className(), SUFFIX), null, sfb.className()); first.appendBlankLine(); first.classBegin(); first.emitDefaultConstructor(); - first.emitRuntimeHelperMethods(); - first.emitFirstHeaderPreamble(libs, useSystemLoadLibrary); - // emit basic primitive types - first.appendIndentedLines(""" - - public static final ValueLayout.OfBoolean C_BOOL = (ValueLayout.OfBoolean) Linker.nativeLinker().canonicalLayouts().get("bool"); - public static final ValueLayout.OfByte C_CHAR =(ValueLayout.OfByte)Linker.nativeLinker().canonicalLayouts().get("char"); - public static final ValueLayout.OfShort C_SHORT = (ValueLayout.OfShort) Linker.nativeLinker().canonicalLayouts().get("short"); - public static final ValueLayout.OfInt C_INT = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get("int"); - public static final ValueLayout.OfLong C_LONG_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get("long long"); - public static final ValueLayout.OfFloat C_FLOAT = (ValueLayout.OfFloat) Linker.nativeLinker().canonicalLayouts().get("float"); - public static final ValueLayout.OfDouble C_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get("double"); - public static final AddressLayout C_POINTER = ((AddressLayout) Linker.nativeLinker().canonicalLayouts().get("void*")) - .withTargetLayout(MemoryLayout.sequenceLayout(java.lang.Long.MAX_VALUE, C_CHAR)); - """); - if (TypeImpl.IS_WINDOWS) { - first.appendIndentedLines("public static final ValueLayout.OfInt C_LONG = (ValueLayout.OfInt) Linker.nativeLinker().canonicalLayouts().get(\"long\");"); - first.appendIndentedLines("public static final ValueLayout.OfDouble C_LONG_DOUBLE = (ValueLayout.OfDouble) Linker.nativeLinker().canonicalLayouts().get(\"double\");"); - } else { - first.appendIndentedLines("public static final ValueLayout.OfLong C_LONG = (ValueLayout.OfLong) Linker.nativeLinker().canonicalLayouts().get(\"long\");"); - } return first; } @@ -118,6 +111,9 @@ public List toFiles() { // add remaining builders files.addAll(otherBuilders.stream() .map(SourceFileBuilder::toFile).toList()); + //add common bindings files + files.addAll(commonUtilsBuilders.stream() + .map(SourceFileBuilder::toFile).toList()); return files; } diff --git a/test/jtreg/generator/clinitCycles/TestGlobal.java b/test/jtreg/generator/clinitCycles/TestGlobal.java index d7f8c58c..6f02406c 100644 --- a/test/jtreg/generator/clinitCycles/TestGlobal.java +++ b/test/jtreg/generator/clinitCycles/TestGlobal.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ public class TestGlobal { @Test public void testGlobal() { - ValueLayout layout = clinit_global_h.C_INT; + ValueLayout layout = LayoutUtils.C_INT; assertNotNull(layout); assertEquals(clinit_global_h.global1(), 1); assertEquals(clinit_global_h.global2(), 2); diff --git a/test/jtreg/generator/clinitCycles/TestStruct.java b/test/jtreg/generator/clinitCycles/TestStruct.java index 931f64ca..6c250b38 100644 --- a/test/jtreg/generator/clinitCycles/TestStruct.java +++ b/test/jtreg/generator/clinitCycles/TestStruct.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -22,6 +22,7 @@ import org.testng.annotations.Test; import test.jextract.clinit.*; +import static test.jextract.clinit.LayoutUtils.*; import java.lang.foreign.GroupLayout; import java.lang.foreign.ValueLayout; @@ -40,7 +41,7 @@ public class TestStruct { @Test public void TestStruct() { - ValueLayout layout = clinit_struct_h.C_INT; + ValueLayout layout = C_INT; assertNotNull(layout); GroupLayout pointLayout = Point.layout(); assertNotNull(pointLayout); diff --git a/test/jtreg/generator/clinitCycles/TestTypedef.java b/test/jtreg/generator/clinitCycles/TestTypedef.java index 705c629c..a4289d36 100644 --- a/test/jtreg/generator/clinitCycles/TestTypedef.java +++ b/test/jtreg/generator/clinitCycles/TestTypedef.java @@ -1,4 +1,4 @@ -/* Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. +/* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -40,7 +40,7 @@ public class TestTypedef { @Test public void TestTypedef() { - ValueLayout layout = clinit_typedef_h.C_INT; + ValueLayout layout = LayoutUtils.C_INT; assertNotNull(layout); assertEquals(layout, clinit_typedef_h.one); assertEquals(layout, clinit_typedef_h.two); diff --git a/test/jtreg/generator/dedup/TestDedup.java b/test/jtreg/generator/dedup/TestDedup.java index 998c3019..6a4e093d 100644 --- a/test/jtreg/generator/dedup/TestDedup.java +++ b/test/jtreg/generator/dedup/TestDedup.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ public void testMacroFields() { } void checkLayout(GroupLayout layout) { - assertEquals(layout.memberLayouts().get(0), macro_fields_h.C_INT.withName("x")); - assertEquals(layout.memberLayouts().get(1), macro_fields_h.C_INT.withName("y")); + assertEquals(layout.memberLayouts().get(0), LayoutUtils.C_INT.withName("x")); + assertEquals(layout.memberLayouts().get(1), LayoutUtils.C_INT.withName("y")); } } diff --git a/test/jtreg/generator/nestedStructTypedef/TestNestedStructTypedef.java b/test/jtreg/generator/nestedStructTypedef/TestNestedStructTypedef.java index 57ab0a92..22f274f1 100644 --- a/test/jtreg/generator/nestedStructTypedef/TestNestedStructTypedef.java +++ b/test/jtreg/generator/nestedStructTypedef/TestNestedStructTypedef.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -45,6 +45,6 @@ public void testMacroFields() { } void checkLayout(GroupLayout layout) { - assertEquals(layout.memberLayouts().get(0), nestedStructTypedef_h.C_INT.withName("x")); + assertEquals(layout.memberLayouts().get(0), LayoutUtils.C_INT.withName("x")); } } diff --git a/test/jtreg/generator/nestedTypes/TestNestedTypes.java b/test/jtreg/generator/nestedTypes/TestNestedTypes.java index fa5377e8..3d19c76d 100644 --- a/test/jtreg/generator/nestedTypes/TestNestedTypes.java +++ b/test/jtreg/generator/nestedTypes/TestNestedTypes.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -56,5 +56,5 @@ void checkNestedLayout(MemoryLayout layout) { assertEquals(((SequenceLayout)nestedLayout).elementLayout().withoutName(), ELEM_NESTED_LAYOUT); } - static final MemoryLayout ELEM_NESTED_LAYOUT = MemoryLayout.structLayout(nested_types_h.C_INT.withName("x")); + static final MemoryLayout ELEM_NESTED_LAYOUT = MemoryLayout.structLayout(LayoutUtils.C_INT.withName("x")); } diff --git a/test/jtreg/generator/nestedTypes/TestNestedTypesNames.java b/test/jtreg/generator/nestedTypes/TestNestedTypesNames.java index 673a41ed..ba6ff95e 100644 --- a/test/jtreg/generator/nestedTypes/TestNestedTypesNames.java +++ b/test/jtreg/generator/nestedTypes/TestNestedTypesNames.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -41,11 +41,11 @@ public class TestNestedTypesNames { static MemoryLayout ARG_STRUCT = MemoryLayout.structLayout( - nested_types_names_h.C_INT.withName("y") + LayoutUtils.C_INT.withName("y") ); static MemoryLayout RET_STRUCT = MemoryLayout.structLayout( - nested_types_names_h.C_INT.withName("x") + LayoutUtils.C_INT.withName("x") ); static FunctionDescriptor FUNC_DESC = FunctionDescriptor.of( diff --git a/test/jtreg/generator/nestedTypes/TestNestedTypesUnsupported.java b/test/jtreg/generator/nestedTypes/TestNestedTypesUnsupported.java index 94e45f8b..e88ac37f 100644 --- a/test/jtreg/generator/nestedTypes/TestNestedTypesUnsupported.java +++ b/test/jtreg/generator/nestedTypes/TestNestedTypesUnsupported.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2024, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -42,7 +42,7 @@ public class TestNestedTypesUnsupported { static MemoryLayout UNDEFINED_STRUCT = MemoryLayout.structLayout( - MemoryLayout.paddingLayout(nested_types_unsupported_h.C_POINTER.byteSize()) + MemoryLayout.paddingLayout(LayoutUtils.C_POINTER.byteSize()) ); @Test diff --git a/test/jtreg/generator/test8244412/LibTest8244412Test.java b/test/jtreg/generator/test8244412/LibTest8244412Test.java index 80b6485f..39d90d8a 100644 --- a/test/jtreg/generator/test8244412/LibTest8244412Test.java +++ b/test/jtreg/generator/test8244412/LibTest8244412Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,7 @@ import test.jextract.test8244412.*; import static test.jextract.test8244412.test8244412_h.*; +import static test.jextract.test8244412.LayoutUtils.*; /* * @test diff --git a/test/jtreg/generator/test8245003/Test8245003.java b/test/jtreg/generator/test8245003/Test8245003.java index e3b729a2..2008a90e 100644 --- a/test/jtreg/generator/test8245003/Test8245003.java +++ b/test/jtreg/generator/test8245003/Test8245003.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -59,8 +59,8 @@ public void testStructAccessor() { @Test public void testArrayAccessor() { var seg = iarr(); - assertEquals(seg.byteSize(), C_INT.byteSize()*5); - int[] arr = seg.toArray(C_INT); + assertEquals(seg.byteSize(), LayoutUtils.C_INT.byteSize()*5); + int[] arr = seg.toArray(LayoutUtils.C_INT); assertEquals(arr.length, 5); assertEquals(arr[0], 2); assertEquals(arr[1], -2); @@ -72,7 +72,7 @@ public void testArrayAccessor() { assertEquals(seg.byteSize(), Foo.sizeof()); assertEquals(Foo.count(seg), 37); var greeting = Foo.greeting(seg); - byte[] barr = greeting.toArray(C_CHAR); + byte[] barr = greeting.toArray(LayoutUtils.C_CHAR); assertEquals(new String(barr), "hello"); } } diff --git a/test/jtreg/generator/test8246341/LibTest8246341Test.java b/test/jtreg/generator/test8246341/LibTest8246341Test.java index 0972d3a5..ce98f2e9 100644 --- a/test/jtreg/generator/test8246341/LibTest8246341Test.java +++ b/test/jtreg/generator/test8246341/LibTest8246341Test.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -28,6 +28,7 @@ import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; import static test.jextract.test8246341.test8246341_h.*; +import static test.jextract.test8246341.LayoutUtils.*; /* * @test diff --git a/test/jtreg/generator/test8252121/Test8252121.java b/test/jtreg/generator/test8252121/Test8252121.java index b70cf1c4..6a112ece 100644 --- a/test/jtreg/generator/test8252121/Test8252121.java +++ b/test/jtreg/generator/test8252121/Test8252121.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -46,7 +46,7 @@ public class Test8252121 { public void test() { try (var arena = Arena.ofConfined()) { int[] array = { 3, 5, 89, 34, -33 }; - MemorySegment seg = arena.allocateFrom(C_INT, array); + MemorySegment seg = arena.allocateFrom(LayoutUtils.C_INT, array); assertEquals(IntStream.of(array).sum(), sum(seg)); assertEquals(IntStream.of(array).reduce(1, (a,b) -> a*b), mul(seg)); } diff --git a/test/jtreg/generator/test8257892/LibUnsupportedTest.java b/test/jtreg/generator/test8257892/LibUnsupportedTest.java index 283a6bdd..ac33c5af 100644 --- a/test/jtreg/generator/test8257892/LibUnsupportedTest.java +++ b/test/jtreg/generator/test8257892/LibUnsupportedTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -34,6 +34,8 @@ import static org.testng.Assert.*; import static test.jextract.unsupported.unsupported_h.*; +import static test.jextract.unsupported.LayoutUtils.*; +import static test.jextract.unsupported.FFMUtils.*; import test.jextract.unsupported.*; /* diff --git a/test/jtreg/generator/testPrintf/TestPrintf.java b/test/jtreg/generator/testPrintf/TestPrintf.java index c81d0911..83aa7aa5 100644 --- a/test/jtreg/generator/testPrintf/TestPrintf.java +++ b/test/jtreg/generator/testPrintf/TestPrintf.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -33,6 +33,7 @@ import static org.testng.Assert.assertEquals; import static test.jextract.printf.printf_h.*; +import static test.jextract.printf.LayoutUtils.*; /* * @test diff --git a/test/jtreg/generator/testStruct/LibStructTest.java b/test/jtreg/generator/testStruct/LibStructTest.java index 4851f22c..1e4d2d4f 100644 --- a/test/jtreg/generator/testStruct/LibStructTest.java +++ b/test/jtreg/generator/testStruct/LibStructTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -31,6 +31,8 @@ import static org.testng.Assert.assertEquals; import static test.jextract.struct.struct_h.*; +import static test.jextract.struct.LayoutUtils.*; +import static test.jextract.struct.FFMUtils.*; import test.jextract.struct.*; /*