< prev index next >

src/hotspot/share/c1/c1_LIRAssembler.cpp

Print this page
@@ -28,14 +28,16 @@
  #include "c1/c1_Instruction.hpp"
  #include "c1/c1_InstructionPrinter.hpp"
  #include "c1/c1_LIRAssembler.hpp"
  #include "c1/c1_MacroAssembler.hpp"
  #include "c1/c1_ValueStack.hpp"
+ #include "ci/ciInlineKlass.hpp"
  #include "ci/ciInstance.hpp"
  #include "compiler/oopMap.hpp"
  #include "gc/shared/barrierSet.hpp"
  #include "runtime/os.hpp"
+ #include "runtime/sharedRuntime.hpp"
  #include "runtime/vm_version.hpp"
  
  void LIR_Assembler::patching_epilog(PatchingStub* patch, LIR_PatchCode patch_code, Register obj, CodeEmitInfo* info) {
    // We must have enough patching space so that call can be inserted.
    // We cannot use fat nops here, since the concurrent code rewrite may transiently

@@ -52,17 +54,19 @@
      switch (code) {
        case Bytecodes::_putstatic:
        case Bytecodes::_getstatic:
        case Bytecodes::_putfield:
        case Bytecodes::_getfield:
+       case Bytecodes::_withfield:
          break;
        default:
          ShouldNotReachHere();
      }
    } else if (patch->id() == PatchingStub::load_klass_id) {
      switch (code) {
        case Bytecodes::_new:
+       case Bytecodes::_defaultvalue:
        case Bytecodes::_anewarray:
        case Bytecodes::_multianewarray:
        case Bytecodes::_instanceof:
        case Bytecodes::_checkcast:
          break;

@@ -115,10 +119,11 @@
  
  LIR_Assembler::~LIR_Assembler() {
    // The unwind handler label may be unnbound if this destructor is invoked because of a bail-out.
    // Reset it here to avoid an assertion.
    _unwind_handler_entry.reset();
+   _verified_inline_entry.reset();
  }
  
  
  void LIR_Assembler::check_codespace() {
    CodeSection* cs = _masm->code_section();

@@ -325,24 +330,22 @@
  }
  #endif
  
  //----------------------------------debug info--------------------------------
  
- 
  void LIR_Assembler::add_debug_info_for_branch(CodeEmitInfo* info) {
    int pc_offset = code_offset();
    flush_debug_info(pc_offset);
    info->record_debug_info(compilation()->debug_info_recorder(), pc_offset);
    if (info->exception_handlers() != NULL) {
      compilation()->add_exception_handlers_for_pco(pc_offset, info->exception_handlers());
    }
  }
  
- 
- void LIR_Assembler::add_call_info(int pc_offset, CodeEmitInfo* cinfo) {
+ void LIR_Assembler::add_call_info(int pc_offset, CodeEmitInfo* cinfo, bool maybe_return_as_fields) {
    flush_debug_info(pc_offset);
-   cinfo->record_debug_info(compilation()->debug_info_recorder(), pc_offset);
+   cinfo->record_debug_info(compilation()->debug_info_recorder(), pc_offset, maybe_return_as_fields);
    if (cinfo->exception_handlers() != NULL) {
      compilation()->add_exception_handlers_for_pco(pc_offset, cinfo->exception_handlers());
    }
  }
  

@@ -478,10 +481,16 @@
    // Record if this method has MethodHandle invokes.
    if (op->is_method_handle_invoke()) {
      compilation()->set_has_method_handle_invokes(true);
    }
  
+   ciInlineKlass* vk = NULL;
+   if (op->maybe_return_as_fields(&vk)) {
+     int offset = store_inline_type_fields_to_buf(vk);
+     add_call_info(offset, op->info(), true);
+   }
+ 
  #if defined(IA32) && defined(COMPILER2)
    // C2 leave fpu stack dirty clean it
    if (UseSSE < 2 && !CompilerConfig::is_c1_only_no_jvmci()) {
      int i;
      for ( i = 1; i <= 7 ; i++ ) {

@@ -584,10 +593,145 @@
        Unimplemented();
        break;
    }
  }
  
+ void LIR_Assembler::add_scalarized_entry_info(int pc_offset) {
+   flush_debug_info(pc_offset);
+   DebugInformationRecorder* debug_info = compilation()->debug_info_recorder();
+   // The VEP and VIEP(RO) of a C1-compiled method call buffer_inline_args_xxx()
+   // before doing any argument shuffling. This call may cause GC. When GC happens,
+   // all the parameters are still as passed by the caller, so we just use
+   // map->set_include_argument_oops() inside frame::sender_for_compiled_frame(RegisterMap* map).
+   // There's no need to build a GC map here.
+   OopMap* oop_map = new OopMap(0, 0);
+   debug_info->add_safepoint(pc_offset, oop_map);
+   DebugToken* locvals = debug_info->create_scope_values(NULL); // FIXME is this needed (for Java debugging to work properly??)
+   DebugToken* expvals = debug_info->create_scope_values(NULL); // FIXME is this needed (for Java debugging to work properly??)
+   DebugToken* monvals = debug_info->create_monitor_values(NULL); // FIXME: need testing with synchronized method
+   bool reexecute = false;
+   bool return_oop = false; // This flag will be ignored since it used only for C2 with escape analysis.
+   bool rethrow_exception = false;
+   bool is_method_handle_invoke = false;
+   debug_info->describe_scope(pc_offset, methodHandle(), method(), 0, reexecute, rethrow_exception, is_method_handle_invoke, return_oop, false, locvals, expvals, monvals);
+   debug_info->end_safepoint(pc_offset);
+ }
+ 
+ // The entries points of C1-compiled methods can have the following types:
+ // (1) Methods with no inline type args
+ // (2) Methods with inline type receiver but no inline type args
+ //     VIEP_RO is the same as VIEP
+ // (3) Methods with non-inline type receiver and some inline type args
+ //     VIEP_RO is the same as VEP
+ // (4) Methods with inline type receiver and other inline type args
+ //     Separate VEP, VIEP and VIEP_RO
+ //
+ // (1)               (2)                 (3)                    (4)
+ // UEP/UIEP:         VEP:                UEP:                   UEP:
+ //   check_icache      pack receiver       check_icache           check_icache
+ // VEP/VIEP/VIEP_RO    jump to VIEP      VEP/VIEP_RO:           VIEP_RO:
+ //   body            UEP/UIEP:             pack inline args       pack inline args (except receiver)
+ //                     check_icache        jump to VIEP           jump to VIEP
+ //                   VIEP/VIEP_RO        UIEP:                  VEP:
+ //                     body                check_icache           pack all inline args
+ //                                       VIEP:                    jump to VIEP
+ //                                         body                 UIEP:
+ //                                                                check_icache
+ //                                                              VIEP:
+ //                                                                body
+ void LIR_Assembler::emit_std_entries() {
+   offsets()->set_value(CodeOffsets::OSR_Entry, _masm->offset());
+ 
+   _masm->align(CodeEntryAlignment);
+   const CompiledEntrySignature* ces = compilation()->compiled_entry_signature();
+   if (ces->has_scalarized_args()) {
+     assert(InlineTypePassFieldsAsArgs && method()->get_Method()->has_scalarized_args(), "must be");
+     CodeOffsets::Entries ro_entry_type = ces->c1_inline_ro_entry_type();
+ 
+     // UEP: check icache and fall-through
+     if (ro_entry_type != CodeOffsets::Verified_Inline_Entry) {
+       offsets()->set_value(CodeOffsets::Entry, _masm->offset());
+       if (needs_icache(method())) {
+         check_icache();
+       }
+     }
+ 
+     // VIEP_RO: pack all value parameters, except the receiver
+     if (ro_entry_type == CodeOffsets::Verified_Inline_Entry_RO) {
+       emit_std_entry(CodeOffsets::Verified_Inline_Entry_RO, ces);
+     }
+ 
+     // VEP: pack all value parameters
+     _masm->align(CodeEntryAlignment);
+     emit_std_entry(CodeOffsets::Verified_Entry, ces);
+ 
+     // UIEP: check icache and fall-through
+     _masm->align(CodeEntryAlignment);
+     offsets()->set_value(CodeOffsets::Inline_Entry, _masm->offset());
+     if (ro_entry_type == CodeOffsets::Verified_Inline_Entry) {
+       // Special case if we have VIEP == VIEP(RO):
+       // this means UIEP (called by C1) == UEP (called by C2).
+       offsets()->set_value(CodeOffsets::Entry, _masm->offset());
+     }
+     if (needs_icache(method())) {
+       check_icache();
+     }
+ 
+     // VIEP: all value parameters are passed as refs - no packing.
+     emit_std_entry(CodeOffsets::Verified_Inline_Entry, NULL);
+ 
+     if (ro_entry_type != CodeOffsets::Verified_Inline_Entry_RO) {
+       // The VIEP(RO) is the same as VEP or VIEP
+       assert(ro_entry_type == CodeOffsets::Verified_Entry ||
+              ro_entry_type == CodeOffsets::Verified_Inline_Entry, "must be");
+       offsets()->set_value(CodeOffsets::Verified_Inline_Entry_RO,
+                            offsets()->value(ro_entry_type));
+     }
+   } else {
+     // All 3 entries are the same (no inline type packing)
+     offsets()->set_value(CodeOffsets::Entry, _masm->offset());
+     offsets()->set_value(CodeOffsets::Inline_Entry, _masm->offset());
+     if (needs_icache(method())) {
+       check_icache();
+     }
+     emit_std_entry(CodeOffsets::Verified_Inline_Entry, NULL);
+     offsets()->set_value(CodeOffsets::Verified_Entry, offsets()->value(CodeOffsets::Verified_Inline_Entry));
+     offsets()->set_value(CodeOffsets::Verified_Inline_Entry_RO, offsets()->value(CodeOffsets::Verified_Inline_Entry));
+   }
+ }
+ 
+ void LIR_Assembler::emit_std_entry(CodeOffsets::Entries entry, const CompiledEntrySignature* ces) {
+   offsets()->set_value(entry, _masm->offset());
+   _masm->verified_entry();
+   switch (entry) {
+   case CodeOffsets::Verified_Entry: {
+     if (needs_clinit_barrier_on_entry(method())) {
+       clinit_barrier(method());
+     }
+     int rt_call_offset = _masm->verified_entry(ces, initial_frame_size_in_bytes(), bang_size_in_bytes(), in_bytes(frame_map()->sp_offset_for_orig_pc()), _verified_inline_entry);
+     add_scalarized_entry_info(rt_call_offset);
+     break;
+   }
+   case CodeOffsets::Verified_Inline_Entry_RO: {
+     assert(!needs_clinit_barrier_on_entry(method()), "can't be static");
+     int rt_call_offset = _masm->verified_inline_ro_entry(ces, initial_frame_size_in_bytes(), bang_size_in_bytes(), in_bytes(frame_map()->sp_offset_for_orig_pc()), _verified_inline_entry);
+     add_scalarized_entry_info(rt_call_offset);
+     break;
+   }
+   case CodeOffsets::Verified_Inline_Entry: {
+     if (needs_clinit_barrier_on_entry(method())) {
+       clinit_barrier(method());
+     }
+     build_frame();
+     offsets()->set_value(CodeOffsets::Frame_Complete, _masm->offset());
+     break;
+   }
+   default:
+     ShouldNotReachHere();
+     break;
+   }
+ }
  
  void LIR_Assembler::emit_op0(LIR_Op0* op) {
    switch (op->code()) {
      case lir_nop:
        assert(op->info() == NULL, "not supported");

@@ -597,23 +741,11 @@
      case lir_label:
        Unimplemented();
        break;
  
      case lir_std_entry:
-       // init offsets
-       offsets()->set_value(CodeOffsets::OSR_Entry, _masm->offset());
-       _masm->align(CodeEntryAlignment);
-       if (needs_icache(compilation()->method())) {
-         check_icache();
-       }
-       offsets()->set_value(CodeOffsets::Verified_Entry, _masm->offset());
-       _masm->verified_entry();
-       if (needs_clinit_barrier_on_entry(compilation()->method())) {
-         clinit_barrier(compilation()->method());
-       }
-       build_frame();
-       offsets()->set_value(CodeOffsets::Frame_Complete, _masm->offset());
+       emit_std_entries();
        break;
  
      case lir_osr_entry:
        offsets()->set_value(CodeOffsets::OSR_Entry, _masm->offset());
        osr_entry();

@@ -663,10 +795,14 @@
  
      case lir_on_spin_wait:
        on_spin_wait();
        break;
  
+     case lir_check_orig_pc:
+       check_orig_pc();
+       break;
+ 
      default:
        ShouldNotReachHere();
        break;
    }
  }

@@ -754,11 +890,12 @@
    }
  }
  
  
  void LIR_Assembler::build_frame() {
-   _masm->build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes());
+   _masm->build_frame(initial_frame_size_in_bytes(), bang_size_in_bytes(), in_bytes(frame_map()->sp_offset_for_orig_pc()),
+                      needs_stack_repair(), method()->has_scalarized_args(), &_verified_inline_entry);
  }
  
  
  void LIR_Assembler::roundfp_op(LIR_Opr src, LIR_Opr tmp, LIR_Opr dest, bool pop_fpu_stack) {
    assert(strict_fp_requires_explicit_rounding, "not required");
< prev index next >