I am trying to log every access to a field/static variable for an analysis tool I'm building, so far I have found this interpreter rt function,
void InterpreterRuntime::resolve_get_put(JavaThread* current, Bytecodes::Code bytecode) { // resolve field fieldDescriptor info; LastFrameAccessor last_frame(current); constantPoolHandle pool(current, last_frame.method()->constants()); methodHandle m(current, last_frame.method()); bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_nofast_putfield || bytecode == Bytecodes::_putstatic); bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic); { JvmtiHideSingleStepping jhss(current); JavaThread* THREAD = current; // For exception macros. LinkResolver::resolve_field_access(info, pool, last_frame.get_index_u2_cpcache(bytecode), m, bytecode, CHECK); } // end JvmtiHideSingleStepping fprintf(stderr, "%s access to %s.%s%s\n", is_put ? "put" : "get", info.field_holder()->external_name(), info.name()->as_C_string(), info.signature()->as_C_string()); // check if link resolution caused cpCache to be updated ConstantPoolCacheEntry* cp_cache_entry = last_frame.cache_entry(); if (cp_cache_entry->is_resolved(bytecode)) return; // compute auxiliary field attributes TosState state = as_TosState(info.field_type()); // Resolution of put instructions on final fields is delayed. That is required so that // exceptions are thrown at the correct place (when the instruction is actually invoked). // If we do not resolve an instruction in the current pass, leaving the put_code // set to zero will cause the next put instruction to the same field to reresolve. // Resolution of put instructions to final instance fields with invalid updates (i.e., // to final instance fields with updates originating from a method different than <init>) // is inhibited. A putfield instruction targeting an instance final field must throw // an IllegalAccessError if the instruction is not in an instance // initializer method <init>. If resolution were not inhibited, a putfield // in an initializer method could be resolved in the initializer. Subsequent // putfield instructions to the same field would then use cached information. // As a result, those instructions would not pass through the VM. That is, // checks in resolve_field_access() would not be executed for those instructions // and the required IllegalAccessError would not be thrown. // // Also, we need to delay resolving getstatic and putstatic instructions until the // class is initialized. This is required so that access to the static // field will call the initialization function every time until the class // is completely initialized ala. in 2.17.5 in JVM Specification. InstanceKlass* klass = info.field_holder(); bool uninitialized_static = is_static && !klass->is_initialized(); bool has_initialized_final_update = info.field_holder()->major_version() >= 53 && info.has_initialized_final_update(); assert(!(has_initialized_final_update && !info.access_flags().is_final()), "Fields with initialized final updates must be final"); Bytecodes::Code get_code = (Bytecodes::Code)0; Bytecodes::Code put_code = (Bytecodes::Code)0; if (!uninitialized_static) { get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield); if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) { put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield); } } cp_cache_entry->set_field( get_code, put_code, info.field_holder(), info.index(), info.offset(), state, info.access_flags().is_final(), info.access_flags().is_volatile() ); } However, this only logs the first access to a field/static variable, I am assuming that this is then cached and placed on some table to be used later for faster access, but I didn't find anything useful so far.
Where is the caching taking place and is there a way to get every access, maybe I should edit cpu specific code?
P.S I am using openjdk 21 and the file can be found at src/hotspot/share/interpreter/interpreterRuntime.cpp.
Thanks