Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
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