[foreign] RFR 8220544: Jextract; library dependent header filtering

Jorn Vernee jbvernee at xs4all.nl
Wed Mar 20 15:51:43 UTC 2019


Well, no, it's not documented, but it is implemented that way on Windows 
[1]:

     // match in unicode_case_insensitive
     final Pattern pattern = Pattern.compile(expr,
         Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);

But that's just how it goes with implementation dependent APIs right?

In general; I'd say we want to take maximum advantage of file system 
leniency when matching paths, and on Windows this also makes path 
matching case insensitive.

Jorn

[1] : 
http://hg.openjdk.java.net/jdk/jdk/file/83cace4142c8/src/java.base/windows/classes/sun/nio/fs/WindowsFileSystem.java#l278

Sundararajan Athijegannathan schreef op 2019-03-20 16:39:
> That API you're using does not seem to guarantee anything case
> matching - so lenient on Windows does not seem to be guaranteed,
> right?
> 
> PS. "the default Unix file system _is_ case sensitive". No, not Mac -
> as usual mac is different :)
> 
> -Sundar
> 
> On 20/03/19, 8:53 PM, Jorn Vernee wrote:
>> For the header path matching, we are currently not implementation 
>> dependent. But, my suggestion is to be lenient towards path casing on 
>> Windows. We could make the current pattern match case insensitive, but 
>> the case sensitivity of paths depends on the file system, so using a 
>> file system dependent utility seems appropriate. AFAICT the default 
>> Unix file system _is_ case sensitive. So I think we want to retain 
>> case sensitive matching in that case?
>> 
>> Note that we are currently always using the default file system when 
>> creating paths for SourceLocations, because we rely on Paths::get to 
>> create them.
>> 
>> Jorn
>> 
>> Sundararajan Athijegannathan schreef op 2019-03-20 16:02:
>>> Hmm..
>>> 
>>> The javadoc says this:
>>> 
>>> " For both the glob and regex syntaxes, the matching details, such as
>>> whether the matching is case sensitive, are implementation-dependent
>>> and therefore not specified."
>>> https://docs.oracle.com/javase/10/docs/api/java/nio/file/FileSystem.html
>>> 
>>> Are we dependent on implementation dependent behavior?
>>> 
>>> -Sundar
>>> 
>>> On 20/03/19, 7:21 PM, Jorn Vernee wrote:
>>> 
>>>> While trying to get a minimal artifact for the opengl sample I ran
>>>> into a weird problem where clang was changing the casing of some of
>>>> the system header paths, which was making the regex match fail.
>>>> Casing of paths on Windows is mostly irrelevant, so that explains
>>>> why this wasn't a problem before.
>>>> 
>>>> After searching for a solution I arrived at
>>>> FileSystem::getPathMatcher, i.e. a utility for matching paths
>>>> already exists, and has FileSystem specific implementations (e.g.
>>>> making the match case insensitive on Windows).
>>>> 
>>>> Switching to that solves the problem:
>>>> http://cr.openjdk.java.net/~jvernee/panama/webrevs/caps/webrev.00
>>>> 
>>>> The numbers are:
>>>> 
>>>> OpenGL:
>>>> before: 4244087 bytes
>>>> after:  106145 bytes (~40x improvement)
>>>> 
>>>> Python:
>>>> before: 482587 bytes
>>>> after:  317240 bytes (~1.5x improvement)
>>>> 
>>>> Tensorflow:
>>>> before: 76915 bytes
>>>> after:  41267 bytes (~1.9x improvement)
>>>> 
>>>> The improvement is most significant for libraries that depend
>>>> heavily on the Windows API (OpenGL) since there's a lot that can be
>>>> filtered out.
>>>> 
>>>> Cheers,
>>>> Jorn
>>>> 
>>>> Maurizio Cimadamore schreef op 2019-03-19 22:06:
>>>> Cool! This is very nice milestone for jextract :-)
>>>> 
>>>> When you have time (and if you can) it would be nice to get some
>>>> stats
>>>> on extracting a library (e.g. Python) on Windows before/after, to
>>>> get
>>>> a sense of what degree of improvement in terms of static footprint
>>>> we
>>>> can get. I tested on Linux and I can get smaller jars (up to 2x) but
>>>> I
>>>> sense that the improvement is much more dramatic on Windows-land.
>>>> 
>>>> Maurizio
>>>> 
>>>> On 19/03/2019 19:58, Jorn Vernee wrote:
>>>> Thanks for the reviews. I've updated the comment and pushed.
>>>> 
>>>> Jorn
>>>> 
>>>> Sundararajan Athijegannathan schreef op 2019-03-19 18:07:
>>>> Tests passed. Please go ahead with push.
>>>> 
>>>> -Sundar
>>>> 
>>>> On 19/03/19, 7:46 PM, Sundararajan Athijegannathan wrote:
>>>> * 47 * A merge between {@link DependencyFinder} and {@link
>>>> ElementFilter}
>>>> 
>>>> in DependencyFilter. Could be removed?
>>>> 
>>>> No comments other than that. +1
>>>> 
>>>> I'm going to submit an internal mach5 build/request for this patch.
>>>> I'll notify you as soon as it is all green.
>>>> 
>>>> -Sundar
>>>> 
>>>> On 19/03/19, 7:34 PM, Maurizio Cimadamore wrote:
>>>> This looks good to me, I have no further comments.
>>>> 
>>>> Great work!
>>>> 
>>>> (I'll leave it to Sundar for further comments/suggestions)
>>>> 
>>>> Maurizio
>>>> 
>>>> On 19/03/2019 13:50, Jorn Vernee wrote:
>>>> Suggestions sound good.
>>>> 
>>>> Here's the updated webrev:
>>>> 
>>> http://cr.openjdk.java.net/~jvernee/panama/webrevs/8220544/webrev.07/
>>>> 
>>>> 
>>>> * Split library based filtering code off from SymbolFilter into
>>>> LibraryLookupFilter.
>>>> * Merged DependencyFinder & ElementFilter into DependencyFilter (as
>>>> nested classes).
>>>> * Also added 2 more test cases to check that symbols being filtered
>>>> out don't have their dependencies added.
>>>> 
>>>> Jorn
>>>> 
>>>> Maurizio Cimadamore schreef op 2019-03-19 13:40:
>>>> Looks good, I did some tests and it seems to behave according to the
>>>> 
>>>> expectations - some comments below:
>>>> 
>>>> On 18/03/2019 10:58, Jorn Vernee wrote:
>>>> Hi,
>>>> 
>>>> I have implemented this:
>>>> 
>>> http://cr.openjdk.java.net/~jvernee/panama/webrevs/8220544/webrev.06/
>>>> This adds 2 options --include-headers and --exclude-headers that
>>>> take regular expression patterns as an argument. The patterns are
>>>> matched against a cursor's full header file path to determine if it
>>>> appears in the header root set.
>>>> 
>>>> For example, I can use the following to include headers in the
>>>> Python include director;
>>>> 
>>>> --include-headers "J:\\Python27\\include\\.*"
>>>> 
>>>> ---
>>>> 
>>>> To recap, we now:
>>>> 1.) Filter functions, vars, and macros by whether they appear in a
>>>> root header.
>>>> 2.) Filter functions, vars, and macros by the
>>>> --includes/exclude-symbols patterns.
>>>> 3.) Filter functions and vars, by whether they appear in any
>>>> shared library.
>>>> 
>>>> I think this is ok, but the way this happens in the code seems to be
>>>> 
>>>> sort of ad hoc, and probably the result of how the code use to be in
>>>> 
>>>> previous rounds.
>>>> 
>>>> For instance, SymbolFilter does both (1), (2) and (3).
>>>> 
>>>> Then we have DependencyFinder which also does a bit of (1).
>>>> 
>>>> Finally we have ElementFilter, which drops everything that is not
>>>> required (as per 4, 5).
>>>> 
>>>> I believe the code could be improved by:
>>>> 
>>>> * separating the library-based filtering from the option-driven
>>>> filtering. These are two separate mechanism (the latter being
>>>> optional
>>>> on -L being used at all). Of course we should also decide which is
>>>> used first.
>>>> 
>>>> * bring together DependencyFinder and ElementFilter into
>>>> DependencyFilter. You can have a two pass visitor - collect deps on
>>>> a
>>>> first pass, then prune on the second pass. This way the state
>>>> remains
>>>> 'internal' to the DependencyFilter visitor, no need to pass magic
>>>> state between two passes.
>>>> 
>>>> Maurizio
>>>> 
>>>> 4.) For the remaining trees in the root headers do dependency
>>>> analysis, and find the required structs, enums, and typedefs.
>>>> 5.) For structs, enums, and typedefs include them if they appear
>>>> in a root header OR are required as dependency.
>>>> 
>>>> Cheers,
>>>> Jorn
>>>> 
>>>> Maurizio Cimadamore schreef op 2019-03-15 19:29:
>>>> On 15/03/2019 18:21, Jorn Vernee wrote:
>>>> Heh - was writing an email pretty much with this suggestion :P
>>>> 
>>>> I think this is a good idea! If you don't think this adds to much
>>>> complexity to the options?
>>>> 
>>>> So we'd basically have:
>>>> 
>>>> Without --include/exclude-header -> same behavior we have right
>>>> now.
>>>> With --include/exclude-header -> Add included headers to root set
>>>> + find any dependencies, and put both in the generated artifact.
>>>> 
>>>> I like that it does no filtering by default, so ad-hoc users don't
>>>> have to figure out which header files define which functions.
>>>> 
>>>> Yep - I like this too. It goes towards the 'no magic' goal, and it
>>>> adds the filter option that makes most sense when you want to chop
>>>> down an API for good. This is a filtering mechanism after all, the
>>>> fact that it's coming back as a filtering option is IMHO, a plus, no
>>>> a
>>>> minus.
>>>> 
>>>> Btw, slight revision to what I said previously - let's make the
>>>> argument of include/exclude regexes too (as for others). This way it
>>>> 
>>>> can be even easier to use, most headers do have some commonalities
>>>> in
>>>> them - and I like that, with that,  we can basically do the
>>>> path-based
>>>> heuristics w/o hardwiring that into jextract.
>>>> 
>>>> Maurizio
>>>> 
>>>> Jorn
>>>> 
>>>> Maurizio Cimadamore schreef op 2019-03-15 19:07:
>>>> On 15/03/2019 18:01, Maurizio Cimadamore wrote:
>>>> 
>>>> On 15/03/2019 17:48, Jorn Vernee wrote:
>>>> I've implemented this, and now doing a clean build based on the
>>>> latest jdk/jdk merge before submitting the next webrev.
>>>> 
>>>> It's working nicely, with one caveat; Some headers rely on
>>>> pre-processor code defined in a parent header. For instance,
>>>> Python.h defines some pre-processor code used in pythonrun.h . The
>>>> example we have only uses functions defined in pythonrun.h, but if
>>>> we just pass that header to jextract Clang throws an error because
>>>> of the missing pre-processor code from Python.h
>>>> 
>>>> In this case we have to pass Python.h first, and then pythonrun.h to
>>>> get everything to work. This also relies on the existence of header
>>>> include guards in the pythonrun.h header (since we're basically
>>>> including it twice). A similar caveat exists with the Windows API.
>>>> 
>>>> Doh! Maybe I've missed the simplest option after all.
>>>> 
>>>> What if the root set was a 'first class' concept in the extraction
>>>> run, rather than something we infer from this or than command line
>>>> option?
>>>> 
>>>> That way we could point jextract at python.h, but then say "hey, I'm
>>>> only really interested at stuff that comes from pythonrun.h".
>>> 
>>> In other words, right now we have
>>> 
>>> --include-symbol
>>> 
>>> and
>>> 
>>> --exclude-symbol
>>> 
>>> If not set, everything is included.
>>> 
>>> Maybe all we need is:
>>> 
>>> --include-header <header>
>>> 
>>> --exclude-header <header>
>>> 
>>> And, again, if none is specified, all headers are part of the 'root
>>> set'.
>>> 
>>> And, to address a concern you had - yes, I'd consider using the
>>> 'include path' for header names in --include/exclude-header
>>> 
>>> Maurizio
>>> 
>>>> Maurizio
>>>> 
>>>> So, the guide-line is: Pass the main header first, then internal
>>>> headers. e.g. If we have a main header A.h which includes a_impl.h,
>>>> and another main header B.h which includes b_impl.h, headers should
>>>> be passed to jextract in the order: A.h a_impl.h B.h b_impl.h
>>>> 
>>>> I think the behavior being dependent on the ordering of the headers
>>>> could be fixed by sorting the headers in topological order. But,
>>>> there's still the requirement to pass all of them, or things break.
>>>> 
>>>> Any thoughs about that?
>>>> 
>>>> Thanks,
>>>> Jorn
>>>> 
>>>> Jorn Vernee schreef op 2019-03-15 14:40:
>>>> I've already been using shell scripts mostly when running jextract
>>>> (except for simple examples). I find it very useful to be able to
>>>> split the command over multiple lines, especially long file paths
>>>> become much more readable.
>>>> 
>>>> I'll start working on this then.
>>>> 
>>>> Jorn
>>>> 
>>>> Maurizio Cimadamore schreef op 2019-03-15 14:21:
>>>> On 15/03/2019 13:15, Jorn Vernee wrote:
>>>> I still like this approach, and I think adding support for wildcard
>>>> patterns and/or header filters would make it better.
>>>> 
>>>> Like you said: It's dead simple. What you pass to jextract is what
>>>> you get. Though, we could still apply dependency analysis, which
>>>> would make sure nothing that's needed gets dropped.
>>>> 
>>>> Why don't we try this then?
>>>> 
>>>> Note that in javac we often use this trick:
>>>> 
>>>> javac `find <path> -name *.java`
>>>> 
>>>> which works
>>>> 
>>>> also, note that jextract also accepts a file with the @ syntax, etc.
>>>> 
>>>> 
>>>> jextract @args.txt
>>>> 
>>>> where args.txt is the command line (which could list all the headers
>>>> you want!).
>>>> 
>>>> Maybe this is indeed the simpler approach.
>>>> 
>>>> Maurizio


More information about the panama-dev mailing list