on javac flags

Jonathan Gibbons jonathan.gibbons at oracle.com
Wed Sep 26 20:15:10 UTC 2018


Maurizio,

I think it would also be good to separate the storage from the API, to 
provide
concise usage within the javac codebase.

For example,
     sym.hasFlag(Flag.STATIC)
     sym.setFlag(Flag.PUBLIC)
     etc

as compared to
    (sym.flags() & STATIC) != 0
     sym.flags |= STATIC;

If you get the API right, maybe as a first step, it would then be easier 
to tweak
the implementation later on as needed.

-- Jon


On 09/26/2018 01:06 PM, Maurizio Cimadamore wrote:
> Hi Bernard,
> your solution is clever, but now a symbol has an array of N elements - 
> which makes it completely unfeasible from a memory footprint 
> perspective. Although maybe the core of what you are suggesting is - 
> just use a custom data structure, e.g. something like an immutable 
> bitset, so that we can share common combinations, etc.
>
> Maurizio
>
> On 26/09/18 20:26, B. Blaser wrote:
>> Hi Maurizio,
>>
>> On Wed, 26 Sep 2018 at 16:17, Maurizio Cimadamore
>> <maurizio.cimadamore at oracle.com> wrote:
>>> Hi,
>>> In javac we have a Flags class which is used to define a list of all 
>>> the
>>> flags that are used, both internally (i.e. javac private flags) and
>>> externally (i.e ACC_ flags). The assumption is that external flags are
>>> 16-bit wide, while internal flags are all values above 2^16 (_which can
>>> fit in a long_).
>>>
>>> There are several issues with the current handling of flags:
>>> [...]
>>> * checking presence/absence of flags is very tedious; we have many many
>>> occurrences (600+) of C-like code like:
>>>
>>> if ((sym.flags() & STATIC) == 0 && ...
>>>
>>> or
>>>
>>> (sym.flags() & (ABSTRACT|DEFAULT|PRIVATE)) == ABSTRACT) { ... }
>>>
>>> [...]
>>> Where does this leave us? I think with these optimizations the memory
>>> footprint should be relatively contained - we are essentially trading a
>>> 64-bit value (long flag) with a 64 bit pointer which might or might not
>>> point to a fresh new object (if not, no extra cost). Of course this all
>>> needed to be validated with some real world profiling/JMH benchmark, 
>>> but
>>> seems like a direction worth exploring.
>>>
>>> Thoughts?
>> I'm afraid that
>>
>> if (!sym.flags().contains(Flag.STATIC) && ...
>>
>> would be also tedious, somewhat slow and probably expensive in term of
>> memory usage...
>>
>> I guess I'd be more for something like:
>>
>> $ cat OnFlags.java
>> class OnFlags {
>>      static enum Flag {
>>          PUBLIC(0, 0x1), PRIVATE(1, 0x2), INTERNAL(2, 0x0);
>>
>>          int index;
>>          int mask; // maybe 'short' would be enough
>>
>>          Flag(int index, int mask) {
>>              this.index = index;
>>              this.mask = mask;
>>          }
>>      }
>>
>>      static class Symbol {
>>          boolean[] flags = new boolean[Flag.values().length];
>>      }
>>
>>      public static void main(String... args) {
>>          var sym = new Symbol();
>>          sym.flags[Flag.PUBLIC.index] = true;
>>          sym.flags[Flag.INTERNAL.index] = true;
>>
>>          int jvmFlags = 0;
>>          for (Flag f: Flag.values())
>>              if (sym.flags[f.index])
>>                  jvmFlags |= f.mask;
>>
>>          for (Flag f: Flag.values())
>>              System.out.println(f + ": " + sym.flags[f.index]);
>>
>>          System.out.println("jvm flags " + jvmFlags);
>>      }
>> }
>>
>> No difference between corresponding internal and external flags, so no
>> mapping would be necessary.
>>
>> Testing a flag would be as fast as simple without much extra memory 
>> cost:
>>
>> if (!sym.flags[Flag.STATIC.index] && ...
>>
>> Computing the jvm external flag would be also straightforward:
>>
>> int jvmFlags = 0;
>> for (Flag f: Flag.values())
>>      if (sym.flags[f.index])
>>          jvmFlags |= f.mask;
>>
>> Opinions?
>>
>> Bernard
>>
>>> Maurizio
>



More information about the compiler-dev mailing list