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
50 changes: 50 additions & 0 deletions ddprof-lib/src/main/cpp/compressedLinenumberStream.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include "compressedLinenumberStream.h"

CompressedLineNumberStream::CompressedLineNumberStream(unsigned char* buffer) :
_buffer(buffer), _position(0), _bci(0), _line(0) {
};

void CompressedLineNumberStream::reset() {
_position = 0;
_bci = 0;
_line = 0;
}

bool CompressedLineNumberStream::read_pair() {
unsigned char next = read_byte();
// Check for terminator
if (next == 0) return false;
if (next == 0xFF) {
// Escape character, regular compression used
_bci += read_signed_int();
_line += read_signed_int();
} else {
// Single byte compression used
_bci += next >> 3;
_line += next & 0x7;
}
return true;
}

uint32_t CompressedLineNumberStream::read_uint() {
const int pos = _position;
const uint32_t b_0 = (uint8_t)_buffer[pos]; //b_0 = a[0]
assert(b_0 >= X);
uint32_t sum = b_0 - X;
if (sum < L) { // common case
_position = pos + 1;
return sum;
}
// must collect more bytes: b[1]...b[4]
int lg_H_i = lg_H; // lg(H)*i == lg(H^^i)
for (int i = 1; ; i++) { // for i in [1..4]
const uint32_t b_i = (uint8_t) _buffer[pos + i]; //b_i = a[i]
assert(b_i >= X);
sum += (b_i - X) << lg_H_i; // sum += (b[i]-X)*(64^^i)
if (b_i < X+L || i == MAX_LENGTH-1) {
_position = pos + i + 1;
return sum;
}
lg_H_i += lg_H;
}
}
51 changes: 51 additions & 0 deletions ddprof-lib/src/main/cpp/compressedLinenumberStream.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#ifndef _COMPRESSED_LINENUMBER_STREAM_H
#define _COMPRESSED_LINENUMBER_STREAM_H

#include <cassert>
#include <cstdint>

/**
* Implementation of openjdk CompressedLineNumberStream
* https://github.com/openjdk/jdk/blob/master/src/hotspot/share/oops/method.hpp#L910
*
* Based on open jdk source:
* https://github.com/openjdk/jdk/blob/master/src/hotspot/share/code/compressedStream.hpp/cpp
* https://github.com/openjdk/jdk/blob/master/src/hotspot/share/utilities/unsigned5.hpp/cpp
*/

class CompressedLineNumberStream {
private:
// Math constants for the modified UNSIGNED5 coding of Pack200
static const int BitsPerByte = 8;
static const int lg_H = 6; // log-base-2 of H (lg 64 == 6)
static const int H = 1<<lg_H; // number of "high" bytes (64)
static const int X = 1 ; // there is one excluded byte ('\0')
static const int MAX_b = (1<<BitsPerByte)-1; // largest byte value
static const int L = (MAX_b+1)-X-H; // number of "low" bytes (191)
static const int MAX_LENGTH = 5; // lengths are in [1..5]
static const uint32_t MAX_VALUE = (uint32_t)-1; // 2^^32-1


unsigned char* _buffer;
int _position;

int _bci;
int _line;

public:
CompressedLineNumberStream(unsigned char* buffer);

bool read_pair();
void reset();

int bci() const { return _bci; }
int line() const { return _line; }

private:
unsigned char read_byte() { return _buffer[_position++]; }
static int decode_sign(uint32_t value) { return (value >> 1) ^ -(int)(value & 1); }
int read_signed_int() { return decode_sign(read_uint()); }
uint32_t read_uint();
};

#endif // _COMPRESSED_LINENUMBER_STREAM_H
9 changes: 9 additions & 0 deletions ddprof-lib/src/main/cpp/javaApi.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,6 +343,15 @@ Java_com_datadoghq_profiler_JavaProfiler_mallocArenaMax0(JNIEnv *env,
ddprof::OS::mallocArenaMax(maxArenas);
}

extern "C" DLLEXPORT void JNICALL
Java_com_datadoghq_profiler_JavaProfiler_populateClassloaders0(JNIEnv *env,
jclass platformClassLoader,
jclass applicationClassLoader) {
ddprof::PlatformClassLoader::set_platform_classloader(env, platformClassLoader);
ddprof::ApplicationClassLoader::set_application_classloader(env, applicationClassLoader);
}


