Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

7903933: Move sharable items from different generations to a common file #278

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 27 additions & 15 deletions src/main/java/org/openjdk/jextract/impl/ClassSourceBuilder.java
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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, "");
}
Expand Down Expand Up @@ -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();
};
}
Expand Down Expand Up @@ -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
Expand All @@ -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;
}

Expand Down
171 changes: 171 additions & 0 deletions src/main/java/org/openjdk/jextract/impl/CommonBindingsBuilder.java
Original file line number Diff line number Diff line change
@@ -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<Options.Library> 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<Options.Library> libraries, boolean useSystemLoadLibrary) {
List<String> 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<String> 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));
};
}
""");
}
}
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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}.
Expand All @@ -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() {
Expand Down
Loading