diff --git a/ddprof-lib/src/main/cpp/vmStructs.cpp b/ddprof-lib/src/main/cpp/vmStructs.cpp index 5cec56cc9..0aeb87bee 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.cpp +++ b/ddprof-lib/src/main/cpp/vmStructs.cpp @@ -13,10 +13,9 @@ #include "jvmHeap.h" #include "safeAccess.h" #include "spinLock.h" +#include "common.h" - -CodeCache* VMStructs::_libjvm = NULL; - +CodeCache* VMStructs::_libjvm = nullptr; bool VMStructs::_has_class_names = false; bool VMStructs::_has_method_structs = false; bool VMStructs::_has_compiler_structs = false; @@ -26,93 +25,53 @@ bool VMStructs::_has_native_thread_id = false; bool VMStructs::_can_dereference_jmethod_id = false; bool VMStructs::_compact_object_headers = false; -int VMStructs::_klass_name_offset = -1; -int VMStructs::_symbol_length_offset = -1; -int VMStructs::_symbol_length_and_refcount_offset = -1; -int VMStructs::_symbol_body_offset = -1; -int VMStructs::_oop_klass_offset = -1; -int VMStructs::_class_loader_data_offset = -1; -int VMStructs::_class_loader_data_next_offset = -1; -int VMStructs::_methods_offset = -1; -int VMStructs::_jmethod_ids_offset = -1; -int VMStructs::_thread_osthread_offset = -1; -int VMStructs::_thread_anchor_offset = -1; -int VMStructs::_thread_state_offset = -1; -int VMStructs::_thread_vframe_offset = -1; -int VMStructs::_thread_exception_offset = -1; -int VMStructs::_osthread_id_offset = -1; -int VMStructs::_call_wrapper_anchor_offset = -1; -int VMStructs::_comp_env_offset = -1; -int VMStructs::_comp_task_offset = -1; -int VMStructs::_comp_method_offset = -1; -int VMStructs::_anchor_sp_offset = -1; -int VMStructs::_anchor_pc_offset = -1; -int VMStructs::_anchor_fp_offset = -1; -int VMStructs::_blob_size_offset = -1; -int VMStructs::_frame_size_offset = -1; -int VMStructs::_frame_complete_offset = -1; -int VMStructs::_code_offset = -1; -int VMStructs::_data_offset = -1; -int VMStructs::_mutable_data_offset = -1; -int VMStructs::_relocation_size_offset = -1; -int VMStructs::_scopes_pcs_offset = -1; -int VMStructs::_scopes_data_offset = -1; -int VMStructs::_nmethod_name_offset = -1; -int VMStructs::_nmethod_method_offset = -1; -int VMStructs::_nmethod_entry_offset = -1; -int VMStructs::_nmethod_state_offset = -1; -int VMStructs::_nmethod_level_offset = -1; -int VMStructs::_nmethod_metadata_offset = -1; -int VMStructs::_nmethod_immutable_offset = -1; -int VMStructs::_method_constmethod_offset = -1; -int VMStructs::_method_code_offset = -1; -int VMStructs::_constmethod_constants_offset = -1; -int VMStructs::_constmethod_idnum_offset = -1; -int VMStructs::_pool_holder_offset = -1; -int VMStructs::_array_len_offset = 0; -int VMStructs::_array_data_offset = -1; -int VMStructs::_code_heap_memory_offset = -1; -int VMStructs::_code_heap_segmap_offset = -1; -int VMStructs::_code_heap_segment_shift = -1; -int VMStructs::_heap_block_used_offset = -1; -int VMStructs::_vs_low_bound_offset = -1; -int VMStructs::_vs_high_bound_offset = -1; -int VMStructs::_vs_low_offset = -1; -int VMStructs::_vs_high_offset = -1; -int VMStructs::_flag_name_offset = -1; -int VMStructs::_flag_addr_offset = -1; -int VMStructs::_flag_origin_offset = -1; -const char* VMStructs::_flags_addr = NULL; -int VMStructs::_flag_count = 0; char* VMStructs::_code_heap[3] = {}; const void* VMStructs::_code_heap_low = NO_MIN_ADDRESS; const void* VMStructs::_code_heap_high = NO_MAX_ADDRESS; -char** VMStructs::_code_heap_addr = NULL; -const void** VMStructs::_code_heap_low_addr = NULL; -const void** VMStructs::_code_heap_high_addr = NULL; -int* VMStructs::_klass_offset_addr = NULL; -char** VMStructs::_narrow_klass_base_addr = NULL; -char* VMStructs::_narrow_klass_base = NULL; -int* VMStructs::_narrow_klass_shift_addr = NULL; +char* VMStructs::_narrow_klass_base = nullptr; int VMStructs::_narrow_klass_shift = -1; -char** VMStructs::_collected_heap_addr = NULL; -int VMStructs::_region_start_offset = -1; -int VMStructs::_region_size_offset = -1; -int VMStructs::_markword_klass_shift = -1; -int VMStructs::_markword_monitor_value = -1; -int VMStructs::_entry_frame_call_wrapper_offset = -1; int VMStructs::_interpreter_frame_bcp_offset = 0; unsigned char VMStructs::_unsigned5_base = 0; -const void** VMStructs::_call_stub_return_addr = NULL; -const void* VMStructs::_call_stub_return = NULL; -const void* VMStructs::_interpreted_frame_valid_start = NULL; -const void* VMStructs::_interpreted_frame_valid_end = NULL; +const void* VMStructs::_call_stub_return = nullptr; +const void* VMStructs::_interpreted_frame_valid_start = nullptr; +const void* VMStructs::_interpreted_frame_valid_end = nullptr; + // Initialize type size to 0 -#define INIT_TYPE_SIZE(name, ...) uint64_t VMStructs::TYPE_SIZE_NAME(name) = 0; +#define INIT_TYPE_SIZE(name, names) uint64_t VMStructs::TYPE_SIZE_NAME(name) = 0; DECLARE_TYPES_DO(INIT_TYPE_SIZE) #undef INIT_TYPE_SIZE +#define offset_value -1 +#define address_value nullptr + +// Initialize field variables +// offset = -1 +// address = nullptr + +// Do nothing macro +#define DO_NOTHING(...) +#define INIT_OFFSET_OR_ADDRESS(var, field_type, names) \ + field_type VMStructs::var = field_type##_value; + +DECLARE_TYPE_FILED_DO(DO_NOTHING, INIT_OFFSET_OR_ADDRESS, INIT_OFFSET_OR_ADDRESS, DO_NOTHING) + +#undef INIT_OFFSET_OR_ADDRESS +#undef DO_NOTHING +#undef offset_value +#undef address_value + +// Initialize constant variables to -1 +#define INIT_INT_CONSTANT(type, field) \ + int VMStructs::_##type##_##field = -1; +#define INIT_LONG_CONSTANT(type, field) \ + long VMStructs::_##type##_##field = -1; + +DECLARE_INT_CONSTANTS_DO(INIT_INT_CONSTANT) +DECLARE_LONG_CONSTANTS_DO(INIT_LONG_CONSTANT) +#undef INIT_INT_CONSTANT +#undef INIT_LONG_CONSTANT + jfieldID VMStructs::_eetop; jfieldID VMStructs::_tid; @@ -125,8 +84,6 @@ VMStructs::LockFunc VMStructs::_lock_func; VMStructs::LockFunc VMStructs::_unlock_func; // Datadog-specific static variables -int VMStructs::_osthread_state_offset = -1; -int VMStructs::_flag_type_offset = -1; CodeCache VMStructs::_unsafe_to_walk("unwalkable code"); VMStructs::HeapUsageFunc VMStructs::_heap_usage_func = NULL; VMStructs::MemoryUsageFunc VMStructs::_memory_usage_func = NULL; @@ -161,259 +118,64 @@ void VMStructs::ready() { initThreadBridge(); } -bool initTypeSize(uint64_t& size, const char* type, uint64_t value, ...) { - va_list args; - va_start(args, value); - const char* match_type = nullptr; - bool found = false; - while ((match_type = va_arg(args, const char*)) != nullptr) { - if (strcmp(type, match_type) == 0) { - size = value; - found = true; - break; +bool matchAny(const char* target_name, const char** names) { + for (const char** name = names; *name != nullptr; name++) { + if (strcmp(target_name, *name) == 0) { + return true; } - } - - va_end(args); - return found; + } + return false; } -void VMStructs::initOffsets() { +void VMStructs::init_offsets_and_addresses() { uintptr_t entry = readSymbol("gHotSpotVMStructs"); uintptr_t stride = readSymbol("gHotSpotVMStructEntryArrayStride"); uintptr_t type_offset = readSymbol("gHotSpotVMStructEntryTypeNameOffset"); uintptr_t field_offset = readSymbol("gHotSpotVMStructEntryFieldNameOffset"); uintptr_t offset_offset = readSymbol("gHotSpotVMStructEntryOffsetOffset"); + uintptr_t isStatic_offset = readSymbol("gHotSpotVMStructEntryIsStaticOffset"); uintptr_t address_offset = readSymbol("gHotSpotVMStructEntryAddressOffset"); + bool isStatic; + + auto read_offset = [&]() -> int { + assert(!isStatic); + return *(int*)(entry + offset_offset); + }; + + auto read_address = [&]() -> address { + assert(isStatic); + return *(address*)(entry + address_offset); + }; if (entry != 0 && stride != 0) { for (;; entry += stride) { - const char* type = *(const char**)(entry + type_offset); - const char* field = *(const char**)(entry + field_offset); - if (type == NULL || field == NULL) { + const char* type_name = *(const char**)(entry + type_offset); + const char* field_name = *(const char**)(entry + field_offset); + isStatic = *(int32_t*)(entry + isStatic_offset) != 0; + + if (type_name == nullptr || field_name == nullptr) { break; } - - if (strcmp(type, "Klass") == 0) { - if (strcmp(field, "_name") == 0) { - _klass_name_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "Symbol") == 0) { - if (strcmp(field, "_length") == 0) { - _symbol_length_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_length_and_refcount") == 0) { - _symbol_length_and_refcount_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_body") == 0) { - _symbol_body_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "oopDesc") == 0) { - if (strcmp(field, "_metadata._klass") == 0) { - _oop_klass_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "Universe") == 0 || strcmp(type, "CompressedKlassPointers") == 0) { - if (strcmp(field, "_narrow_klass._base") == 0 || strcmp(field, "_base") == 0) { - _narrow_klass_base_addr = *(char***)(entry + address_offset); - } else if (strcmp(field, "_narrow_klass._shift") == 0 || strcmp(field, "_shift") == 0) { - _narrow_klass_shift_addr = *(int**)(entry + address_offset); - } else if (strcmp(field, "_collectedHeap") == 0) { - _collected_heap_addr = *(char***)(entry + address_offset); - } - } else if (strcmp(type, "MemRegion") == 0) { - if (strcmp(field, "_start") == 0) { - _region_start_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_word_size") == 0) { - _region_size_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CompiledMethod") == 0 || strcmp(type, "nmethod") == 0) { - if (strcmp(field, "_method") == 0) { - _nmethod_method_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_verified_entry_offset") == 0) { - _nmethod_entry_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_verified_entry_point") == 0) { - _nmethod_entry_offset = - *(int*)(entry + offset_offset); - } else if (strcmp(field, "_state") == 0) { - _nmethod_state_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_comp_level") == 0) { - _nmethod_level_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_metadata_offset") == 0) { - _nmethod_metadata_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_immutable_data") == 0) { - _nmethod_immutable_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_scopes_pcs_offset") == 0) { - _scopes_pcs_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_scopes_data_offset") == 0) { - _scopes_data_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_scopes_data_begin") == 0) { - _scopes_data_offset = - *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "Method") == 0) { - if (strcmp(field, "_constMethod") == 0) { - _method_constmethod_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_code") == 0) { - _method_code_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ConstMethod") == 0) { - if (strcmp(field, "_constants") == 0) { - _constmethod_constants_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_method_idnum") == 0) { - _constmethod_idnum_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ConstantPool") == 0) { - if (strcmp(field, "_pool_holder") == 0) { - _pool_holder_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "InstanceKlass") == 0) { - if (strcmp(field, "_class_loader_data") == 0) { - _class_loader_data_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_methods") == 0) { - _methods_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_methods_jmethod_ids") == 0) { - _jmethod_ids_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ClassLoaderData") == 0) { - if (strcmp(field, "_next") == 0) { - _class_loader_data_next_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "java_lang_Class") == 0) { - if (strcmp(field, "_klass_offset") == 0) { - _klass_offset_addr = *(int**)(entry + address_offset); - } - } else if (strcmp(type, "Thread") == 0) { - // Since JDK 25, _osthread field belongs to Thread rather than JavaThread - if (strcmp(field, "_osthread") == 0) { - _thread_osthread_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "JavaThread") == 0) { - if (strcmp(field, "_osthread") == 0) { - _thread_osthread_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_anchor") == 0) { - _thread_anchor_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_thread_state") == 0) { - _thread_state_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_vframe_array_head") == 0) { - _thread_vframe_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ThreadShadow") == 0) { - if (strcmp(field, "_exception_file") == 0) { - _thread_exception_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "OSThread") == 0) { - if (strcmp(field, "_thread_id") == 0) { - _osthread_id_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_state") == 0) { - _osthread_state_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CompilerThread") == 0) { - if (strcmp(field, "_env") == 0) { - _comp_env_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "ciEnv") == 0) { - if (strcmp(field, "_task") == 0) { - _comp_task_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CompileTask") == 0) { - if (strcmp(field, "_method") == 0) { - _comp_method_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "JavaCallWrapper") == 0) { - if (strcmp(field, "_anchor") == 0) { - _call_wrapper_anchor_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "JavaFrameAnchor") == 0) { - if (strcmp(field, "_last_Java_sp") == 0) { - _anchor_sp_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_last_Java_pc") == 0) { - _anchor_pc_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_last_Java_fp") == 0) { - _anchor_fp_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CodeBlob") == 0) { - if (strcmp(field, "_size") == 0) { - _blob_size_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_frame_size") == 0) { - _frame_size_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_frame_complete_offset") == 0) { - _frame_complete_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_code_offset") == 0) { - _code_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_code_begin") == 0) { - _code_offset = - *(int*)(entry + offset_offset); - } else if (strcmp(field, "_data_offset") == 0) { - _data_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_mutable_data") == 0) { - _mutable_data_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_relocation_size") == 0) { - _relocation_size_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_name") == 0) { - _nmethod_name_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "CodeCache") == 0) { - if (strcmp(field, "_heap") == 0) { - _code_heap_addr = *(char***)(entry + address_offset); - } else if (strcmp(field, "_heaps") == 0) { - _code_heap_addr = *(char***)(entry + address_offset); - } else if (strcmp(field, "_low_bound") == 0) { - _code_heap_low_addr = *(const void***)(entry + address_offset); - } else if (strcmp(field, "_high_bound") == 0) { - _code_heap_high_addr = *(const void***)(entry + address_offset); - } - } else if (strcmp(type, "CodeHeap") == 0) { - if (strcmp(field, "_memory") == 0) { - _code_heap_memory_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_segmap") == 0) { - _code_heap_segmap_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_log2_segment_size") == 0) { - _code_heap_segment_shift = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "HeapBlock::Header") == 0) { - if (strcmp(field, "_used") == 0) { - _heap_block_used_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "VirtualSpace") == 0) { - if (strcmp(field, "_low_boundary") == 0) { - _vs_low_bound_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_high_boundary") == 0) { - _vs_high_bound_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_low") == 0) { - _vs_low_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_high") == 0) { - _vs_high_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "StubRoutines") == 0) { - if (strcmp(field, "_call_stub_return_address") == 0) { - _call_stub_return_addr = *(const void***)(entry + address_offset); - } - } else if (strcmp(type, "GrowableArrayBase") == 0 || strcmp(type, "GenericGrowableArray") == 0) { - if (strcmp(field, "_len") == 0) { - _array_len_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "GrowableArray") == 0) { - if (strcmp(field, "_data") == 0) { - _array_data_offset = *(int*)(entry + offset_offset); - } - } else if (strcmp(type, "JVMFlag") == 0 || strcmp(type, "Flag") == 0) { - if (strcmp(field, "_name") == 0 || strcmp(field, "name") == 0) { - _flag_name_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_addr") == 0 || strcmp(field, "addr") == 0) { - _flag_addr_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "_flags") == 0 || strcmp(field, "origin") == 0) { - _flag_origin_offset = *(int*)(entry + offset_offset); - } else if (strcmp(field, "flags") == 0) { - _flags_addr = **(char***)(entry + address_offset); - } else if (strcmp(field, "numFlags") == 0) { - _flag_count = **(int**)(entry + address_offset); - } else if (strcmp(field, "_type") == 0 || strcmp(field, "type") == 0) { - _flag_type_offset = *(int *)(entry + offset_offset); - } - } else if (strcmp(type, "PcDesc") == 0) { - // TODO - } +#define MATCH_TYPE_NAMES(type, type_names) \ + if (matchAny(type_name, type_names)) { +#define READ_FIELD_VALUE(var, field_type, field_names) \ + if (matchAny(field_name, field_names)) { \ + var = read_##field_type(); \ + continue; \ + } +#define END_TYPE() continue; } + DECLARE_TYPE_FILED_DO(MATCH_TYPE_NAMES, READ_FIELD_VALUE, READ_FIELD_VALUE, END_TYPE) +#undef MATCH_TYPE_NAMES +#undef READ_FIELD_VALUE +#undef END_TYPE } } +} - entry = readSymbol("gHotSpotVMTypes"); - stride = readSymbol("gHotSpotVMTypeEntryArrayStride"); - type_offset = readSymbol("gHotSpotVMTypeEntryTypeNameOffset"); +void VMStructs::init_type_sizes() { + uintptr_t entry = readSymbol("gHotSpotVMTypes"); + uintptr_t stride = readSymbol("gHotSpotVMTypeEntryArrayStride"); + uintptr_t type_offset = readSymbol("gHotSpotVMTypeEntryTypeNameOffset"); uintptr_t size_offset = readSymbol("gHotSpotVMTypeEntrySizeOffset"); if (entry != 0 && stride != 0) { @@ -425,71 +187,132 @@ void VMStructs::initOffsets() { uint64_t size = *(uint64_t*)(entry + size_offset); - #define TYPE_SIZE_MATCH(name, ...) \ - if (initTypeSize(VMStructs::TYPE_SIZE_NAME(name), type, size, ##__VA_ARGS__)) continue; + #define READ_TYPE_SIZE(name, names) \ + if (matchAny(type, names)) { \ + TYPE_SIZE_NAME(name) = size; \ + continue; \ + } - DECLARE_TYPES_DO(TYPE_SIZE_MATCH) + DECLARE_TYPES_DO(READ_TYPE_SIZE) -#undef TYPE_SIZE_MATCH +#undef READ_TYPE_SIZE } } +} + +#define READ_CONSTANT(type, field) \ + if (strcmp(type_name, #type "::" #field) == 0) { \ + _##type##_##field = value; \ + continue; \ + } - entry = readSymbol("gHotSpotVMLongConstants"); - stride = readSymbol("gHotSpotVMLongConstantEntryArrayStride"); - uintptr_t name_offset = readSymbol("gHotSpotVMLongConstantEntryNameOffset"); - uintptr_t value_offset = readSymbol("gHotSpotVMLongConstantEntryValueOffset"); +void VMStructs::init_constants() { + // Int constants + uintptr_t entry = readSymbol("gHotSpotVMIntConstants"); + uintptr_t stride = readSymbol("gHotSpotVMIntConstantEntryArrayStride"); + uintptr_t name_offset = readSymbol("gHotSpotVMIntConstantEntryNameOffset"); + uintptr_t value_offset = readSymbol("gHotSpotVMIntConstantEntryValueOffset"); if (entry != 0 && stride != 0) { for (;; entry += stride) { - const char* name = *(const char**)(entry + name_offset); - if (name == NULL) { + const char* type_name = *(const char**)(entry + name_offset); + if (type_name == nullptr) { break; } - - if (strncmp(name, "markWord::", 10) == 0) { - if (strcmp(name + 10, "klass_shift") == 0) { - _markword_klass_shift = *(long*)(entry + value_offset); - } else if (strcmp(name + 10, "monitor_value") == 0) { - _markword_monitor_value = *(long*)(entry + value_offset); - } - } + int value = *(int*)(entry + value_offset); + DECLARE_INT_CONSTANTS_DO(READ_CONSTANT) } } + // Sepcial case + _frame_entry_frame_call_wrapper_offset *= sizeof(uintptr_t); - entry = readSymbol("gHotSpotVMIntConstants"); - stride = readSymbol("gHotSpotVMIntConstantEntryArrayStride"); - name_offset = readSymbol("gHotSpotVMIntConstantEntryNameOffset"); - value_offset = readSymbol("gHotSpotVMIntConstantEntryValueOffset"); + + // Long constants + entry = readSymbol("gHotSpotVMLongConstants"); + stride = readSymbol("gHotSpotVMLongConstantEntryArrayStride"); + name_offset = readSymbol("gHotSpotVMLongConstantEntryNameOffset"); + value_offset = readSymbol("gHotSpotVMLongConstantEntryValueOffset"); if (entry != 0 && stride != 0) { for (;; entry += stride) { - const char* name = *(const char**)(entry + name_offset); - if (name == NULL) { + const char* type_name = *(const char**)(entry + name_offset); + if (type_name == nullptr) { break; } - if (strcmp(name, "frame::entry_frame_call_wrapper_offset") == 0) { - _entry_frame_call_wrapper_offset = *(int*)(entry + value_offset) * sizeof(uintptr_t); - break; // remove it for reading more constants - } + long value = *(long*)(entry + value_offset); + DECLARE_LONG_CONSTANTS_DO(READ_CONSTANT) } } } +#undef READ_CONSTANT + + +#ifdef DEBUG +void VMStructs::verify_offsets() { +// Verify type sizes +#define VERIFY_TYPE_SIZE(name, names) assert(TYPE_SIZE_NAME(name) > 0); + DECLARE_TYPES_DO(VERIFY_TYPE_SIZE); +#undef VERIFY_TYPE_SIZE + + +// Verify offsets and addresses +#define offset_value -1 +#define address_value nullptr +#define off_value_value -1 +#define addr_value_value -1 + +// Do nothing macro +#define DO_NOTHING(...) +#define VERIFY_OFFSET_OR_ADDRESS(var, field_type, names) \ + assert(var != field_type##_value); + + DECLARE_TYPE_FILED_DO(DO_NOTHING, VERIFY_OFFSET_OR_ADDRESS, DO_NOTHING, DO_NOTHING) +#undef VERIFY_OFFSET_OR_ADDRESS +#undef DO_NOTHING +#undef offset_value +#undef address_value +#undef off_value_value +#undef addr_value_value + +// Verify constants +// Initialize constant variables to -1 +#define VERIFY_CONSTANT(type, field) \ + // assert(_##type##_##field != -1); + + DECLARE_INT_CONSTANTS_DO(VERIFY_CONSTANT) + DECLARE_LONG_CONSTANTS_DO(VERIFY_CONSTANT) +#undef INIT_CONSTANT +} + +#endif // DEBUG + +void VMStructs::initOffsets() { + init_type_sizes(); + init_offsets_and_addresses(); + init_constants(); + + +#ifdef DEBUG +// verify_offsets(); +#endif +} + void VMStructs::resolveOffsets() { if (VM::isOpenJ9() || VM::isZing()) { return; } if (_klass_offset_addr != NULL) { - _klass = (jfieldID)(uintptr_t)(*_klass_offset_addr << 2 | 2); + _klass = (jfieldID)(uintptr_t)(*(int*)_klass_offset_addr << 2 | 2); } VMFlag* ccp = VMFlag::find("UseCompressedClassPointers"); - if (ccp != NULL && ccp->get() && _narrow_klass_base_addr != NULL && _narrow_klass_shift_addr != NULL) { - _narrow_klass_base = *_narrow_klass_base_addr; - _narrow_klass_shift = *_narrow_klass_shift_addr; + if (ccp != NULL && ccp->get() && _narrow_klass_base_addr != NULL && _narrow_klass_shift_addr != nullptr) { + _narrow_klass_base = *(char**)_narrow_klass_base_addr; + _narrow_klass_shift = *(int*)_narrow_klass_shift_addr; } VMFlag* coh = VMFlag::find("UseCompactObjectHeaders"); @@ -498,7 +321,7 @@ void VMStructs::resolveOffsets() { } _has_class_names = _klass_name_offset >= 0 - && (_compact_object_headers ? (_markword_klass_shift >= 0 && _markword_monitor_value == MONITOR_BIT) + && (_compact_object_headers ? (_markWord_klass_shift >= 0 && _markWord_monitor_value == MONITOR_BIT) : _oop_klass_offset >= 0) && (_symbol_length_offset >= 0 || _symbol_length_and_refcount_offset >= 0) && _symbol_body_offset >= 0 @@ -506,7 +329,7 @@ void VMStructs::resolveOffsets() { _has_method_structs = _jmethod_ids_offset >= 0 && _nmethod_method_offset >= 0 - && _nmethod_entry_offset != -1 + && (_nmethod_entry_offset != -1 || _nmethod_entry_address != -1) && _nmethod_state_offset >= 0 && _method_constmethod_offset >= 0 && _method_code_offset >= 0 @@ -530,10 +353,10 @@ void VMStructs::resolveOffsets() { #elif defined(__aarch64__) _interpreter_frame_bcp_offset = VM::hotspot_version() >= 11 ? -9 : VM::hotspot_version() == 8 ? -7 : 0; // The constant is missing on ARM, but fortunately, it has been stable for years across all JDK versions - _entry_frame_call_wrapper_offset = -64; + _frame_entry_frame_call_wrapper_offset = -64; #elif defined(__arm__) || defined(__thumb__) _interpreter_frame_bcp_offset = VM::hotspot_version() >= 11 ? -8 : 0; - _entry_frame_call_wrapper_offset = 0; + _frame_entry_frame_call_wrapper_offset = 0; #endif // JDK-8292758 has slightly changed ScopeDesc encoding @@ -542,7 +365,7 @@ void VMStructs::resolveOffsets() { } if (_call_stub_return_addr != NULL) { - _call_stub_return = *_call_stub_return_addr; + _call_stub_return = *(const void**)_call_stub_return_addr; } // Since JDK 23, _metadata_offset is relative to _data_offset. See metadata() @@ -552,11 +375,11 @@ void VMStructs::resolveOffsets() { _has_stack_structs = _has_method_structs && _call_wrapper_anchor_offset >= 0 - && _entry_frame_call_wrapper_offset != -1 + && _frame_entry_frame_call_wrapper_offset != -1 && _interpreter_frame_bcp_offset != 0 - && _code_offset != -1 + && (_code_offset != -1 || _code_address != -1) && _data_offset >= 0 - && _scopes_data_offset != -1 + && (_scopes_data_offset != -1 || _scopes_data_address != -1) && _scopes_pcs_offset >= 0 && ((_mutable_data_offset >= 0 && _relocation_size_offset >= 0) || _nmethod_metadata_offset >= 0) && _thread_vframe_offset >= 0 @@ -567,16 +390,16 @@ void VMStructs::resolveOffsets() { _can_dereference_jmethod_id = _has_method_structs && VM::hotspot_version() <= 25; if (_code_heap_addr != NULL && _code_heap_low_addr != NULL && _code_heap_high_addr != NULL) { - char* code_heaps = *_code_heap_addr; + char* code_heaps = *(char**)_code_heap_addr; unsigned int code_heap_count = *(unsigned int*)(code_heaps + _array_len_offset); if (code_heap_count <= 3 && _array_data_offset >= 0) { char* code_heap_array = *(char**)(code_heaps + _array_data_offset); memcpy(_code_heap, code_heap_array, code_heap_count * sizeof(_code_heap[0])); } - _code_heap_low = *_code_heap_low_addr; - _code_heap_high = *_code_heap_high_addr; + _code_heap_low = *(const void**)_code_heap_low_addr; + _code_heap_high = *(const void**)_code_heap_high_addr; } else if (_code_heap_addr != NULL && _code_heap_memory_offset >= 0) { - _code_heap[0] = *_code_heap_addr; + _code_heap[0] = *(char**)_code_heap_addr; _code_heap_low = *(const void**)(_code_heap[0] + _code_heap_memory_offset + _vs_low_bound_offset); _code_heap_high = *(const void**)(_code_heap[0] + _code_heap_memory_offset + _vs_high_bound_offset); } @@ -915,8 +738,10 @@ int ScopeDesc::readInt() { VMFlag* VMFlag::find(const char* name) { if (_flags_addr != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count; i++) { - VMFlag* f = VMFlag::cast(_flags_addr + i * VMFlag::type_size()); + size_t count = *(size_t*)_flag_count; + + for (size_t i = 0; i < count; i++) { + VMFlag* f = VMFlag::cast(*(const char**)_flags_addr + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0 && f->addr() != NULL) { return f; } @@ -935,8 +760,9 @@ VMFlag *VMFlag::find(const char *name, std::initializer_list types VMFlag *VMFlag::find(const char *name, int type_mask) { if (_flags_addr != NULL && VMFlag::type_size() > 0) { - for (int i = 0; i < _flag_count; i++) { - VMFlag* f = VMFlag::cast(_flags_addr + i * VMFlag::type_size()); + size_t count = *(size_t*)_flag_count; + for (size_t i = 0; i < count; i++) { + VMFlag* f = VMFlag::cast(*(const char**)_flags_addr + i * VMFlag::type_size()); if (f->name() != NULL && strcmp(f->name(), name) == 0) { int masked = 0x1 << f->type(); if (masked & type_mask) { @@ -1188,13 +1014,13 @@ HeapUsage HeapUsage::get(bool allow_jmx) { if (_collected_heap_addr != NULL) { if (_heap_usage_func != NULL) { // this is the JDK 17+ path - usage = _heap_usage_func(*_collected_heap_addr); + usage = _heap_usage_func(*(char**)_collected_heap_addr); usage._used_at_last_gc = - ((CollectedHeapWrapper *)*_collected_heap_addr)->_used_at_last_gc; + ((CollectedHeapWrapper *)*(char**)_collected_heap_addr)->_used_at_last_gc; } else if (_gc_heap_summary_func != NULL) { // this is the JDK 11 path // we need to collect GCHeapSummary information first - GCHeapSummary summary = _gc_heap_summary_func(*_collected_heap_addr); + GCHeapSummary summary = _gc_heap_summary_func(*(char**)_collected_heap_addr); usage._initSize = -1; usage._used = summary.used(); usage._committed = -1; diff --git a/ddprof-lib/src/main/cpp/vmStructs.h b/ddprof-lib/src/main/cpp/vmStructs.h index 4db172c49..6f0bc2365 100644 --- a/ddprof-lib/src/main/cpp/vmStructs.h +++ b/ddprof-lib/src/main/cpp/vmStructs.h @@ -19,7 +19,6 @@ class GCHeapSummary; class HeapUsage; -#define TYPE_SIZE_NAME(name) _##name##_size template inline T* cast_to(const void* ptr) { @@ -28,6 +27,27 @@ inline T* cast_to(const void* ptr) { return reinterpret_cast(const_cast(ptr)); } +#define TYPE_SIZE_NAME(name) _##name##_size + +// MATCH_SYMBOLS macro expands into an nullptr terminated char string array, +// that is consumed by matchAny() method +#define MATCH_SYMBOLS(...) (const char*[]) { __VA_ARGS__, nullptr } + +/** + * This macro defines a counterpart of a JVM class, e.g. VMKass -> Klass. + * By the convention, we prefix the class name with 'VM' to avoid namespace collision + * with JVM inside a debug session. E.g. + * gdb > p this + * gdb > (VMKlass*)0x123456 + * gdb > p (Klass*)this + * .... + * + * The macro implicitly defines three static functions: + * - type_size() Return class size defined in JVM. + * - cast() It performs memory readability check before casts a void* pointer to this type. + * It ensures the memory range [ptr, ptr + type_size()) is readable. + * - load_then_cast() It loads a pointer from specified location, then does above cast. + */ #define DECLARE(name) \ class name : VMStructs { \ public: \ @@ -39,22 +59,212 @@ inline T* cast_to(const void* ptr) { #define DECLARE_END }; -#define MATCH_SYMBOLS(...) __VA_ARGS__, nullptr +/** + * Defines a type and its matching symbols in vmStructs. + * A type may match multiple names in different JVM versions. + * Macro expansion: + * - Declaration phase + * static uint64_t _TYPE_size; + * + * For example: + * f(VMClassLoaderData) -> static uint64_t _VMClassLoaderData_size; + * + * - Initialization phase + * uint64_t VMStructs::_TYPE_size = 0; + * + * For exmaple: + * f(VMClassLoaderData) -> uint64_t VMStructs::_VMClassLoaderData_size = 0; + * + * - Value population phase + * if (matchAny((char*)[]) { typeName, nullptr}) { + * _TYPE_size = size; + * continue; + * } + * + * For example: + * f(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) -> + * if (matchAny((char*)[] {"ClassLoaderData", nullptr})) { + * _ClassLoaderData_size = size; + * continue; + * } + * + * - Value verification phase + * assert(_TYPE_size > 0); + * + * For example: + * f(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) -> + * assert(_VMClassLoaderData_size > 0); + */ -// Defines a type and its matching symbols in vmStructs. -// A type may match multiple names in different JVM versions. #define DECLARE_TYPES_DO(f) \ - f(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) \ - f(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ - f(VMConstMethod, MATCH_SYMBOLS("ConstMethod")) \ - f(VMFlag, MATCH_SYMBOLS("JVMFlag", "Flag")) \ - f(VMJavaFrameAnchor, MATCH_SYMBOLS("JavaFrameAnchor")) \ - f(VMKlass, MATCH_SYMBOLS("Klass")) \ - f(VMMethod, MATCH_SYMBOLS("Method")) \ - f(VMNMethod, MATCH_SYMBOLS("nmethod")) \ - f(VMSymbol, MATCH_SYMBOLS("Symbol")) \ + f(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) \ + f(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ + f(VMConstMethod, MATCH_SYMBOLS("ConstMethod")) \ + f(VMFlag, MATCH_SYMBOLS("JVMFlag", "Flag")) \ + f(VMJavaFrameAnchor, MATCH_SYMBOLS("JavaFrameAnchor")) \ + f(VMKlass, MATCH_SYMBOLS("Klass")) \ + f(VMMethod, MATCH_SYMBOLS("Method")) \ + f(VMNMethod, MATCH_SYMBOLS("nmethod")) \ + f(VMSymbol, MATCH_SYMBOLS("Symbol")) \ f(VMThread, MATCH_SYMBOLS("Thread")) +/** + * Following macros define field offsets, addresses or values of JVM classes that are exported by + * vmStructs. + * - type_begin() Start a definition of a type. The type name is not used at this moment, but + * improves readability. + * - field() Define a field of a class, can be either an offset, an address or a value + * - field_no_check Define a field of a class, just like above. But the field may not be exported + * by JVMs. Therefore, it is skiped by verify_offsets() + * - type_end() End of a type definition +*/ + +typedef int offset; +typedef void* address; + +#define DECLARE_TYPE_FILED_DO(type_begin, field, field_no_check, type_end) \ + type_begin(VMMemRegion, MATCH_SYMBOLS("MemRegion")) \ + field(_region_start_offset, offset, MATCH_SYMBOLS("_start")) \ + field(_region_size_offset, offset, MATCH_SYMBOLS("_word_size")) \ + type_end() \ + type_begin(VMNMethod, MATCH_SYMBOLS("CompiledMethod", "nmethod")) \ + field(_nmethod_method_offset, offset, MATCH_SYMBOLS("_method")) \ + field(_nmethod_entry_offset, offset, MATCH_SYMBOLS("_verified_entry_offset")) \ + field(_nmethod_entry_address, offset, MATCH_SYMBOLS("_verified_entry_point")) \ + field(_nmethod_state_offset, offset, MATCH_SYMBOLS("_state")) \ + field(_nmethod_level_offset, offset, MATCH_SYMBOLS("_comp_level")) \ + field(_nmethod_metadata_offset, offset, MATCH_SYMBOLS("_metadata_offset")) \ + field_no_check(_nmethod_immutable_offset, offset, MATCH_SYMBOLS("_immutable_data")) \ + field(_scopes_pcs_offset, offset, MATCH_SYMBOLS("_scopes_pcs_offset")) \ + field(_scopes_data_offset, offset, MATCH_SYMBOLS("_scopes_data_offset")) \ + field(_scopes_data_address, offset, MATCH_SYMBOLS("_scopes_data_begin")) \ + type_end() \ + type_begin(VMMethod, MATCH_SYMBOLS("Method")) \ + field(_method_constmethod_offset, offset, MATCH_SYMBOLS("_constMethod")) \ + field(_method_code_offset, offset, MATCH_SYMBOLS("_code")) \ + type_end() \ + type_begin(VMConstMethod, MATCH_SYMBOLS("ConstMethod")) \ + field(_constmethod_constants_offset, offset, MATCH_SYMBOLS("_constants")) \ + field(_constmethod_idnum_offset, offset, MATCH_SYMBOLS("_method_idnum")) \ + type_end() \ + type_begin(VMConstantPool, MATCH_SYMBOLS("ConstantPool")) \ + field(_pool_holder_offset, offset, MATCH_SYMBOLS("_pool_holder")) \ + type_end() \ + type_begin(VMKlass, MATCH_SYMBOLS("Klass", "InstanceKlass")) \ + field(_klass_name_offset, offset, MATCH_SYMBOLS("_name")) \ + field(_class_loader_data_offset, offset, MATCH_SYMBOLS("_class_loader_data")) \ + field(_methods_offset, offset, MATCH_SYMBOLS("_methods")) \ + field(_jmethod_ids_offset, offset, MATCH_SYMBOLS("_methods_jmethod_ids")) \ + type_end() \ + type_begin(VMClassLoaderData, MATCH_SYMBOLS("ClassLoaderData")) \ + field(_class_loader_data_next_offset, offset, MATCH_SYMBOLS("_next")) \ + type_end() \ + type_begin(VMJavaClass, MATCH_SYMBOLS("java_lang_Class")) \ + field(_klass_offset_addr, address, MATCH_SYMBOLS("_klass_offset")) \ + type_end() \ + type_begin(VMSymbol, MATCH_SYMBOLS("Symbol")) \ + field(_symbol_length_offset, offset, MATCH_SYMBOLS("_length")) \ + field(_symbol_body_offset, offset, MATCH_SYMBOLS("_body")) \ + field_no_check(_symbol_length_and_refcount_offset, offset, MATCH_SYMBOLS("_length_and_refcount")) \ + type_end() \ + type_begin(VMJavaThread, MATCH_SYMBOLS("JavaThread", "Thread")) \ + field(_thread_osthread_offset, offset, MATCH_SYMBOLS("_osthread")) \ + field(_thread_anchor_offset, offset, MATCH_SYMBOLS("_anchor")) \ + field(_thread_state_offset, offset, MATCH_SYMBOLS("_thread_state")) \ + field(_thread_vframe_offset, offset, MATCH_SYMBOLS("_vframe_array_head")) \ + type_end() \ + type_begin(VMOSThread, MATCH_SYMBOLS("OSThread")) \ + field(_osthread_id_offset, offset, MATCH_SYMBOLS("_thread_id")) \ + field(_osthread_state_offset, offset, MATCH_SYMBOLS("_state")) \ + type_end() \ + type_begin(VMThreadShow, MATCH_SYMBOLS("ThreadShadow")) \ + field(_thread_exception_offset, offset, MATCH_SYMBOLS("_exception_file")) \ + type_end() \ + type_begin(VMCompilerThread, MATCH_SYMBOLS("CompilerThread")) \ + field(_comp_env_offset, offset, MATCH_SYMBOLS("_env")) \ + type_end() \ + type_begin(VMciEnv, MATCH_SYMBOLS("ciEnv")) \ + field(_comp_task_offset, offset, MATCH_SYMBOLS("_task")) \ + type_end() \ + type_begin(VMCompileTask, MATCH_SYMBOLS("CompileTask")) \ + field(_comp_method_offset, offset, MATCH_SYMBOLS("_method")) \ + type_end() \ + type_begin(VMJavaCallWrapper, MATCH_SYMBOLS("JavaCallWrapper")) \ + field(_call_wrapper_anchor_offset, offset, MATCH_SYMBOLS("_anchor")) \ + type_end() \ + type_begin(VMJavaFrameAnchor, MATCH_SYMBOLS("JavaFrameAnchor")) \ + field(_anchor_sp_offset, offset, MATCH_SYMBOLS("_last_Java_sp")) \ + field(_anchor_pc_offset, offset, MATCH_SYMBOLS("_last_Java_pc")) \ + field(_anchor_fp_offset, offset, MATCH_SYMBOLS("_last_Java_fp")) \ + type_end() \ + type_begin(VMCodeBlob, MATCH_SYMBOLS("CodeBlob")) \ + field(_blob_size_offset, offset, MATCH_SYMBOLS("_size")) \ + field(_frame_size_offset, offset, MATCH_SYMBOLS("_frame_size")) \ + field(_frame_complete_offset, offset, MATCH_SYMBOLS("_frame_complete_offset")) \ + field(_code_offset, offset, MATCH_SYMBOLS("_code_offset")) \ + field(_code_address, offset, MATCH_SYMBOLS("_code_begin")) \ + field(_data_offset, offset, MATCH_SYMBOLS("_data_offset")) \ + field_no_check(_mutable_data_offset, offset, MATCH_SYMBOLS("_mutable_data")) \ + field_no_check(_relocation_size_offset, offset, MATCH_SYMBOLS("_relocation_size")) \ + field(_nmethod_name_offset, offset, MATCH_SYMBOLS("_name")) \ + type_end() \ + type_begin(VMCodeCache, MATCH_SYMBOLS("CodeCache")) \ + field(_code_heap_addr, address, MATCH_SYMBOLS("_heap", "_heaps")) \ + field(_code_heap_low_addr, address, MATCH_SYMBOLS("_low_bound")) \ + field(_code_heap_high_addr, address, MATCH_SYMBOLS("_high_bound")) \ + type_end() \ + type_begin(VMCodeHeap, MATCH_SYMBOLS("CodeHeap")) \ + field(_code_heap_memory_offset, offset, MATCH_SYMBOLS("_memory")) \ + field(_code_heap_segmap_offset, offset, MATCH_SYMBOLS("_segmap")) \ + field(_code_heap_segment_shift, offset, MATCH_SYMBOLS("_log2_segment_size")) \ + type_end() \ + type_begin(VMHeapBlock, MATCH_SYMBOLS("HeapBlock::Header")) \ + field(_heap_block_used_offset, offset, MATCH_SYMBOLS("_used")) \ + type_end() \ + type_begin(VMVirtualSpace, MATCH_SYMBOLS("VirtualSpace")) \ + field(_vs_low_bound_offset, offset, MATCH_SYMBOLS("_low_boundary")) \ + field(_vs_high_bound_offset, offset, MATCH_SYMBOLS("_high_boundary")) \ + field(_vs_low_offset, offset, MATCH_SYMBOLS("_low")) \ + field(_vs_high_offset, offset, MATCH_SYMBOLS("_high")) \ + type_end() \ + type_begin(VMStubRoutine, MATCH_SYMBOLS("StubRoutines")) \ + field(_call_stub_return_addr, address, MATCH_SYMBOLS("_call_stub_return_address")) \ + type_end() \ + type_begin(VMGrowableArray, MATCH_SYMBOLS("GrowableArrayBase", "GenericGrowableArray")) \ + field(_array_len_offset, offset, MATCH_SYMBOLS("_len")) \ + type_end() \ + type_begin(VMGrowableArrayInt, MATCH_SYMBOLS("GrowableArray")) \ + field(_array_data_offset, offset, MATCH_SYMBOLS("_data")) \ + type_end() \ + type_begin(VMFlag, MATCH_SYMBOLS("JVMFlag", "Flag")) \ + field(_flag_name_offset, offset, MATCH_SYMBOLS("_name", "name")) \ + field(_flag_addr_offset, offset, MATCH_SYMBOLS("_addr", "addr")) \ + field(_flag_origin_offset, offset, MATCH_SYMBOLS("_flags", "origin")) \ + field(_flags_addr, address, MATCH_SYMBOLS("flags")) \ + field(_flag_count, address, MATCH_SYMBOLS("numFlags")) \ + field(_flag_type_offset, offset, MATCH_SYMBOLS("_type", "type")) \ + type_end() \ + type_begin(VMOop, MATCH_SYMBOLS("oopDesc")) \ + field(_oop_klass_offset, offset, MATCH_SYMBOLS("_metadata._klass")) \ + type_end() \ + type_begin(VMUniverse, MATCH_SYMBOLS("Universe", "CompressedKlassPointers")) \ + field(_narrow_klass_base_addr, address, MATCH_SYMBOLS("_narrow_klass._base", "_base")) \ + field(_narrow_klass_shift_addr, address, MATCH_SYMBOLS("_narrow_klass._shift", "_shift")) \ + field(_collected_heap_addr, address, MATCH_SYMBOLS("_collectedHeap")) \ + type_end() + +/** + * The follwing macros declare JVM constants that are exported by vmStructs + * - constant defines a constant of a class + */ + +#define DECLARE_INT_CONSTANTS_DO(constant) \ + constant(frame, entry_frame_call_wrapper_offset) + +#define DECLARE_LONG_CONSTANTS_DO(constant) \ + constant(markWord, klass_shift) \ + constant(markWord, monitor_value) + class VMStructs { public: typedef bool (*IsValidMethodFunc)(void *); @@ -72,97 +282,49 @@ class VMStructs { static bool _has_native_thread_id; static bool _can_dereference_jmethod_id; static bool _compact_object_headers; - - static int _klass_name_offset; - static int _symbol_length_offset; - static int _symbol_length_and_refcount_offset; - static int _symbol_body_offset; - static int _oop_klass_offset; - static int _class_loader_data_offset; - static int _class_loader_data_next_offset; - static int _methods_offset; - static int _jmethod_ids_offset; - static int _thread_osthread_offset; - static int _thread_anchor_offset; - static int _thread_state_offset; - static int _thread_vframe_offset; - static int _thread_exception_offset; - static int _osthread_id_offset; - static int _call_wrapper_anchor_offset; - static int _comp_env_offset; - static int _comp_task_offset; - static int _comp_method_offset; - static int _anchor_sp_offset; - static int _anchor_pc_offset; - static int _anchor_fp_offset; - static int _blob_size_offset; - static int _frame_size_offset; - static int _frame_complete_offset; - static int _code_offset; - static int _data_offset; - static int _mutable_data_offset; - static int _relocation_size_offset; - static int _scopes_pcs_offset; - static int _scopes_data_offset; - static int _nmethod_name_offset; - static int _nmethod_method_offset; - static int _nmethod_entry_offset; - static int _nmethod_state_offset; - static int _nmethod_level_offset; - static int _nmethod_metadata_offset; - static int _nmethod_immutable_offset; - static int _method_constmethod_offset; - static int _method_code_offset; - static int _constmethod_constants_offset; - static int _constmethod_idnum_offset; - static int _pool_holder_offset; - static int _array_len_offset; - static int _array_data_offset; - static int _code_heap_memory_offset; - static int _code_heap_segmap_offset; - static int _code_heap_segment_shift; - static int _heap_block_used_offset; - static int _vs_low_bound_offset; - static int _vs_high_bound_offset; - static int _vs_low_offset; - static int _vs_high_offset; - static int _flag_name_offset; - static int _flag_addr_offset; - static int _flag_origin_offset; - static const char* _flags_addr; - static int _flag_count; + + static int _narrow_klass_shift; static char* _code_heap[3]; static const void* _code_heap_low; static const void* _code_heap_high; - static char** _code_heap_addr; - static const void** _code_heap_low_addr; - static const void** _code_heap_high_addr; - static int* _klass_offset_addr; - static char** _narrow_klass_base_addr; static char* _narrow_klass_base; - static int* _narrow_klass_shift_addr; - static int _narrow_klass_shift; - static char** _collected_heap_addr; - static int _region_start_offset; - static int _region_size_offset; - static int _markword_klass_shift; - static int _markword_monitor_value; - static int _entry_frame_call_wrapper_offset; static int _interpreter_frame_bcp_offset; static unsigned char _unsigned5_base; - static const void** _call_stub_return_addr; static const void* _call_stub_return; static const void* _interpreted_frame_valid_start; static const void* _interpreted_frame_valid_end; + // Declare type size variables - #define DECLARE_TYPE_SIZE_VAR(name, ...) \ + #define DECLARE_TYPE_SIZE_VAR(name, names) \ static uint64_t TYPE_SIZE_NAME(name); - - DECLARE_TYPES_DO(DECLARE_TYPE_SIZE_VAR) + DECLARE_TYPES_DO(DECLARE_TYPE_SIZE_VAR) #undef DECLARE_TYPE_SIZE_VAR - + +// Declare vmStructs' field offsets and addresses + +// Do nothing macro +#define DO_NOTHING(...) +#define DECLARE_TYPE_FIELD(var, field_type, names) \ + static field_type var; + + DECLARE_TYPE_FILED_DO(DO_NOTHING, DECLARE_TYPE_FIELD, DECLARE_TYPE_FIELD, DO_NOTHING) +#undef DECLARE_TYPE_FIELD +#undef DO_NOTHING + +// Declare int constant variables +#define DECLARE_INT_CONSTANT_VAR(type, field) \ + static int _##type##_##field; + DECLARE_INT_CONSTANTS_DO(DECLARE_INT_CONSTANT_VAR) +#undef DECLARE_INT_CONSTANT_VAR + +// Declare long constant variables +#define DECLARE_LONG_CONSTANT_VAR(type, field) \ + static long _##type##_##field; + DECLARE_LONG_CONSTANTS_DO(DECLARE_LONG_CONSTANT_VAR) +#undef DECLARE_LONG_CONSTANT_VAR + static jfieldID _eetop; static jfieldID _tid; @@ -177,8 +339,6 @@ class VMStructs { // Datadog-specific extensions static CodeCache _unsafe_to_walk; - static int _osthread_state_offset; - static int _flag_type_offset; typedef HeapUsage (*HeapUsageFunc)(const void *); static HeapUsageFunc _heap_usage_func; typedef void *(*MemoryUsageFunc)(void *, void *, bool); @@ -188,7 +348,17 @@ class VMStructs { static IsValidMethodFunc _is_valid_method_func; static uintptr_t readSymbol(const char* symbol_name); + + // Read VM information from vmStructs + static void init_type_sizes(); + static void init_offsets_and_addresses(); + static void init_constants(); static void initOffsets(); + +#ifdef DEBUG + static void verify_offsets(); +#endif + static void resolveOffsets(); static void patchSafeFetch(); static void initJvmFunctions(); @@ -408,7 +578,7 @@ DECLARE(VMKlass) if (mark & MONITOR_BIT) { mark = *(uintptr_t*)(mark ^ MONITOR_BIT); } - narrow_klass = mark >> _markword_klass_shift; + narrow_klass = mark >> _markWord_klass_shift; } else { narrow_klass = *(unsigned int*)(oop + _oop_klass_offset); } @@ -446,9 +616,9 @@ DECLARE(VMJavaFrameAnchor) public: static VMJavaFrameAnchor* fromEntryFrame(uintptr_t fp) { - assert(_entry_frame_call_wrapper_offset != -1); + assert(_frame_entry_frame_call_wrapper_offset != -1); assert(_call_wrapper_anchor_offset >= 0); - const char* call_wrapper = (const char*) SafeAccess::loadPtr((void**)(fp + _entry_frame_call_wrapper_offset), nullptr); + const char* call_wrapper = (const char*) SafeAccess::loadPtr((void**)(fp + _frame_entry_frame_call_wrapper_offset), nullptr); if (!goodPtr(call_wrapper) || (uintptr_t)call_wrapper - fp > MAX_CALL_WRAPPER_DISTANCE) { return NULL; } @@ -632,26 +802,26 @@ DECLARE(VMNMethod) } const char* code() { - if (_code_offset > 0) { + if (_code_offset != -1) { // JDK23+ return at(*(int*) at(_code_offset)); } else { - return *(const char**) at(-_code_offset); + return *(const char**) at(_code_address); } } const char* scopes() { - if (_scopes_data_offset > 0) { + if (_scopes_data_offset != -1) { // JDK23+ return immutableDataAt(*(int*) at(_scopes_data_offset)); } else { - return *(const char**) at(-_scopes_data_offset); + return *(const char**) at(_scopes_data_address); } } const void* entry() { - if (_nmethod_entry_offset > 0) { + if (_nmethod_entry_offset != -1) { // JDK23+ return at(*(int*) at(_code_offset) + *(unsigned short*) at(_nmethod_entry_offset)); } else { - return *(void**) at(-_nmethod_entry_offset); + return *(void**) at(_nmethod_entry_address); } }