extern "C" DLLEXPORT jstring JNICALL
Java_com_datadoghq_profiler_JVMAccess_findStringJVMFlag0(JNIEnv *env,
jobject unused,
Expand Down
4 changes: 4 additions & 0 deletions ddprof-lib/src/main/cpp/stackWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
#include "stackFrame.h"
#include "symbols.h"
#include "vmStructs.h"
#include "vmStructs_dd.h"


const uintptr_t SAME_STACK_DISTANCE = 8192;
Expand Down Expand Up @@ -370,6 +371,8 @@ __attribute__((no_sanitize("address"))) int StackWalker::walkVM(void* ucontext,

if (is_plausible_interpreter_frame) {
VMMethod* method = ((VMMethod**)fp)[InterpreterFrame::method_offset];
// assert(ddprof::BootstrapClassLoader::loaded_by(method));

jmethodID method_id = getMethodId(method);
if (method_id != NULL) {
const char* bytecode_start = method->bytecode();
Expand All @@ -386,6 +389,7 @@ __attribute__((no_sanitize("address"))) int StackWalker::walkVM(void* ucontext,

if (depth == 0) {
VMMethod* method = (VMMethod*)frame.method();
// assert(ddprof::BootstrapClassLoader::loaded_by(method));
jmethodID method_id = getMethodId(method);
if (method_id != NULL) {
fillFrame(frames[depth++], FRAME_INTERPRETED, 0, method_id);
Expand Down
6 changes: 5 additions & 1 deletion ddprof-lib/src/main/cpp/vmEntry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -537,7 +537,11 @@ void VM::loadAllMethodIDs(jvmtiEnv *jvmti, JNIEnv *jni) {
jclass *classes;
if (jvmti->GetLoadedClasses(&class_count, &classes) == 0) {
for (int i = 0; i < class_count; i++) {
loadMethodIDs(jvmti, jni, classes[i]);
jclass klass = classes[i];
// Only populates jmethodID for classes loaded by a unknown classloader
if (!ddprof::ClassLoader::loaded_by_known_classloader(jni, klass)) {
loadMethodIDs(jvmti, jni, classes[i]);
}
}
jvmti->Deallocate((unsigned char *)classes);
}
Expand Down
44 changes: 44 additions & 0 deletions ddprof-lib/src/main/cpp/vmStructs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

#include <pthread.h>
#include <unistd.h>
#include "compressedLinenumberStream.h"
#include "vmStructs.h"
#include "vmEntry.h"
#include "j9Ext.h"
Expand Down Expand Up @@ -66,6 +67,8 @@ int VMStructs::_method_code_offset = -1;
int VMStructs::_constmethod_constants_offset = -1;
int VMStructs::_constmethod_idnum_offset = -1;
int VMStructs::_constmethod_size = -1;
int VMStructs::_constmethod_flags_offset = -1;
int VMStructs::_constmethod_code_size = -1;;
int VMStructs::_pool_holder_offset = -1;
int VMStructs::_array_len_offset = 0;
int VMStructs::_array_data_offset = -1;
Expand Down Expand Up @@ -228,6 +231,10 @@ void VMStructs::initOffsets() {
_constmethod_constants_offset = *(int*)(entry + offset_offset);
} else if (strcmp(field, "_method_idnum") == 0) {
_constmethod_idnum_offset = *(int*)(entry + offset_offset);
} else if (strcmp(field, "_flags._flags") == 0) {
_constmethod_flags_offset = *(int*)(entry + offset_offset);
} else if (strcmp(field, "_code_size") == 0) {
_constmethod_code_size = *(int*)(entry + offset_offset);
}
} else if (strcmp(type, "ConstantPool") == 0) {
if (strcmp(field, "_pool_holder") == 0) {
Expand Down Expand Up @@ -686,6 +693,16 @@ jmethodID VMMethod::id() {
return NULL;
}

VMKlass* VMMethod::method_holder() {
// We may find a bogus NMethod during stack walking, it does not always point to a valid VMMethod
const char* const_method = (const char*) SafeAccess::load((void**) at(_method_constmethod_offset));
assert(goodPtr(const_method));
const char* cpool = (const char*) SafeAccess::load((void**)(const_method + _constmethod_constants_offset));
assert(goodPtr(cpool));
return *(VMKlass**)(cpool + _pool_holder_offset);
}


jmethodID VMMethod::validatedId() {
jmethodID method_id = id();
if (!_can_dereference_jmethod_id || (goodPtr(method_id) && *(VMMethod**)method_id == this)) {
Expand All @@ -694,6 +711,33 @@ jmethodID VMMethod::validatedId() {
return NULL;
}

bool VMConstMethod::get_linenumber_table(jint* entry_count_ptr,
jvmtiLineNumberEntry** table_ptr) {
if (!has_linenumber_table()) {
return false;
}
assert(entry_count_ptr != nullptr);
assert(table_ptr != nullptr);
unsigned char* table_start = code_base() + code_size();
int count = 0;
CompressedLineNumberStream stream(table_start);
while (stream.read_pair()) {
count++;
}

jvmtiLineNumberEntry* table = (jvmtiLineNumberEntry*)malloc(count * sizeof(jvmtiLineNumberEntry));
stream.reset();
count = 0;
while (stream.read_pair()) {
table[count].start_location = (jlocation)stream.bci();
table[count].line_number = (jint)stream.line();
}
*table_ptr = table;
*entry_count_ptr = count;

return true;
}

NMethod* CodeHeap::findNMethod(char* heap, const void* pc) {
unsigned char* heap_start = *(unsigned char**)(heap + _code_heap_memory_offset + _vs_low_offset);
unsigned char* segmap = *(unsigned char**)(heap + _code_heap_segmap_offset + _vs_low_offset);
Expand Down
33 changes: 33 additions & 0 deletions ddprof-lib/src/main/cpp/vmStructs.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ class VMStructs {
static int _constmethod_constants_offset;
static int _constmethod_idnum_offset;
static int _constmethod_size;
static int _constmethod_flags_offset;
static int _constmethod_code_size;
static int _pool_holder_offset;
static int _array_len_offset;
static int _array_data_offset;
Expand Down Expand Up @@ -413,6 +415,31 @@ class VMThread : VMStructs {
}
};

// constMethod
class VMConstMethod : VMStructs {
public:
bool has_linenumber_table() {
unsigned int flags = *(unsigned int*)at(_constmethod_flags_offset);
return (flags & 0x01) == 0x01;
}

unsigned short code_size() {
return *(unsigned short*)at(_constmethod_code_size);
}

int size() {
return *(int*)at(_constmethod_size);
}

bool get_linenumber_table(jint* entry_count_ptr, jvmtiLineNumberEntry** table_ptr);

private:
unsigned char* code_base() const {
return (unsigned char*)(this + 1);
}
};


class VMMethod : VMStructs {
public:
jmethodID id();
Expand All @@ -431,9 +458,15 @@ class VMMethod : VMStructs {
return *(const char**) at(_method_constmethod_offset) + _constmethod_size;
}

VMConstMethod* constMethod() {
return *(VMConstMethod**)at(_method_constmethod_offset);
}

NMethod* code() {
return *(NMethod**) at(_method_code_offset);
}

VMKlass* method_holder();
};

class NMethod : VMStructs {
Expand Down
13 changes: 11 additions & 2 deletions ddprof-lib/src/main/cpp/vmStructs_dd.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ namespace ddprof {
VMStructs_::MemoryUsageFunc VMStructs_::_memory_usage_func = NULL;
VMStructs_::GCHeapSummaryFunc VMStructs_::_gc_heap_summary_func = NULL;
VMStructs_::IsValidMethodFunc VMStructs_::_is_valid_method_func = NULL;

::VMKlass** BootstrapClassLoader::_object_klass_addr = nullptr;
::VMKlass* PlatformClassLoader::_class_loader = nullptr;
::VMKlass* ApplicationClassLoader::_class_loader = nullptr;

// Run at agent load time
void VMStructs_::init(CodeCache* libjvm) {
Expand Down Expand Up @@ -66,6 +68,13 @@ namespace ddprof {
break;
}

if (strcmp(type, "vmClasses") == 0) {
// java/lang/Object must be loaded by bootstrap class loader, we use it to locate
// its CLD
if (strcmp(field, "_klasses[static_cast<int>(vmClassID::Object_klass_knum)]") == 0) {
BootstrapClassLoader::set_object_klass_location(*(::VMKlass***)(entry + address_offset));
}
}
if (strcmp(type, "OSThread") == 0) {
if (strcmp(field, "_state") == 0) {
TEST_LOG("Setting _osthread_state_offset value");
Expand Down Expand Up @@ -395,4 +404,4 @@ namespace ddprof {
jvmti->Deallocate((unsigned char *)method_sig);
jvmti->Deallocate((unsigned char *)method_name);
}
}
}
Loading
Loading