Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
5f5fa35
Don't preload jmethodIDs when cstack=vm with hotspot JVM
zhengyu123 May 27, 2026
4e3bf98
v1
zhengyu123 May 27, 2026
957d27c
v2
zhengyu123 May 28, 2026
14728a7
v3
zhengyu123 May 31, 2026
64e183b
Clean up
zhengyu123 Jun 1, 2026
c782c3c
Fix
zhengyu123 Jun 1, 2026
c462d85
Add application/platform class loader support
zhengyu123 Jun 1, 2026
7710c6f
Fix
zhengyu123 Jun 1, 2026
6c6f1a7
Fix
zhengyu123 Jun 1, 2026
07c3a4c
Harden symbolAt()
zhengyu123 Jun 1, 2026
4827c68
Merge branch 'main' into hs_jmethod_id
zhengyu123 Jun 2, 2026
3dda4e3
force_jmethodID argument
zhengyu123 Jun 2, 2026
a826e7e
Consolidate JVM initialization
zhengyu123 Jun 2, 2026
9d1818a
Cleanup: fixed typo and etc.
zhengyu123 Jun 2, 2026
13349c3
Remove dead code
zhengyu123 Jun 2, 2026
06b1a92
Fix
zhengyu123 Jun 2, 2026
b95c88c
Fix
zhengyu123 Jun 2, 2026
df5e992
Fix
zhengyu123 Jun 2, 2026
c26aeea
Handle hidden classes
zhengyu123 Jun 2, 2026
b2a9a1d
Review comments
zhengyu123 Jun 3, 2026
b56c6b4
Clean up
zhengyu123 Jun 3, 2026
7567904
Review comments
zhengyu123 Jun 4, 2026
79adaea
Correct comment
zhengyu123 Jun 4, 2026
4702a62
Merge branch 'main' into hs_jmethod_id
zhengyu123 Jun 5, 2026
4d6724c
Merge branch 'main' into hs_jmethod_id
jbachorik Jun 8, 2026
39149af
Review comments
zhengyu123 Jun 9, 2026
ed1c047
Fix default value
zhengyu123 Jun 9, 2026
b5a898f
Code review comments
zhengyu123 Jun 10, 2026
1ef3b88
More review comments
zhengyu123 Jun 11, 2026
f7fe9bf
Deal with <cinit>
zhengyu123 Jun 12, 2026
aa92b9b
add test
zhengyu123 Jun 12, 2026
b8a3e09
Fix
zhengyu123 Jun 12, 2026
396fec6
Postponding jmethodID loading decision till execution
zhengyu123 Jun 12, 2026
bb03bac
Fix jdk8 patching
zhengyu123 Jun 12, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions ddprof-lib/src/main/cpp/arguments.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,11 @@ Error Arguments::parse(const char *args) {
msg = "jstackdepth must be > 0";
}

CASE("fjmethodid")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it unintuitive/confusing that in order to turn the new feature on, we have to set the flag to false.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like to name, what do you suggest?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah I don't know either, it seems hard. I could only come up with dont-preload-methodIds or no-preload-methodIds, but it doesn't seem very much better. I leave that up to you.

if (value != nullptr && strcmp(value, "false") == 0) {
_force_jmethodID = false;
}

CASE("safemode")
_safe_mode = value == NULL ? INT_MAX : (int)strtol(value, NULL, 0);

