Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
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
381 changes: 1 addition & 380 deletions ddprof-lib/src/main/cpp/flightRecorder.cpp

Large diffs are not rendered by default.

116 changes: 1 addition & 115 deletions ddprof-lib/src/main/cpp/flightRecorder.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "frame.h"
#include "jfrMetadata.h"
#include "log.h"
#include "methodInfo.h"
#include "mutex.h"
#include "objectSampler.h"
#include "threadFilter.h"
Expand Down Expand Up @@ -55,92 +56,6 @@ struct CpuTimes {
CpuTime proc;
CpuTime total;
};

class SharedLineNumberTable {
public:
int _size;
void *_ptr;

SharedLineNumberTable(int size, void *ptr) : _size(size), _ptr(ptr) {}
~SharedLineNumberTable();
};

class MethodInfo {
public:
MethodInfo()
: _mark(false), _is_entry(false), _referenced(false), _age(0), _key(0), _class(0),
_name(0), _sig(0), _modifiers(0), _line_number_table(nullptr), _type() {}

bool _mark;
bool _is_entry;
bool _referenced; // Tracked during writeStackTraces() for cleanup
int _age; // Consecutive chunks without reference (0 = recently used)
u32 _key;
u32 _class;
u32 _name;
u32 _sig;
jint _modifiers;
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);
}
};

// MethodMap's key can be derived from 3 sources:
// 1) jmethodID for Java methods
// 2) void* address for native method names
// 3) Encoded RemoteFrameInfo
// The values of the keys are potentially overlapping, so we use
// the highest 2 bits to distinguish them.
// 00 - jmethodID
// 10 - void* address
// 01 - RemoteFrameInfo
class MethodMap : public std::map<unsigned long, MethodInfo> {
public:
static constexpr unsigned long ADDRESS_MARK = 0x8000000000000000ULL;
static constexpr unsigned long REMOTE_FRAME_MARK = 0x4000000000000000ULL;
static constexpr unsigned long KEY_TYPE_MASK = ADDRESS_MARK | REMOTE_FRAME_MARK;

MethodMap() {}

static unsigned long makeKey(jmethodID method) {
unsigned long key = (unsigned long)method;
assert((key & KEY_TYPE_MASK) == 0);
return key;
}

static unsigned long makeKey(const char* addr) {
unsigned long key = (unsigned long)addr;
assert((key & KEY_TYPE_MASK) == 0);
return (key | ADDRESS_MARK);
}

static unsigned long makeKey(unsigned long packed_remote_frame) {
unsigned long key = packed_remote_frame;
assert((key & KEY_TYPE_MASK) == 0);
return (key | REMOTE_FRAME_MARK);}
};

class Recording {
friend ObjectSampler;
friend Profiler;
Expand Down Expand Up @@ -297,35 +212,6 @@ class Recording {
private:
void cleanupUnreferencedMethods();
};

class Lookup {
public:
Recording *_rec;
MethodMap *_method_map;
Dictionary *_classes;
Dictionary _packages;
Dictionary _symbols;

private:
void fillNativeMethodInfo(MethodInfo *mi, const char *name,
const char *lib_name);
void fillRemoteFrameInfo(MethodInfo *mi, const RemoteFrameInfo *rfi);
void cutArguments(char *func);
void fillJavaMethodInfo(MethodInfo *mi, jmethodID method, bool first_time);
bool has_prefix(const char *str, const char *prefix) const {
return strncmp(str, prefix, strlen(prefix)) == 0;
}

public:
Lookup(Recording *rec, MethodMap *method_map, Dictionary *classes)
: _rec(rec), _method_map(method_map), _classes(classes), _packages(),
_symbols() {}

MethodInfo *resolveMethod(ASGCT_CallFrame &frame);
u32 getPackage(const char *class_name);
u32 getSymbol(const char *name);
};

class FlightRecorder {
friend Profiler;

Expand Down
7 changes: 6 additions & 1 deletion 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,12 +13,14 @@ 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_INTERPRETED_METHOD = 8,
FRAME_TYPE_MAX = FRAME_INTERPRETED_METHOD // Maximum valid frame type
};

class FrameType {
public:
static inline int encode(int type, int bci) {
assert((type != FRAME_INTERPRETED_METHOD || VM::isHotspot()) && "FRAME_INTERPRETED_METHOD is only valid for hotspot");
return (1 << 24) | (type << 25) | (bci & 0xffffff);
}

Expand Down
19 changes: 19 additions & 0 deletions ddprof-lib/src/main/cpp/hotspot/classloader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/*
* Copyright The async-profiler authors
* Copyright 2026, Datadog, Inc.
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef _HOTSPOT_CLASSLOADER_H
#define _HOTSPOT_CLASSLOADER_H

#include "hotspot/vmStructs.h"

class VMClassLoader {
public:
// Is the method belongs to a class that is loaded by bootstrap class loader
static inline bool isLoadedByBootstrapClassLoader(const VMMethod* method);
};

#endif // _HOTSPOT_CLASSLOADER_H

38 changes: 38 additions & 0 deletions ddprof-lib/src/main/cpp/hotspot/classloader.inline.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright The async-profiler authors
* Copyright 2026, Datadog, Inc.
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef _HOTSPOT_CLASSLOADER_INLINE_H
#define _HOTSPOT_CLASSLOADER_INLINE_H

#include "hotspot/classloader.h"

#include <cassert>

bool VMClassLoader::isLoadedByBootstrapClassLoader(const VMMethod* method) {
if (method == nullptr) {
return false;
}

VMKlass* method_klass = method->methodHolderSafe();
if (method_klass == nullptr) {
return false;
}

VMClassLoaderData* cld = method_klass->classLoaderDataSafe();
if (cld == nullptr) {
return false;
}

// java/lang/Object must be loaded by bootstrap class loader
VMKlass* obj_klass = VMClasses::obj_klass();
assert(obj_klass != nullptr && "VMClasses not yet initialized");
assert(obj_klass->classLoaderData() != nullptr && "Object class has no class loader data");

return cld == obj_klass->classLoaderData();
}

#endif // _HOTSPOT_CLASSLOADER_INLINE_H

Loading
Loading