JDK-8261556 : NMT: Sometimes we skip too many frames
  • Type: Enhancement
  • Component: hotspot
  • Sub-Component: runtime
  • Affected Version: 17
  • Priority: P4
  • Status: Resolved
  • Resolution: Cannot Reproduce
  • Submitted: 2021-02-11
  • Updated: 2022-06-24
  • Resolved: 2022-06-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other
tbdResolved
Related Reports
Relates :  
Relates :  
Description
JDK-8261302 introduced a change to NativeCallStack::NativeCallStack() which caused the call to os::get_native_stack() to not be a tail call anymore and hence the "guess-if-its-a-tail-call-or-not" logic was now wrong:

```
    // We need to skip the NativeCallStack::NativeCallStack frame if a tail call is NOT used
    // to call os::get_native_stack. A tail call is used if _NMT_NOINLINE_ is not defined
    // (which means this is not a slowdebug build), and we are on 64-bit (except Windows).
    // This is not necessarily a rule, but what has been obvserved to date.
#if (defined(_NMT_NOINLINE_) || defined(_WINDOWS) || !defined(_LP64) || defined(PPC64))
    // Not a tail call.
    toSkip++;
#if (defined(_NMT_NOINLINE_) && defined(BSD) && defined(_LP64))
    // Mac OS X slowdebug builds have this odd behavior where NativeCallStack::NativeCallStack
    // appears as two frames, so we need to skip an extra frame.
    toSkip++;
#endif // Special-case for BSD.
#endif // Not a tail call.
```

and we were seeing the NativeCallStack::NativeCallStack() frame in the output, not being skipped, which tripped off the associated jtreg test. JDK-8261520 tracks that issue.

However, what struck me as odd is that not every call stack shows this frame. Some do, some don't. But since the decision to skip frames depends on compile time settings, we either always or never skip. This means that before JDK-8261302, we sometimes skipped where we should not skip.

I looked at "good" NMT output. And yes, it seems that we sometimes skip too much.

Examples:

```
[0x00007f6a2439ab71] ModuleEntry::restore_growable_array(Array<ModuleEntry*>*)+0x41         
[0x00007f6a2441c99d] PackageEntryTable::load_archived_entries(Array<PackageEntry*>*)+0x4d   
[0x00007f6a23d59844] ClassLoaderDataShared::serialize(SerializeClosure*)+0xf4               
[0x00007f6a2436a5ea] MetaspaceShared::initialize_shared_spaces()+0x19a                      
                             (malloc=2KB type=Module #92)                                   
```

which really should be:

```
[0x00007fc69d73080e] ResourceObj::operator new(unsigned long, ResourceObj::allocation_type, MEMFLAGS)+0x16e
[0x00007fc69df5d9f1] ModuleEntry::restore_growable_array(Array<ModuleEntry*>*)+0x41
[0x00007fc69dfdf7ed] PackageEntryTable::load_archived_entries(Array<PackageEntry*>*)+0x4d
[0x00007fc69d91c844] ClassLoaderDataShared::serialize(SerializeClosure*)+0xf4
                             (malloc=2KB type=Module #92)
```

or:

```
[0x00007f6a244bc840] SafepointMechanism::initialize()+0x40
[0x00007f6a2469599f] Threads::create_vm(JavaVMInitArgs*, bool*)+0x17f      
[0x00007f6a240ad951] JNI_CreateJavaVM+0x51                                 
[0x00007f6a257ad611] JavaMain+0x91
```

missing the last frame, which is os::reserve_memory().



Comments
I don't seem to be able to reproduce this behavior anymore.
24-06-2022