RFR: 8159370: Add FlagGuard for easier modification of flags for unit tests

Erik Helin erik.helin at oracle.com
Tue Jun 21 14:27:28 UTC 2016


On 2016-06-17, Kim Barrett wrote:
> > On Jun 17, 2016, at 11:31 AM, Erik Helin <erik.helin at oracle.com> wrote:
> > 
> > On 2016-06-14, Kim Barrett wrote:
> >>> On Jun 14, 2016, at 6:58 AM, Erik Helin <erik.helin at oracle.com> wrote:
> >>> 
> >>> Hi all,
> >>> 
> >>> this patch adds a small utility class that makes it easier for TEST_VM
> >>> unit tests to safely modify flags. The class FlagGuard will store the
> >>> value of the flag in its constructor and then restore the flag in its
> >>> destructor. This is similar IntFlagSetting, UIntFlagSetting etc, but the
> >>> FlagGuard differs in two aspects:
> >>> - it does not set a new value
> >>> - it is "untyped", you can use FlagGuard for flags with any type
> >> 
> >> Is there a reason why this is being added to the unit test framework,
> >> rather than being a generalization of the existing [U]IntFlagSetting
> >> &etc and placed nearby?  That’s where I would expect to find it.
> > 
> > So my reasoning was that the FlagGuard was pretty slow, since it used
> > Flag::find_flag, so I didn't want to encourage anyone to use it in
> > production. Me and Per hacked together a new implementation of
> > FlagGuard, which uses templates and memcpy instead of Flag::find_flag:
> > 
> > http://cr.openjdk.java.net/~ehelin/8159370/00/
> 
> That's the old URL; the correct URL ends in /01/

Thanks for correcting the URL. New patches are located at:
- incremental: http://cr.openjdk.java.net/~ehelin/8159370/01-02/
- full: http://cr.openjdk.java.net/~ehelin/8159370/02/

(tested in JRPT)

Please see my comments inline.

> > What do you think? I also moved FlagGuard to runtime/globals.hpp and
> > added some tests. I don't want to update [U]IntFlagSetting since
> > they also take a new value as parameter, FlagGuard just restores the
> > value at the end of the scope.
> 
> ------------------------------------------------------------------------------
> For reference, the technique used here is based on C++2003 3.9/2.
> 
> The basic idea seems sound, though I have quibbles about details.
> 
> I'm fine with this interface and leaving [U]IntFlagSetting alone.

Thanks!

> Given that we have a fixed set of types to deal with, I suspect there
> is some tag dispatching / sizeof trick that could eliminate the memcpy
> and use the actual option type, but it hardly seems worth the trouble.
> 
> There are much cleaner solutions with C++11...
> 
> ------------------------------------------------------------------------------  
> src/share/vm/runtime/globals.hpp 
>  469   uint8_t _value[SIZE];
> 
> Element type should be char or unsigned char.  uint8_t is not
> necessarily either of those, though it likely is on any platform we
> support.

Ok, I changed _value to be unsigned char.

> ------------------------------------------------------------------------------   
> src/share/vm/runtime/globals.hpp 
>  475   void* operator new(size_t size) throw() {
>  476     return 0;
>  477   }
>  478 
>  479   void* operator new [](size_t size) throw() {
>  480     return 0;
>  481   }
> 
> Leave off the definitions, further ensuring they can't be used, and
> not being misleading about them.

Agree, fixed.

> ------------------------------------------------------------------------------ 
> src/share/vm/runtime/globals.hpp 
>  470   const uintptr_t _addr;
>  484   FlagGuard(uintptr_t flag_addr) : _addr(flag_addr) {
>  493 #define FLAG_GUARD(f) FlagGuard<sizeof(f)> f ## _guard((uintptr_t) &f)
> 
> Why the address conversion to uintptr_t?  Why not just use const void*,
> and eliminate lots of casts...

Agree, changed to void*.

> ------------------------------------------------------------------------------  
> src/share/vm/runtime/globals.hpp 
>  485     memcpy((void*) _value, (const void*) _addr, SIZE);
>  489     memcpy((void*) _addr, (const void*) _value, SIZE);
> 
> Unnecessary casts of _value.

Fixed.

> ------------------------------------------------------------------------------  
> test/native/runtime/test_globals.cpp 
> 
> This file only contains tests for FlagGuard.  I don't know what
> conventions we're adopting for native tests, and what restrictions the
> build system might be imposing on us.  It seems to me though that this
> might be better called test_FlagGuard, and other native tests of
> facilities in globals.hpp would be in other file(s).

I would like to start by using one test_ file per source file until we
have more experience with the unit tests. If we then find that it is
better to use multiple test_ files for one source files, then I'll be
happy to move the FlagGuard tests into its own file.

> ------------------------------------------------------------------------------ 
> test/native/runtime/test_globals.cpp 
> 
> I think each test should also contain a check that the flag is of the
> expected type, e.g. at the beginning something like
> 
>   ASSERT(Flag::find_flag("AlwaysActAsServerClassMachine")->is_bool());
> 
> Otherwise, a change in the type of an option could accidently result
> in an untested case here.

Agree, fixed.

> ------------------------------------------------------------------------------  
> test/native/runtime/test_globals.cpp 
> 
> The code here is extreme boilerplate.  Consider a macro to reduce
> that?

Yep, agree. What do you think of the macro?

> ------------------------------------------------------------------------------  
> test/native/runtime/test_globals.cpp 
>  102   const char* original_value = PerfDataSaveFile;
> 
> For consistency, I think that should be ccstr rather than const char*.

Agree, fixed.

Thanks,
Erik


More information about the hotspot-dev mailing list