changeset 58901:d6f2bf38b95b foreign

8222025: jextract generates reference to underfined type for va_list Reviewed-by: mcimadamore
author sundar
date Mon, 08 Apr 2019 20:15:51 +0530
parents 598c7de32482
children ff8363d4969e fd46cd549dd6 85aacaac9b3b
files make/copy/Copy-jdk.jextract.gmk src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactory.java src/jdk.jextract/share/classes/com/sun/tools/jextract/BuiltinTypesHandler.java src/jdk.jextract/share/classes/com/sun/tools/jextract/Context.java src/jdk.jextract/share/classes/com/sun/tools/jextract/HeaderResolver.java src/jdk.jextract/share/classes/com/sun/tools/jextract/JavaSourceFactory.java src/jdk.jextract/share/classes/com/sun/tools/jextract/JextractTool.java src/jdk.jextract/share/classes/com/sun/tools/jextract/TypeDictionary.java src/jdk.jextract/share/classes/com/sun/tools/jextract/Utils.java test/jdk/com/sun/tools/jextract/test8222025/ValistUseTest.java test/jdk/com/sun/tools/jextract/test8222025/va_list_use.h
diffstat 11 files changed, 278 insertions(+), 7 deletions(-) [+]
line wrap: on
line diff
--- a/make/copy/Copy-jdk.jextract.gmk	Wed Apr 03 21:28:01 2019 +0530
+++ b/make/copy/Copy-jdk.jextract.gmk	Mon Apr 08 20:15:51 2019 +0530
@@ -27,11 +27,18 @@
 
 ################################################################################
 