Expand Down
4 changes: 3 additions & 1 deletion ddprof-lib/src/main/cpp/arguments.h
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,7 @@ class Arguments {
bool _enable_method_cleanup;
bool _remote_symbolication; // Enable remote symbolication for native frames
bool _jvmtistacks; // Delegate CPU/wall stack walks to HotSpot JFR RequestStackTrace extension
bool _force_jmethodID; // Load all jmethodIDs, true by default

Arguments(bool persistent = false)
: _buf(NULL),
Expand Down Expand Up @@ -229,7 +230,8 @@ class Arguments {
_lightweight(false),
_enable_method_cleanup(true),
_remote_symbolication(false),
_jvmtistacks(false) {}
_jvmtistacks(false),
_force_jmethodID(false) {}

~Arguments();

Expand Down
23 changes: 14 additions & 9 deletions ddprof-lib/src/main/cpp/flightRecorder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,11 @@
#include "context_api.h"
#include "counters.h"
#include "dictionary.h"
#include "flightRecorder.h"
#include "flightRecorder.inline.h"
#include "incbin.h"
#include "jfrMetadata.h"
#include "jniHelper.h"
#include "jvmSupport.inline.h"
#include "os.h"
#include "profiler.h"
#include "signalSafety.h"
Expand Down Expand Up @@ -485,8 +486,12 @@ MethodInfo *Lookup::resolveMethod(ASGCT_CallFrame &frame) {
static const char* UNKNOWN = "unknown";
unsigned long key;
jint bci = frame.bci;
jmethodID method_id = frame.method_id;

jmethodID method = frame.method_id;
// Resolve native method
if (FrameType::isRawPointer(bci)) {
method_id = JVMSupport::resolve(frame.method);
Comment thread
zhengyu123 marked this conversation as resolved.
}

// BCI_VTABLE_RECEIVER: method holds a VMSymbol* (see vmEntry.h). Resolve
// to a class_id via the per-dump cache once, then key MethodMap by the
Expand All @@ -495,10 +500,10 @@ MethodInfo *Lookup::resolveMethod(ASGCT_CallFrame &frame) {
// row.
u32 vtable_class_id = 0;
if (bci == BCI_VTABLE_RECEIVER) {
vtable_class_id = resolveVTableReceiverCached((void *)method);
vtable_class_id = resolveVTableReceiverCached((void *)method_id);
}

if (method == nullptr) {
if (method_id == nullptr) {
key = MethodMap::makeKey(UNKNOWN);
} else if (bci == BCI_ERROR || bci == BCI_NATIVE_FRAME) {
key = MethodMap::makeKey(frame.native_function_name);
Expand All @@ -511,7 +516,7 @@ MethodInfo *Lookup::resolveMethod(ASGCT_CallFrame &frame) {
assert(frame_type == FRAME_INTERPRETED || frame_type == FRAME_JIT_COMPILED ||
frame_type == FRAME_INLINED || frame_type == FRAME_C1_COMPILED ||
VM::isOpenJ9()); // OpenJ9 may have bugs that produce invalid frame types
key = MethodMap::makeKey(method);
key = MethodMap::makeKey(method_id);
}

MethodInfo *mi = &(*_method_map)[key];
Expand All @@ -522,12 +527,12 @@ MethodInfo *Lookup::resolveMethod(ASGCT_CallFrame &frame) {
if (first_time) {
mi->_key = _method_map->size() + 1; // avoid zero key
}
if (method == nullptr) {
if (method_id == nullptr) {
fillNativeMethodInfo(mi, UNKNOWN, nullptr);
} else if (bci == BCI_ERROR) {
fillNativeMethodInfo(mi, (const char *)method, nullptr);
fillNativeMethodInfo(mi, (const char *)method_id, nullptr);
} else if (bci == BCI_NATIVE_FRAME) {
const char *name = (const char *)method;
const char *name = (const char *)method_id;
fillNativeMethodInfo(mi, name,
Profiler::instance()->getLibraryName(name));
} else if (bci == BCI_NATIVE_FRAME_REMOTE) {
Expand Down Expand Up @@ -575,7 +580,7 @@ MethodInfo *Lookup::resolveMethod(ASGCT_CallFrame &frame) {
mi->_type = FRAME_NATIVE;
mi->_is_entry = false;
} else {
fillJavaMethodInfo(mi, method, first_time);
fillJavaMethodInfo(mi, method_id, first_time);
}
}

Expand Down
23 changes: 2 additions & 21 deletions ddprof-lib/src/main/cpp/flightRecorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,27 +90,8 @@ class MethodInfo {
std::shared_ptr<SharedLineNumberTable> _line_number_table;
FrameTypeId _type;

jint getLineNumber(jint bci) {
// if the shared pointer is not pointing to the line number table, consider
// size 0
if (!_line_number_table || _line_number_table->_size == 0) {
return 0;
}

int i = 1;
while (i < _line_number_table->_size &&
bci >= ((jvmtiLineNumberEntry *)_line_number_table->_ptr)[i]
.start_location) {
i++;
}
return ((jvmtiLineNumberEntry *)_line_number_table->_ptr)[i - 1]
.line_number;
}

bool isHidden() {
// 0x1400 = ACC_SYNTHETIC(0x1000) | ACC_BRIDGE(0x0040)
return _modifiers == 0 || (_modifiers & 0x1040);
}
inline jint getLineNumber(jint bci);
inline bool isHidden();
};

// MethodMap's key can be derived from 3 sources:
Expand Down
31 changes: 31 additions & 0 deletions ddprof-lib/src/main/cpp/flightRecorder.inline.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/*
* Copyright The async-profiler authors
* Copyright 2026, Datadog, Inc.
* SPDX-License-Identifier: Apache-2.0
*/

#include "flightRecorder.h"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

leading space


#include "jvmSupport.inline.h"


jint MethodInfo::getLineNumber(jint bci) {
// if the shared pointer is not pointing to the line number table, consider
// size 0
if (!_line_number_table || _line_number_table->_size == 0) {
return 0;
}

int i = 1;
while (i < _line_number_table->_size &&
bci >= ((jvmtiLineNumberEntry *)_line_number_table->_ptr)[i]
.start_location) {
i++;
}
return ((jvmtiLineNumberEntry *)_line_number_table->_ptr)[i - 1]
.line_number;
}

bool MethodInfo::isHidden() {
return JVMSupport::isHidden(_modifiers);
}
28 changes: 21 additions & 7 deletions ddprof-lib/src/main/cpp/frame.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
#ifndef _FRAME_H
#define _FRAME_H

#include <cassert>
#include "vmEntry.h"

enum FrameTypeId {
FRAME_INTERPRETED = 0,
FRAME_JIT_COMPILED = 1,
Expand All @@ -10,23 +13,34 @@ enum FrameTypeId {
FRAME_KERNEL = 5,
FRAME_C1_COMPILED = 6,
FRAME_NATIVE_REMOTE = 7, // Native frame with remote symbolication (build-id + pc-offset)
FRAME_TYPE_MAX = FRAME_NATIVE_REMOTE // Maximum valid frame type
FRAME_TYPE_MAX = FRAME_NATIVE_REMOTE, // Maximum valid frame type
FRAME_TYPE_MASK = 0x7
};

class FrameType {
// Maximu size of a single Java method is 64KB of bytecode instructions
static constexpr int BCI_MASK = 0xffff;
static constexpr int TYPE_SHIFT = 21;
static constexpr int ENCODED_MASK = 1 << 20; // bit indicates that value is encoded
static constexpr int RAW_POINTER_MASK = 1 << 30;
Comment thread
zhengyu123 marked this conversation as resolved.
public:
static inline int encode(int type, int bci) {
return (1 << 24) | (type << 25) | (bci & 0xffffff);
static inline int encode(int type, int bci, bool rawPointer = false) {
assert((!rawPointer || VM::isHotspot()) && "Raw pointer is only valid for hotspot");
return ENCODED_MASK | (type << TYPE_SHIFT) | (bci & BCI_MASK) | (rawPointer ? RAW_POINTER_MASK : 0);
}

static inline FrameTypeId decode(int bci) {
if ((bci >> 24) <= 0) {
// Unencoded BCI (bit 24 not set) or negative special BCI values
if ((bci & ENCODED_MASK) == 0 || bci < 0) {
// Unencoded BCI (ENCODED_SHIFT bit not set) or negative special BCI values
return FRAME_JIT_COMPILED;
}

// Clamp to valid FrameTypeId range to defend against corrupted values
int raw_type = bci >> 25;
return (FrameTypeId)(raw_type <= FRAME_TYPE_MAX ? raw_type : FRAME_TYPE_MAX);
return (FrameTypeId)((bci >> TYPE_SHIFT) & FRAME_TYPE_MASK);
}

static inline bool isRawPointer(int bci) {
return bci > 0 && (bci & RAW_POINTER_MASK) != 0;
}
};

Expand Down
Loading