zoukankan      html  css  js  c++  java
  • 第13篇-通过InterpreterCodelet存储机器指令片段

    在TemplateInterpreterGenerator::generate_all()函数中生成了许多字节码指令以及一些虚拟机辅助执行的机器指令片段,例如生成空指针异常抛出入口的实现如下:

    {
        CodeletMark cm(_masm, "throw exception entrypoints");
        // ...
        Interpreter::_throw_NullPointerException_entry = generate_exception_handler("java/lang/NullPointerException",NULL);
        // ...
    }

    调用generate_exception_handler()函数生成抛出空指针的代码片段。

    address generate_exception_handler(const char* name, const char* message) {
        return generate_exception_handler_common(name, message, false);
    }

    调用的generate_exception_handler_common()函数的实现如下:

    address TemplateInterpreterGenerator::generate_exception_handler_common(
    const char* name, 
    const char* message, 
    bool pass_oop
    ) {
    
      assert(!pass_oop || message == NULL, "either oop or message but not both");
      address entry = __ pc();
      if (pass_oop) {
        // object is at TOS
        __ pop(c_rarg2);
      }
    
      // expression stack must be empty before entering the VM if an
      // exception happened
      __ empty_expression_stack();
    
      // setup parameters
      __ lea(c_rarg1, ExternalAddress((address)name));
    
      if (pass_oop) {
        __ call_VM(rax,
                   CAST_FROM_FN_PTR(address,InterpreterRuntime::create_klass_exception),
                   c_rarg1,c_rarg2);
      } else {
        // kind of lame ExternalAddress can't take NULL because
        // external_word_Relocation will assert.
        if (message != NULL) {
          __ lea(c_rarg2, ExternalAddress((address)message));
        } else {
          __ movptr(c_rarg2, NULL_WORD);
        }
        __ call_VM(rax,
                   CAST_FROM_FN_PTR(address, InterpreterRuntime::create_exception),
                   c_rarg1, c_rarg2);
      }
    
      // throw exception
      __ jump(ExternalAddress(Interpreter::throw_exception_entry()));
    
      return entry;
    }
    

    生成的汇编代码如下:

    0x00007fffe10101cb: mov    -0x40(%rbp),%rsp
    0x00007fffe10101cf: movq   $0x0,-0x10(%rbp)
    0x00007fffe10101d7: movabs $0x7ffff6e09878,%rsi
    0x00007fffe10101e1: movabs $0x0,%rdx
    0x00007fffe10101eb: callq  0x00007fffe10101f5
    0x00007fffe10101f0: jmpq   0x00007fffe1010288
    0x00007fffe10101f5: lea    0x8(%rsp),%rax
    0x00007fffe10101fa: mov    %r13,-0x38(%rbp)
    0x00007fffe10101fe: mov    %r15,%rdi
    0x00007fffe1010201: mov    %rbp,0x200(%r15)
    0x00007fffe1010208: mov    %rax,0x1f0(%r15)
    0x00007fffe101020f: test   $0xf,%esp
    0x00007fffe1010215: je     0x00007fffe101022d
    0x00007fffe101021b: sub    $0x8,%rsp
    0x00007fffe101021f: callq  0x00007ffff66b3fbc
    0x00007fffe1010224: add    $0x8,%rsp
    0x00007fffe1010228: jmpq   0x00007fffe1010232
    0x00007fffe101022d: callq  0x00007ffff66b3fbc
    0x00007fffe1010232: movabs $0x0,%r10
    0x00007fffe101023c: mov    %r10,0x1f0(%r15)
    0x00007fffe1010243: movabs $0x0,%r10
    0x00007fffe101024d: mov    %r10,0x200(%r15)
    0x00007fffe1010254: cmpq   $0x0,0x8(%r15)
    0x00007fffe101025c: je     0x00007fffe1010267
    0x00007fffe1010262: jmpq   0x00007fffe1000420
    0x00007fffe1010267: mov    0x250(%r15),%rax
    0x00007fffe101026e: movabs $0x0,%r10
    0x00007fffe1010278: mov    %r10,0x250(%r15)
    0x00007fffe101027f: mov    -0x38(%rbp),%r13
    0x00007fffe1010283: mov    -0x30(%rbp),%r14
    0x00007fffe1010287: retq   
    0x00007fffe1010288: jmpq   0x00007fffe100f3d3
    

    在这里的重点不是读懂TemplateInterpreterGenerator::generate_exception_handler_common()函数的逻辑及生成的汇编代码,而是要清楚知道CodeletMark的应用,以及generate_exception_handler_common()函数生成的机器指令是如何写入InterpreterCodelet实例中的。之前介绍过InterpreterCodelet与CodeBuffer类,如下: 

    通过CodeBuffer操作InterpreterCodelet实例的存储机器指令片段的内存区域,而CodeBuffer中的代码部分(CodeSection)被赋值给AbstractAssembler::_code_section。这样我们就可以通过_code_section属性向InterpreterCodelet实例中写入机器指令了。

    向CodeletMark中传入的_masm参数定义在AbstractInterpreterGenerator类中,如下:

    class AbstractInterpreterGenerator: public StackObj {
       protected:
          InterpreterMacroAssembler* _masm;
          // ...
    }
    

    generate_exception_handler_common()函数中的__是一个宏,定义如下:

    #define __ _masm->
    

    这样其实就是调用InterpreterMacroAssembler类中的相关函数写机器指令,例如

    __ pop(c_rarg2);

    调用的pop()函数如下:

    // 定义在InterpreterMacroAssembler中
    void pop(Register r ) {
      ((MacroAssembler*)this)->pop(r);
    }
    
    // 定义在Assembler类中
    void Assembler::pop(Register dst) {
      int encode = prefix_and_encode(dst->encoding());
      emit_int8(0x58 | encode);
    }
    
    // 定义在AbstractAssembler类中
    void emit_int8(   int8_t  x) { 
       code_section()->emit_int8(   x); 
    }
    

    code_section()函数获取的就是AbstractAssembler的_code_section属性的值。  

    推荐阅读:

    第1篇-关于JVM运行时,开篇说的简单些

    第2篇-JVM虚拟机这样来调用Java主类的main()方法

    第3篇-CallStub新栈帧的创建

    第4篇-JVM终于开始调用Java主类的main()方法啦

    第5篇-调用Java方法后弹出栈帧及处理返回结果

    第6篇-Java方法新栈帧的创建

    第7篇-为Java方法创建栈帧

    第8篇-dispatch_next()函数分派字节码

    第9篇-字节码指令的定义

    第10篇-初始化模板表

    第11篇-认识Stub与StubQueue

    第12篇-认识CodeletMark

    如果有问题可直接评论留言或加作者微信mazhimazh

    关注公众号,有HotSpot VM源码剖析系列文章!

     

  • 相关阅读:
    我的Firefox
    九成偏股基金净值增长弱于大盘 仅18只跑赢指数
    大事记:
    Symantec AntiVirus企业版(接受管理)客户机端卸载方法
    CDP
    两行代码解决iOS上拉下拉时,底部栏顶部栏跟随手势滚动
    8Windows概要
    4断点和单步执行
    win7下windbg本机内核调试
    windbg技巧看和改标志位创建进程时断下
  • 原文地址:https://www.cnblogs.com/mazhimazhi/p/15206153.html
Copyright © 2011-2022 走看看