--- old/src/jdk.incubator.jextract/share/classes/jdk/incubator/jextract/tool/JavaSourceBuilder.java 2020-02-03 17:34:28.000000000 +0530 +++ new/src/jdk.incubator.jextract/share/classes/jdk/incubator/jextract/tool/JavaSourceBuilder.java 2020-02-03 17:34:27.000000000 +0530 @@ -324,7 +324,8 @@ sb.append(PUB_MODS + mtype.returnType().getName() + " " + f.name() + " ("); String delim = ""; List pNames = new ArrayList<>(); - for (int i = 0 ; i < f.parameters().size() ; i++) { + final int numParams = f.parameters().size(); + for (int i = 0 ; i < numParams; i++) { String pName = f.parameters().get(i).name(); if (pName.isEmpty()) { pName = "x" + i; @@ -334,8 +335,11 @@ delim = ", "; } if (f.type().varargs()) { - String lastArg = "x" + f.parameters().size(); - sb.append(", Object... " + lastArg); + String lastArg = "x" + numParams; + if (numParams > 0) { + sb.append(", "); + } + sb.append("Object... " + lastArg); pNames.add(lastArg); } sb.append(") {\n"); --- old/src/jdk.incubator.jextract/share/classes/jdk/incubator/jextract/tool/Main.java 2020-02-03 17:34:29.000000000 +0530 +++ new/src/jdk.incubator.jextract/share/classes/jdk/incubator/jextract/tool/Main.java 2020-02-03 17:34:29.000000000 +0530 @@ -191,6 +191,10 @@ toplevel = Filter.filter(toplevel, options.filters.toArray(new String[0])); } + //handle names + GroupNameHandler nameHandler = new GroupNameHandler(); + toplevel = nameHandler.fillNames(toplevel); + if (Main.DEBUG) { System.out.println(toplevel); } --- old/test/jdk/TEST.groups 2020-02-03 17:34:30.000000000 +0530 +++ new/test/jdk/TEST.groups 2020-02-03 17:34:30.000000000 +0530 @@ -338,7 +338,8 @@ java/foreign jdk_jextract = \ - java/jextract + java/jextract \ + tools/jextract ############################# --- /dev/null 2020-02-03 17:34:32.000000000 +0530 +++ new/src/jdk.incubator.jextract/share/classes/jdk/incubator/jextract/tool/GroupNameHandler.java 2020-02-03 17:34:31.000000000 +0530 @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2020, 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 jdk.incubator.jextract.tool; + +import jdk.incubator.foreign.MemoryLayout; +import jdk.incubator.jextract.Declaration; +import jdk.incubator.jextract.Position; + +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.List; +import java.util.stream.Collectors; + +final class GroupNameHandler implements Declaration.Visitor { + private final Deque parents = new ArrayDeque<>(); + private int id; + + Declaration.Scoped fillNames(Declaration.Scoped toplevel) { + return (Declaration.Scoped)toplevel.accept(this, null); + } + + @Override + public Declaration visitScoped(Declaration.Scoped d, Void aVoid) { + parents.addFirst(d); + Declaration[] newMembers = d.members().stream() + .map(decl -> decl.accept(this, null)).toArray(Declaration[]::new); + parents.removeFirst(); + return switch (d.kind()) { + case ENUM -> makeGroup(d, newMembers, Declaration::enum_, Declaration::enum_); + case UNION -> makeGroup(d, newMembers, Declaration::union, Declaration::union); + case STRUCT -> makeGroup(d, newMembers, Declaration::struct, Declaration::struct); + case CLASS -> makeGroup(d, newMembers, Declaration::class_, Declaration::class_); + case BITFIELDS -> Declaration.bitfields(d.pos(), d.name(), d.layout().get(), + List.of(newMembers).toArray(new Declaration.Variable[0])); + case NAMESPACE -> Declaration.namespace(d.pos(), d.name(), newMembers); + case TYPEDEF -> Declaration.typedef(d.pos(), d.name(), newMembers[0]); + case TOPLEVEL -> Declaration.toplevel(d.pos(), newMembers); + }; + } + + private interface GroupFactoryNoLayout { + Declaration make(Position pos, String name, Declaration... members); + } + + private interface GroupFactoryLayout { + Declaration make(Position pos, String name, MemoryLayout layout, Declaration... members); + } + + private Declaration makeGroup(Declaration.Scoped d, Declaration[] newMembers, GroupFactoryNoLayout factoryNoLayout, GroupFactoryLayout factoryLayout) { + String name = groupName(d.name()); + if (d.layout().isEmpty()) { + return factoryNoLayout.make(d.pos(), name, newMembers); + } else { + return factoryLayout.make(d.pos(), name, d.layout().get().withName(name), newMembers); + } + } + + private String groupName(String name) { + if (!name.isEmpty()) { + return name; + } else { + String prefix = parents.stream() + .filter(d -> ((Declaration.Scoped)d).kind() != Declaration.Scoped.Kind.TOPLEVEL && !d.name().isEmpty()) + .map(Declaration::name) + .collect(Collectors.joining("$")); + if (((Declaration.Scoped)parents.peek()).kind() == Declaration.Scoped.Kind.TYPEDEF) { + return prefix; + } else { + return prefix + "$" + id++; + } + } + } + + @Override + public Declaration visitDeclaration(Declaration d, Void aVoid) { + return d; + } +} --- /dev/null 2020-02-03 17:34:33.000000000 +0530 +++ new/test/jdk/tools/jextract/JtregJextract.java 2020-02-03 17:34:33.000000000 +0530 @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2020, 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. + * + * 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. + */ + +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.spi.ToolProvider; + +public class JtregJextract { + private static final ToolProvider JEXTRACT = ToolProvider.findFirst("jextract") + .orElseThrow(() -> + new RuntimeException("jextract tool not found") + ); + + private final Path inputDir; + private final Path outputDir; + + JtregJextract() { + this(null, null); + } + + JtregJextract(Path input, Path output) { + inputDir = (input != null) ? input : + Paths.get(System.getProperty("test.src", ".")); + outputDir = (output != null) ? output : + Paths.get(System.getProperty("test.classes", ".")); + + } + + protected String[] processArgs(String... args) { + Pattern sysPropPattern = Pattern.compile("'?\\$\\((.*)\\)'?"); + ArrayList jextrOpts = new ArrayList<>(); + + jextrOpts.clear(); + jextrOpts.add("-C-nostdinc"); + jextrOpts.add("-I"); + jextrOpts.add(inputDir.toAbsolutePath().toString()); + jextrOpts.add("--output"); + jextrOpts.add(outputDir.toAbsolutePath().toString()); + jextrOpts.add("--compile"); + + int i = 0; + while (i < args.length) { + String opt = args[i++]; + switch (opt) { + case "--": + break; + case "--output": + case "--compile": + i++; + continue; + default: { + // Pattern $(system.property.name) is replaced with the + // value of the System property of that name. + Matcher m = sysPropPattern.matcher(opt); + if (m.matches()) { + jextrOpts.add(System.getProperty(m.group(1))); + } else { + jextrOpts.add(opt); + } + } + } + } + + while (i < args.length) { + jextrOpts.add(getInputFilePath(args[i++]).toString()); + } + + return jextrOpts.toArray(String[]::new); + } + + protected int jextract(String... options) { + int result = JEXTRACT.run(System.out, System.err, processArgs(options)); + if (result != 0) { + throw new RuntimeException(JEXTRACT.name() + " returns non-zero value"); + } + return result; + } + + private Path getInputFilePath(String filename) { + return inputDir.resolve(filename).toAbsolutePath(); + } + + public static int main(String[] args) { + JtregJextract jj = new JtregJextract(); + return jj.jextract(args); + } +} --- /dev/null 2020-02-03 17:34:34.000000000 +0530 +++ new/test/jdk/tools/jextract/testStruct/LibStructTest.java 2020-02-03 17:34:34.000000000 +0530 @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2020, 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. + * + * 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. + */ + +import java.incubator.foreign.*; +import org.testng.annotations.Test; +import test.jextract.struct.struct_h; + +import static org.testng.Assert.assertEquals; +import static org.testng.Assert.fail; +import static test.jextract.struct.struct_h.*; + +/* + * @test + * @library .. + * @modules jdk.incubator.jextract + * @run driver JtregJextract -l Struct -t test.jextract.struct -- struct.h + * @run testng LibStructTest + */ +public class LibStructTest { + @Test + public void func() {} + + /* + @Test + public void testVoidArguments() { + libStruct.voidArguments(); + assertEquals(Pointer.toString(libStruct.LastCalledMethod$get()), "voidArguments"); + } + + @Test + public void testEmptyArguments() { + libStruct.emptyArguments(1); + assertEquals(Pointer.toString(libStruct.LastCalledMethod$get()), "emptyArguments"); + } + + @Test + public void testCastAndAccess() { + Pointer ptr = libStruct.allocateUndefinedStruct(); + Plain pt = libStruct.fromUndefinedStruct(ptr); + assertEquals(pt.x$get(), 0x1234); + assertEquals(pt.y$get(), 0x3412); + + try { + Plain tmp = ptr.cast(LayoutType.ofStruct(Plain.class)).get(); + fail("Should not be able to cast incompatible layout directly"); + } catch (ClassCastException ex) { + // ignore expected + } + + // This is working now as an escape, but should it really? + Plain tmp = ptr.cast(NativeTypes.VOID).cast(LayoutType.ofStruct(Plain.class)).get(); + assertEquals(tmp.x$get(), 0x1234); + assertEquals(tmp.y$get(), 0x3412); + }*/ +} --- /dev/null 2020-02-03 17:34:35.000000000 +0530 +++ new/test/jdk/tools/jextract/testStruct/libStruct.c 2020-02-03 17:34:35.000000000 +0530 @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2020, 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. + * + * 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. + */ + +#include "struct.h" +#include +#include + +EXPORT char* LastCalledMethod; + +struct UndefinedStruct { + int x; + int y; +}; + +struct UndefinedStructForPointer { + UndefinedStruct position; + UndefinedStructPointer parent; + UndefinedStructPointer firstChild; + struct UndefinedStructForPointer *left; + UndefinedStructPointer right; + struct Opaque *data; +}; + +struct Opaque { + int size; + char *data; +}; + +EXPORT UndefinedStruct* allocateUndefinedStruct() { + UndefinedStruct *p = malloc(sizeof(UndefinedStruct)); + p->x = 0x1234; + p->y = 0x3412; + return p; +} + +EXPORT struct Plain fromUndefinedStruct(UndefinedStruct *p) { + return *((struct Plain*) p); +} + +// intentionally mismatch prototype with same type +EXPORT UndefinedStructPointer getParent(struct UndefinedStructForPointer * node) { + return node->parent; +} + +// intentionally mismatch prototype with same type +EXPORT UndefinedStructPointer getSibling(UndefinedStructPointer node) { + return node->right; +} + +EXPORT UndefinedStructPointer getFirstChild(struct UndefinedStructForPointer *node) { + return node->firstChild; +} + +EXPORT struct Opaque* allocate_opaque_struct() { + return (struct Opaque*) malloc(sizeof(struct Opaque)); +} + +EXPORT TypedefAnonymous getAnonymous(TypedefNamedDifferent_t fns, int x, int y) { + TypedefAnonymous s; + s.x = x; + s.y = y; + s.l = fns.fn(x, y); + + return s; +} + +EXPORT void emptyArguments() { + LastCalledMethod = "emptyArguments"; + printf("%s\n", LastCalledMethod); +} + +EXPORT void voidArguments(void) { + LastCalledMethod = "voidArguments"; + printf("%s\n", LastCalledMethod); +} + +EXPORT void* FunctionWithVoidPointer(void *data, void **array_data) { + return NULL; +} --- /dev/null 2020-02-03 17:34:36.000000000 +0530 +++ new/test/jdk/tools/jextract/testStruct/struct.h 2020-02-03 17:34:36.000000000 +0530 @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2020, 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. + * + * 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. + */ + +#ifdef __cplusplus +extern "C" { +#endif // __cplusplus + +#ifdef _WIN64 +#define EXPORT __declspec(dllexport) +#else +#define EXPORT +#endif + +typedef struct UndefinedStruct UndefinedStruct; +EXPORT UndefinedStruct* allocateUndefinedStruct(); + +typedef struct UndefinedStructForPointer *UndefinedStructPointer; +EXPORT UndefinedStructPointer getParent(UndefinedStructPointer node); +EXPORT struct UndefinedStructForPointer* getSibling(UndefinedStructPointer node); +EXPORT UndefinedStructPointer getFirstChild(struct UndefinedStructForPointer* node); + +EXPORT struct Opaque* allocate_opaque_struct(); + +typedef struct TypedefNamedAsIs { + int i; + long l; +} TypedefNamedAsIs; + +typedef struct TypedefNamedDifferent { + long (*fn)(int i, int j); +} TypedefNamedDifferent_t; + +typedef struct { + union { + long l; + struct { + int x1; + int y1; + }; + struct { + int x2; + int y2; + } p2; + }; + int x; + int y; +} TypedefAnonymous; + +struct Plain { + int x; + int y; +}; + +EXPORT struct Plain fromUndefinedStruct(UndefinedStruct *p); + +EXPORT TypedefAnonymous getAnonymous(TypedefNamedDifferent_t fn, int x, int y); + +EXPORT void emptyArguments(); +EXPORT void voidArguments(void); + +typedef void* (*FunctionPointer)(void *data, void **array_data); + +EXPORT void* FunctionWithVoidPointer(void *data, void **array_data); + +EXPORT extern char* LastCalledMethod; + +#ifdef __cplusplus +} +#endif // __cplusplus