jvm 解释器解析get/put方法只解析对字段的第一次访问

noj0wjuj  于 5个月前  发布在  其他
关注(0)|答案(1)|浏览(44)

我试图记录我正在构建的分析工具对字段/静态变量的每次访问,到目前为止,我发现了这个解释器rt函数,

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()
      );
    }

字符串
然而,这只记录了对字段/静态变量的第一次访问,我假设这然后被缓存并放置在某个表上,以便稍后使用以实现更快的访问,但到目前为止我没有发现任何有用的东西。
缓存发生在哪里,是否有一种方法来获得每一个访问,也许我应该编辑cpu特定的代码?
P.S我使用openjdk 21,文件可以在src/hotspot/share/interpreter/interpreterRuntime.cpp找到。
谢谢

dba5bblo

dba5bblo1#

您不需要修改JDK代码来跟踪字段访问。
JVM工具接口(JVM TI)是专门为这类工具设计的。
或者,您可以创建一个字节码插装代理,通过在每个getfield/putfield/getstatic/putstatic字节码旁边添加对跟踪方法的调用来修改加载的类。

相关问题