zoukankan      html  css  js  c++  java
  • Valhalla Calling Convention

    1. 返回值类型

    SharedRuntime::generate_buffered_inline_type_adapter会生成pack和unpack的handler,这两个handler会放到InlineKlass的后面(就像signature handler一样)。pack和unpack是针对buffer object的操作:

    • pack handler:把fields从寄存器打包到buffer object里 [register->buffer]
    • unpack handler:把拆开buffer object,把里面的fields放到寄存器[buffer->register]

    pack handler和unpack handler都要求buffer object必须放到rax。

    InlineTypeReturnedAsFields做的事情是,直接返回fields而不是primitive type reference,相当于返回一个结构体给caller,而不是返回一个对象。它需要修改C1,C2,Interp等各处,并考虑两者交互的情况。

    C1

    C1 return val时候,把val拆开到register

    
    void LIR_Assembler::return_op(LIR_Opr result, C1SafepointPollStub* code_stub) {
      ...
      ciMethod* method = compilation()->method();
      ciType* return_type = method->return_type();
      if (InlineTypeReturnedAsFields && return_type->is_inlinetype()) {
        ciInlineKlass* vk = return_type->as_inline_klass();
        if (vk->can_be_returned_as_fields()) {
    #ifndef _LP64
          Unimplemented();
    #else
          address unpack_handler = vk->unpack_handler();
          assert(unpack_handler != NULL, "must be");
          __ call(RuntimeAddress(unpack_handler));
          // At this point, rax points to the value object (for interpreter or C1 caller).
          // The fields of the object are copied into registers (for C2 caller).
    #endif
        }
      }
      ...
    }
    

    C1 Foo f = call foo,从寄存器里面拿fields,放到f里面

    void LIR_Assembler::emit_call(LIR_OpJavaCall* op) {
      verify_oop_map(op->info());
    
      // must align calls sites, otherwise they can't be updated atomically
      align_call(op->code());
    
      // emit the static call stub stuff out of line
      emit_static_call_stub();
      CHECK_BAILOUT();
    
      switch (op->code()) {
      case lir_static_call:
      case lir_dynamic_call:
        call(op, relocInfo::static_call_type);
        break;
      case lir_optvirtual_call:
        call(op, relocInfo::opt_virtual_call_type);
        break;
      case lir_icvirtual_call:
        ic_call(op);
        break;
      case lir_virtual_call:
        vtable_call(op);
        break;
      default:
        fatal("unexpected op code: %s", op->name());
        break;
      }
    
      // JSR 292
      // Record if this method has MethodHandle invokes.
      if (op->is_method_handle_invoke()) {
        compilation()->set_has_method_handle_invokes(true);
      }
    
      ciInlineKlass* vk;
      if (op->maybe_return_as_fields(&vk)) {
        int offset = store_inline_type_fields_to_buf(vk);
        add_call_info(offset, op->info(), true);
      }
      ...
    }
    
    

    C2

    void Compile::return_values(JVMState* jvms) {
      GraphKit kit(jvms);
      Node* ret = new ReturnNode(TypeFunc::Parms,
                                 kit.control(),
                                 kit.i_o(),
                                 kit.reset_memory(),
                                 kit.frameptr(),
                                 kit.returnadr());
      // Add zero or 1 return values
      int ret_size = tf()->range_sig()->cnt() - TypeFunc::Parms;
      if (ret_size > 0) {
        kit.inc_sp(-ret_size);  // pop the return value(s)
        kit.sync_jvms();
        Node* res = kit.argument(0);
        if (tf()->returns_inline_type_as_fields()) {
          // Multiple return values (inline type fields): add as many edges
          // to the Return node as returned values.
          assert(res->is_InlineType(), "what else supports multi value return?");
          InlineTypeNode* vt = res->as_InlineType();
          ret->add_req_batch(NULL, tf()->range_cc()->cnt() - TypeFunc::Parms);
          if (vt->is_allocated(&kit.gvn()) && !StressInlineTypeReturnedAsFields) {
            ret->init_req(TypeFunc::Parms, vt->get_oop());
          } else {
            ret->init_req(TypeFunc::Parms, vt->tagged_klass(kit.gvn()));
          }
          uint idx = TypeFunc::Parms + 1;
          vt->pass_fields(&kit, ret, idx);
        } else {
          ret->add_req(res);
          // Note:  The second dummy edge is not needed by a ReturnNode.
        }
      }
      // bind it to root
      root()->add_req(ret);
      record_for_igvn(ret);
      initial_gvn()->transform_no_reclaim(ret);
    }
    

    Interp

    (return字节码和throw stub会有remove_activation)
    void InterpreterMacroAssembler::remove_activation(...) {
      ...
    	if (state == atos && InlineTypeReturnedAsFields) {
            Label skip;
            // Test if the return type is an inline type
            movptr(rdi, Address(rbp, frame::interpreter_frame_method_offset * wordSize));
            movptr(rdi, Address(rdi, Method::const_offset()));
            load_unsigned_byte(rdi, Address(rdi, ConstMethod::result_type_offset()));
            cmpl(rdi, T_INLINE_TYPE);
            jcc(Assembler::notEqual, skip);
    
            // We are returning an inline type, load its fields into registers
    #ifndef _LP64
            super_call_VM_leaf(StubRoutines::load_inline_type_fields_in_regs());
    #else
            // Load fields from a buffered value with an inline class specific handler
            Register tmp_load_klass = LP64_ONLY(rscratch1) NOT_LP64(noreg);
            load_klass(rdi, rax, tmp_load_klass);
            movptr(rdi, Address(rdi, InstanceKlass::adr_inlineklass_fixed_block_offset()));
            movptr(rdi, Address(rdi, InlineKlass::unpack_handler_offset()));
    
            testptr(rdi, rdi);
            jcc(Assembler::equal, skip);
    
            call(rdi);
    #endif
            // call above kills the value in rbx. Reload it.
            movptr(rbx, Address(rbp, frame::interpreter_frame_sender_sp_offset * wordSize));
            bind(skip);
        }
        ...
    }
    

    StubGenerator && JavaCalls

    address generate_call_stub(address& return_address) {
      // call java 
      ...
      __ BIND(is_value);
        if (InlineTypeReturnedAsFields) {
          // Check for flattened return value
          __ testptr(rax, 1);
          __ jcc(Assembler::zero, is_long);
          // Load pack handler address
          __ andptr(rax, -2);
          __ movptr(rax, Address(rax, InstanceKlass::adr_inlineklass_fixed_block_offset()));
          __ movptr(rbx, Address(rax, InlineKlass::pack_handler_jobject_offset()));
          // Call pack handler to initialize the buffer
          __ call(rbx);
          __ jmp(exit);
        }
      ...
    }
    
    void JavaCalls::call_helper(...) {
        if (InlineTypeReturnedAsFields && result->get_type() == T_INLINE_TYPE) {
        // Pre allocate a buffered inline type in case the result is returned
        // flattened by compiled code
        InlineKlass* vk = method->returned_inline_type(thread);
        if (vk->can_be_returned_as_fields()) {
          oop instance = vk->allocate_instance(CHECK);
          value_buffer = JNIHandles::make_local(thread, instance);
          result->set_jobject(value_buffer);
        }
      }
    
      // do call
      ...
    }
    

    2. 传入值类型

    InlineTypeReturnedAsFields做的事情是把primitive type的对象的字段当作实参传递,而不是传递这个对象引用。

  • 相关阅读:
    leetcode二叉树翻转二叉树
    编译PBRTv2
    人最大的快乐不是赚多少钱,而是将一个一个的梦想付诸实现。
    今天终于把工作的事定下了安心开始新的学习
    Ogre学习(二)
    关于游戏引擎关于心情
    Ogitor的安装与使用
    软件随想录
    Lost in Island
    OGRE学习(一)
  • 原文地址:https://www.cnblogs.com/kelthuzadx/p/15726437.html
Copyright © 2011-2022 走看看