java解释器的阅读

本文深入剖析了Java字节码的解释执行过程,重点介绍了X86平台下BytecodeInterpreter::run方法如何通过循环匹配字节码指令来执行Java程序,并详细分析了_new字节码指令的具体解释流程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

     前面已经提到了java的方法入口是Interpreter::entry_for_method,此处就将cpu控制权交给了java的解释器。

上面的entry_for_method为这个AbstractInterpreterGenerator::generate_method_entry函数的返回值,在此还是以X86机器为例,普通的方法由InterpreterGenerator::generate_normal_entry返回。

     address InterpreterGenerator::generate_normal_entry(bool synchronized) {

                .......

          //调用真正解释器的地方

          RuntimeAddress normal(CAST_FROM_FN_PTR(address, BytecodeInterpreter::run));
           RuntimeAddress checking(CAST_FROM_FN_PTR(address, BytecodeInterpreter::runWithChecks));

           __ call(JvmtiExport::can_post_interpreter_events() ? checking : normal);
           __ popl(rax);                                                  // discard parameter to run

     }

   在执行到上面的call时,就会调用了BytecodeInterpreter::run方法。此方法在BytecodeInterpreter.cpp里面,用#ifdef这些包含,不容易找到。这也是一个硕大的方法。挑选进行字节码解释部分分析一下。

     while (1){

            opcode = *pc;

            switch (opcode){

                   ...........

                   CASE(_new): {
                           u2 index = Bytes::get_Java_u2(pc+1);
                           constantPoolOop constants = istate->method()->constants();
                           if (!constants->tag_at(index).is_unresolved_klass()) {
                            // Make sure klass is initialized and doesn't have a finalizer
                           oop entry = (klassOop) *constants->obj_at_addr(index);
                           assert(entry->is_klass(), "Should be resolved klass");
                           klassOop k_entry = (klassOop) entry;
                           assert(k_entry->klass_part()->oop_is_instance(), "Should be instanceKlass");
                           instanceKlass* ik = (instanceKlass*) k_entry->klass_part();
                           if ( ik->is_initialized() && ik->can_be_fastpath_allocated() ) {
                           size_t obj_size = ik->size_helper();
                           oop result = NULL;
                           // If the TLAB isn't pre-zeroed then we'll have to do it
                           bool need_zero = !ZeroTLAB;
                           if (UseTLAB) {
                                   result = (oop) THREAD->tlab().allocate(obj_size);
                           }
                           if (result == NULL) {
                                   need_zero = true;
                                   // Try allocate in shared eden
                           retry:
                                   HeapWord* compare_to = *Universe::heap()->top_addr();
                                   HeapWord* new_top = compare_to + obj_size;
                                   if (new_top <= *Universe::heap()->end_addr()) {
                                               if (Atomic::cmpxchg_ptr(new_top, Universe::heap()->top_addr(), compare_to) != compare_to) {
                                               goto retry;
                                 }
                           result = (oop) compare_to;
                       }
                     }
                  if (result != NULL) {
                            // Initialize object (if nonzero size and need) and then the header
                        if (need_zero ) {
                                  HeapWord* to_zero = (HeapWord*) result + sizeof(oopDesc) / oopSize;
                                  obj_size -= sizeof(oopDesc) / oopSize;
                                  if (obj_size > 0 ) {
                                          memset(to_zero, 0, obj_size * HeapWordSize);
                                  }
                   }
                   if (UseBiasedLocking) {
                             result->set_mark(ik->prototype_header());
                   } else {
                            result->set_mark(markOopDesc::prototype());
                   }
                   result->set_klass(k_entry);
                   SET_STACK_OBJECT(result, 0);
                   UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);
                 }
              }
          }
          // Slow case allocation
          CALL_VM(InterpreterRuntime::_new(THREAD, METHOD->constants(), index),
                handle_exception);
          SET_STACK_OBJECT(THREAD->vm_result(), 0);
          THREAD->set_vm_result(NULL);
          UPDATE_PC_AND_TOS_AND_CONTINUE(3, 1);
      }

   //上面挑选一段new字节码的解释过程,整个run函数用到太多的宏,看起来太费劲,个人感觉宏难以理解,还是少用为好

      ................

      if (!THREAD->has_pending_exception()) {
        CONTINUE;
      }
      /* We will be gcsafe soon, so flush our state. */
      DECACHE_PC();
      goto handle_exception;
    }
  do_continue: ;

 }

 .........

 //下面是些处理异常的操作

由上面的代码可以看到,整个解释过程就是不断读入字节码,和系统预先定义好的字节码进行匹配(也就是上面的case处理)的过程。解释所用到的java栈、栈桢、本地方法栈等,还有待于慢慢阅读分析。

 

内容: 这个合成医疗保健数据集的创建是为了作为数据科学、机器学习和数据分析爱好者的宝贵资源。 灵感: 医疗保健数据通常很敏感,并受隐私法规的约束,因此难以访问以进行学习和实验。为了解决这一差距,我利用 Python 的 Faker 库生成了一个数据集,该数据集反映了医疗保健记录中常见的结构和属性。通过提供这些合成数据,我希望促进医疗保健分析领域的创新、学习和知识共享。 表格信息: 每列都提供有关患者、其入院情况和提供的医疗保健服务的特定信息,使此数据集适用于医疗保健领域的各种数据分析和建模任务。以下是数据集中每一列的简要说明 - 名字:此列表示与医疗保健记录关联的患者的姓名。 年龄:患者入院时的年龄,以年表示。 性:指示患者的性别,“男性”或“女性”。 血型:患者的血型,可以是常见的血型之一(例如,“A+”、“O-”等)。 医疗状况:此列指定了与患者相关的主要医疗状况或诊断,例如“糖尿病”、“高血压”、“哮喘”等。 入学日期:患者入住医疗机构的日期。 医生:在患者入院期间负责护理的医生的姓名。 医院:标识患者收治的医疗机构或医院。 保险提供商:此列指示患者的保险提供商,可以是多个选项之一,包括“Aetna”、“Blue Cross”、“Cigna”、“UnitedHealthcare”和“Medicare”。 账单金额:患者在入院期间为他们的医疗保健服务开具的账单金额。这表示为浮点数。 房间号:患者入院期间入住的房间号。 入场类型:指定入院类型,可以是“紧急”、“选择性”或“紧急”,以反映入院的情况。 出院日期:患者从医疗机构出院的日期,基于入院日期和实际范围内的随机天数。 药物:确定患者在入院期间开具或服用的药物。例子包括“阿司匹林”、“布洛芬”、“青霉素”、“扑热息痛”和“立普妥”。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值