[foreign] RFR 8219822: Jextract should handle complex macro constants

Maurizio Cimadamore maurizio.cimadamore at oracle.com
Wed Feb 27 19:02:38 UTC 2019


Hi,
this patch regularizes support for constant macros (and enum constants too).

http://cr.openjdk.java.net/~mcimadamore/panama/8219822_v2/

The goal of this patch is to stop having jextract generating 'default' 
methods for constants. Instead, two new annotations are introduced:

@NativeNumericConstant
@NativeStringConstant

The first takes a long value, the second a String value.

So, given C code like this:

#define FOO 1

instead of generating a method like this:

default int FOO() {
    return 1;
}

We will now generate this:

@NativeNumericConstant(1L)
int FOO();

And then binder will then generate the implementation.

Decoupling the generation of the constant methods from jextract has a 
big advantage: we can now support complex constant types, such as 
strings (which need to be turned to Pointer<Byte>) and pointer constants 
(e.g. (void*)0). Note that, whenever we need some 'constant' pointer, we 
need to allocate, which means we need a scope - which we don't have at 
extraction time.

Efficiency-wise, the binder-generated implementation should be as good 
as the jextract one - it just ldc a constant (which can even be a 
pointer constant, via CP patching!) and then returns it.

In order to support pointer constants of the kind:

#define PTR (void*)0

I also tweaked MacroParser, so that now two attempts can be made at 
evaluating the macro:

1) a first attempt is made using a snippet like this:

__auto_type jextract$var = PTR;

If this fails (and it does fail in this case, as clang cursor evaluation 
API doesn't detect this constant), then:

2) we look at the type of the cursor, if the type is a pointer type, 
then we trigger another snippet parse, this time of:

__auto_type jextract$var = (long)PTR;

The extra cast will effectively reinterpret the value as a numeric 
constant. Then we'll create a macro whose type is the pointer type 
determined at (1) and whose value is the one determined at (2).


Note that, since we only execute step (2) when the type of the cursor in 
(1) is a pointer type, we don't end up executing the second step very 
often. I also tried some of the examples, and the extraction time is the 
same as before this patch.


There is a slight issue with AsmCodeFactoryExt: ideally, we'd like for 
constant methods to be turned into static constants here; and we'd like 
to initialize such constants to the result of the computation of the 
bound constant method - that is, if the library has a method:

@NativeNumericConstant(1L)
int FOO();

Then, the static wrapper should have the following static field:

static final int FOO = lib.FOO();

However, if we do so, a test will fail, namely LibEnumTest, as that test 
uses the constants of the static wrapper as labels in a 'switch' 
statement; this only works if the constant field has the 'ConstantValue' 
attribute, and that in turn is only possible if the constant is 'simple' 
- using a condy-based ConstantValue would be a way out, but that is not 
something that is supported currently, neither by the VM nor by javac.

So we have a choice here:

1) we extract the value of the constant, and we create a plain constant 
field - e.g.

static final int FOO = 1;

which will then work as before (as a true compile-time constant)

2) we aim for regularity, and we just translate as

static final int FOO = lib.FOO();


The patch I've submitted does (1) for simple numeric constants and falls 
back to (2) for complex constants. I'm open to suggestions as to whether 
it's better to keep this behavior, or simplify it by always aiming for (2).

Maurizio






More information about the panama-dev mailing list