-$(eval $(call SetupCopyFiles, COPY_JEXTRACT_HEADERS, \
+$(eval $(call SetupCopyFiles, COPY_CLANG_HEADERS, \
     DEST := $(CONF_DST_DIR)/jextract, \
     FILES := $(wildcard $(CLANG_INCLUDE_AUX_PATH)/*.h), \
 ))
 
-TARGETS := $(COPY_JEXTRACT_HEADERS)
+JEXTRACT_HEADERS_SRC := $(TOPDIR)/src/jdk.jextract/share/conf
+
+$(eval $(call SetupCopyFiles, COPY_JEXTRACT_HEADERS, \
+    DEST := $(CONF_DST_DIR)/jextract, \
+    FILES := $(wildcard $(JEXTRACT_HEADERS_SRC)/*.h), \
+))
+
+TARGETS := $(COPY_CLANG_HEADERS) $(COPY_JEXTRACT_HEADERS)
 
 ################################################################################
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactory.java	Wed Apr 03 21:28:01 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/AsmCodeFactory.java	Mon Apr 08 20:15:51 2019 +0530
@@ -161,7 +161,7 @@
             SourceLocation src = tree.location();
             SourceLocation.Location loc = src.getFileLocation();
             Path p = loc.path();
-            av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
+            av.visit("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
             av.visit("line", loc.line());
             av.visit("column", loc.column());
             av.visitEnd();
@@ -199,7 +199,7 @@
             SourceLocation src = tree.location();
             SourceLocation.Location loc = src.getFileLocation();
             Path p = loc.path();
-            av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
+            av.visit("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
             av.visit("line", loc.line());
             av.visit("column", loc.column());
             av.visitEnd();
@@ -249,7 +249,7 @@
             AnnotationVisitor av = mv.visitAnnotation(NATIVE_LOCATION, true);
             SourceLocation.Location loc = src.getFileLocation();
             Path p = loc.path();
-            av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
+            av.visit("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
             av.visit("line", loc.line());
             av.visit("column", loc.column());
             av.visitEnd();
@@ -444,7 +444,7 @@
             SourceLocation src = funcTree.location();
             SourceLocation.Location loc = src.getFileLocation();
             Path p = loc.path();
-            av.visit("file", p == null ? "builtin" : p.toAbsolutePath().toString());
+            av.visit("file", p == null ? "<builtin>" : p.toAbsolutePath().toString());
             av.visit("line", loc.line());
             av.visit("column", loc.column());
             av.visitEnd();
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/BuiltinTypesHandler.java	Mon Apr 08 20:15:51 2019 +0530
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2019, 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.
+ */
+package com.sun.tools.jextract;
+
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.logging.Logger;
+import com.sun.tools.jextract.parser.Parser;
+import com.sun.tools.jextract.tree.HeaderTree;
+import com.sun.tools.jextract.tree.SimpleTreeVisitor;
+import com.sun.tools.jextract.tree.Tree;
+import com.sun.tools.jextract.tree.TreeMaker;
+import com.sun.tools.jextract.tree.TreePhase;
+import com.sun.tools.jextract.tree.TreePrinter;
+import jdk.internal.clang.Cursor;
+
+/**
+ * Handles builtin struct/union types by creating fake Trees in a
+ * builtin header tree.
+ */
+final class BuiltinTypesHandler extends SimpleTreeVisitor<Void, Void>
+        implements TreePhase {
+    private final TreeMaker treeMaker = new TreeMaker();
+
+    // Potential Tree instances that will go into transformed HeaderTree
+    // are collected in this list.
+    private List<Tree> decls = new ArrayList<>();
+    private final Log log;
+
+    public BuiltinTypesHandler(Context ctx) {
+        this.log = ctx.log;
+    }
+
+    @Override
+    public HeaderTree transform(HeaderTree ht) {
+        // Process all header declarations are collect potential
+        // declarations that will go into transformed HeaderTree
+        // into the this.decls field.
+        ht.accept(this, null);
+
+        return treeMaker.createHeader(ht.cursor(), ht.path(), decls);
+    }
+
+    @Override
+    public Void defaultAction(Tree tree, Void v) {
+        /*
+         * There are built-in types like struct __va_list_tag. These are not exposed
+         * as declaration cursor for any headers, but are available from Type objects.
+         * We've to walk and check null file path to detect these Cursors and create Trees.
+         */
+        Utils.getBuiltinRecordTypes(tree.type()).forEach(c -> {
+            decls.add(treeMaker.createTree(c));
+        });
+
+        decls.add(tree);
+        return null;
+    }
+
+    @Override
+    public Void visitHeader(HeaderTree ht, Void v) {
+        ht.declarations().forEach(decl -> decl.accept(this, null));
+        return null;
+    }
+
+    // test main to manually check this visitor
+    public static void main(String[] args) {
+        if (args.length == 0) {
+            System.err.println("Expected a header file");
+            return;
+        }
+
+        Context context = Context.createDefault();
+        Parser p = new Parser(context, true);
+        Path builtinInc = Paths.get(System.getProperty("java.home"), "conf", "jextract");
+        List<String> clangArgs = List.of("-I" + builtinInc);
+        HeaderTree header = p.parse(Paths.get(args[0]), clangArgs);
+        TreePrinter printer = new TreePrinter();
+        BuiltinTypesHandler handler = new BuiltinTypesHandler(context);
+        handler.transform(header).accept(printer, null);
+    }
+}
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/Context.java	Wed Apr 03 21:28:01 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/Context.java	Mon Apr 08 20:15:51 2019 +0530
@@ -55,4 +55,8 @@
     public static Path getBuiltinHeadersDir() {
         return Paths.get(System.getProperty("java.home"), "conf", "jextract");
     }
+
+    public static Path getBuiltinHeaderFile() {
+        return getBuiltinHeadersDir().resolve("builtin$.h");
+    }
 }
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/HeaderResolver.java	Wed Apr 03 21:28:01 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/HeaderResolver.java	Mon Apr 08 20:15:51 2019 +0530
@@ -38,10 +38,12 @@
     // The header file parsed
     private final Map<Path, HeaderFile> headerMap = new LinkedHashMap<>();
     private final Log log;
+    private final Path builtinHeader;
 
     public HeaderResolver(Context ctx) {
         this.log = ctx.log;
         usePackageForFolder(Context.getBuiltinHeadersDir(), "clang_support");
+        this.builtinHeader = Context.getBuiltinHeaderFile();
         ctx.sources.stream()
                 .map(Path::getParent)
                 .forEach(p -> usePackageForFolder(p, ctx.options.targetPackage));
@@ -144,6 +146,10 @@
     }
 
     public HeaderFile headerFor(Path path) {
+        if (path == null) {
+            path = builtinHeader;
+        }
+
         return headerMap.computeIfAbsent(path.normalize().toAbsolutePath(), this::getHeaderFile);
     }
 }
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/JavaSourceFactory.java	Wed Apr 03 21:28:01 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/JavaSourceFactory.java	Mon Apr 08 20:15:51 2019 +0530
@@ -168,7 +168,7 @@
             SourceLocation.Location loc = src.getFileLocation();
             Path p = loc.path();
             Map<String, Object> fields = new HashMap<>();
-            fields.put("file", p == null ? "builtin" :  p.toAbsolutePath().toString().replace("\\", "\\\\"));
+            fields.put("file", p == null ? "<builtin>" :  p.toAbsolutePath().toString().replace("\\", "\\\\"));
             fields.put("line", loc.line());
             fields.put("column", loc.column());
             jsb.addAnnotation(align, NATIVE_LOCATION, fields);
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/JextractTool.java	Wed Apr 03 21:28:01 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/JextractTool.java	Mon Apr 08 20:15:51 2019 +0530
@@ -68,6 +68,7 @@
                 .map(new SymbolFilter(ctx))
                 .map(new LibraryLookupFilter(ctx))
                 .map(new DependencyFilter(ctx))
+                .map(new BuiltinTypesHandler(ctx))
                 .map(new TypedefHandler(ctx))
                 .map(new EmptyNameHandler())
                 .map(new DuplicateDeclarationHandler())
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/TypeDictionary.java	Wed Apr 03 21:28:01 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/TypeDictionary.java	Mon Apr 08 20:15:51 2019 +0530
@@ -66,6 +66,9 @@
         try {
             //try resolve globally
             Path p = t.getDeclarationCursor().getSourceLocation().getFileLocation().path();
+            if (p == null) {
+                p = Context.getBuiltinHeaderFile();
+            }
             HeaderFile hf = resolver.headerFor(p);
             return Utils.toInternalName(hf.pkgName, hf.headerClsName);
         } catch (Throwable ex) {
--- a/src/jdk.jextract/share/classes/com/sun/tools/jextract/Utils.java	Wed Apr 03 21:28:01 2019 +0530
+++ b/src/jdk.jextract/share/classes/com/sun/tools/jextract/Utils.java	Mon Apr 08 20:15:51 2019 +0530
@@ -27,6 +27,7 @@
 import java.foreign.layout.Layout;
 import java.nio.file.Files;
 import java.nio.file.Path;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.List;
 import java.util.Optional;
@@ -36,6 +37,7 @@
 
 import jdk.internal.clang.Cursor;
 import jdk.internal.clang.CursorKind;
+import jdk.internal.clang.SourceLocation;
 import jdk.internal.clang.Type;
 import com.sun.tools.jextract.tree.LayoutUtils;
 import jdk.internal.clang.TypeKind;
@@ -184,6 +186,57 @@
         }
     }
 
+    // return builtin Record types accessible from the given Type
+    public static Stream<Cursor> getBuiltinRecordTypes(Type type) {
+        List<Cursor> recordTypes = new ArrayList<>();
+        fillBuiltinRecordTypes(type, recordTypes);
+        return recordTypes.stream().distinct();
+    }
+
+    private static void fillBuiltinRecordTypes(Type type, List<Cursor> recordTypes) {
+        type = type.canonicalType();
+        switch (type.kind()) {
+            case ConstantArray:
+            case IncompleteArray:
+                fillBuiltinRecordTypes(type.getElementType(), recordTypes);
+                break;
+
+            case FunctionProto:
+            case FunctionNoProto: {
+                final int numArgs = type.numberOfArgs();
+                for (int i = 0; i < numArgs; i++) {
+                    fillBuiltinRecordTypes(type.argType(i), recordTypes);
+                }
+                fillBuiltinRecordTypes(type.resultType(), recordTypes);
+            }
+            break;
+
+            case Record: {
+                Cursor c = type.getDeclarationCursor();
+                if (c.isDefinition()) {
+                    SourceLocation sloc = c.getSourceLocation();
+                    if (sloc != null && sloc.getFileLocation().path() == null) {
+                        recordTypes.add(c);
+                    }
+                }
+            }
+            break;
+
+            case BlockPointer:
+            case Pointer:
+                fillBuiltinRecordTypes(type.getPointeeType(), recordTypes);
+                break;
+
+            case Unexposed:
+            case Elaborated:
+            case Typedef:
+                fillBuiltinRecordTypes(type, recordTypes);
+                break;
+
+            default: // nothing to do
+        }
+    }
+
     // return the absolute path of the library of given name by searching
     // in the given array of paths.
     public static Optional<Path> findLibraryPath(Path[] paths, String libName) {
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/tools/jextract/test8222025/ValistUseTest.java	Mon Apr 08 20:15:51 2019 +0530
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2019, 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.io.IOException;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertTrue;
+
+/*
+ * @test
+ * @bug 8222025
+ * @summary jextract generates reference to underfined type for va_list
+ * @library ..
+ * @run testng ValistUseTest
+ */
+public class ValistUseTest extends JextractToolRunner {
+    @Test
+    public void test() throws IOException {
+        Path vaListUseJar = getOutputFilePath("test8222025.jar");
+        deleteFile(vaListUseJar);
+        Path va_list_use_H = getInputFilePath("va_list_use.h");
+        run("-o", vaListUseJar.toString(),
+            va_list_use_H.toString()).checkSuccess();
+        try {
+            Loader loader = classLoader(vaListUseJar);
+            Class<?> vaListTag = loader.loadClass("clang_support.builtin$$__va_list_tag");
+            assertTrue(vaListTag != null);
+        } finally {
+            deleteFile(vaListUseJar);
+        }
+     }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/jdk/com/sun/tools/jextract/test8222025/va_list_use.h	Mon Apr 08 20:15:51 2019 +0530
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2019, 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
+
+#include <stdarg.h>
+
+EXPORT void func(const char* fmt, va_list list);
+
+#ifdef __cplusplus
+}
+#endif // __cplusplus