-
Bug
-
Resolution: Fixed
-
P2
-
23
-
b02
-
generic
-
generic
Issue | Fix Version | Assignee | Priority | Status | Resolution | Resolved In Build |
---|---|---|---|---|---|---|
JDK-8333894 | 23 | Volker Simonis | P2 | Resolved | Fixed | b27 |
JDK-8333877 | na | Volker Simonis | P2 | Closed | Not an Issue |
`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.
```
// 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 [
```
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.
- backported by
-
JDK-8333894 Fix CompilerDirectives for non-compiler JVM variants
- Resolved
-
JDK-8333877 Fix CompilerDirectives for non-compiler JVM variants
- Closed
- relates to
-
JDK-8329421 Native methods can not be selectively printed
- Resolved
- links to
-
Commit openjdk/jdk/5f9d3e3a
-
Commit openjdk/jdk/fdbc2b24
-
Review openjdk/jdk/19578
-
Review openjdk/jdk/19622
(2 links to)