RFR: 8333722: Fix CompilerDirectevies for non-compiler JVM variants

Volker Simonis simonis at openjdk.org
Thu Jun 6 13:41:58 UTC 2024


`DirectivesStack::getMatchingDirective()` relies on the fact that the default directives set is always enabled. And that's indeed the case for normal builds with C1 and C2 compilers (see `DirectivesStack::init()` in `compilerDirectives.cpp`):


// Create a new dirstack and push a default directive
void DirectivesStack::init() {
  CompilerDirectives* _default_directives = new CompilerDirectives();
  char str[] = "*.*";
  const char* error_msg = nullptr;
  _default_directives->add_match(str, error_msg);
#if defined(COMPILER1) || INCLUDE_JVMCI
  _default_directives->_c1_store->EnableOption = true;
#endif
#ifdef COMPILER2
  if (CompilerConfig::is_c2_enabled()) {
    _default_directives->_c2_store->EnableOption = true;
  }
#endif
  assert(error_msg == nullptr, "Must succeed.");
  push(_default_directives);
}


However, if we're building a JVM configuration without compilers (e.g. `--with-jvm-variants=core`), this is not the case and `DirectivesStack::getMatchingDirective()` will return the base directive set without incrementing the reference count of its directive:


    CompilerDirectives* dir = _top;
    assert(dir != nullptr, "Must be initialized");

    while (dir != nullptr) {
      if (dir->is_default_directive() || dir->match(method)) {
        match = dir->get_for(comp);
        assert(match != nullptr, "Consistency");
        if (match->EnableOption) {
          // The directiveSet for this compile is also enabled -> success
          dir->inc_refcount();
          break;
        }
      }
      dir = dir->next();
    }
  }
  guarantee(match != nullptr, "There should always be a default directive that matches");

  // Check for legacy compile commands update, without DirectivesStack_lock
  return match->compilecommand_compatibility_init(method);


If this directive set will be released, it will delete the corresponding base directive and subsequent usages of the base directive will lead to a segmentation fault.

After [JDK-8329421: Native methods can not be selectively printed](https://bugs.openjdk.org/browse/JDK-8329421) which replaced the call to

DirectiveSet* directive = DirectivesStack::getDefaultDirective(CompileBroker::compiler(CompLevel_simple));

by

DirectiveSet* directive = DirectivesStack::getMatchingDirective(method, CompileBroker::compiler(CompLevel_simple));

in `sharedRuntime.cpp` this issue is now triggered at JVM startup for non-compiler configurations when native wrappers are generated (see https://github.com/openjdk/jdk/pull/18567#issuecomment-2149408243).

The fix is trivial. Just increment the reference count of a compiler directive in `DirectivesStack::getMatchingDirective()` if it is the base directive, even if it is not enabled.

-------------

Commit messages:
 - 8333722: Fix CompilerDirectevies for non-compiler JVM variants

Changes: https://git.openjdk.org/jdk/pull/19578/files
  Webrev: https://webrevs.openjdk.org/?repo=jdk&pr=19578&range=00
  Issue: https://bugs.openjdk.org/browse/JDK-8333722
  Stats: 1 line in 1 file changed: 0 ins; 0 del; 1 mod
  Patch: https://git.openjdk.org/jdk/pull/19578.diff
  Fetch: git fetch https://git.openjdk.org/jdk.git pull/19578/head:pull/19578

PR: https://git.openjdk.org/jdk/pull/19578


More information about the hotspot-compiler-dev mailing list