Exemplo n.º 1
0
  //------------------------------------------------------------------------------------------------------------------------
  // Continuation point for throwing of implicit exceptions that are not handled in
  // the current activation. Fabricates an exception oop and initiates normal
  // exception dispatching in this frame. Only callee-saved registers are preserved
  // (through the normal register window / RegisterMap handling).
  // If the compiler needs all registers to be preserved between the fault
  // point and the exception handler then it must assume responsibility for that in
  // AbstractCompiler::continuation_for_implicit_null_exception or
  // continuation_for_implicit_division_by_zero_exception. All other implicit
  // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are
  // either at call sites or otherwise assume that stack unwinding will be initiated,
  // so caller saved registers were assumed volatile in the compiler.
  //
  address generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc) {
    int insts_size = VerifyThread ? 1 * K : 512;
    int locs_size  = 32;

    CodeBuffer code(name, insts_size, locs_size);
    MacroAssembler* _masm = new MacroAssembler(&code);

    const Register saved_exception_pc_addr = GR31_SCRATCH;
    const Register continuation            = GR30_SCRATCH;

    const Register saved_exception_pc      = GR31_SCRATCH;

    const BranchRegister continuation_br   = BR6_SCRATCH;

    // 4826555: nsk test stack016 fails.  See os_linux_ia64.cpp.
    // Reload register stack limit because the Linux kernel
    // doesn't reload GR4-7 from the ucontext.
    __ add(GR7_reg_stack_limit, thread_(register_stack_limit));
    __ ld8(GR7_reg_stack_limit, GR7_reg_stack_limit);

//  __ verify_thread();

    // If the exception occured at a call site target, RP contains the return address
    // (which is also the exception PC), and the call instruction has pushed a degenerate
    // register frame.  If the exception happened elsewhere, the signal handler has saved
    // the exception address in the thread state and we must execute a call instruction
    // in order to obtain a degenerate frame.  In either case, we must then push a frame
    // so we can execute a call_VM.

    if (restore_saved_exception_pc) {
      __ add(saved_exception_pc_addr, thread_(saved_exception_pc));
      __ ld8(saved_exception_pc, saved_exception_pc_addr);
      __ push_dummy_full_frame(saved_exception_pc);
    } else {
      __ push_full_frame();
    }

    // Install the exception oop in the thread state, etc.
    __ call_VM(noreg, runtime_entry);

    // Scale back to a thin frame for forward_exception.
    __ pop_full_to_thin_frame();

    // Branch to forward_exception.
    __ mova(continuation, StubRoutines::forward_exception_entry());
    __ mov(continuation_br, continuation);
    __ br(continuation_br);

    __ flush_bundle();

    RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, &code, CodeBlob::frame_never_safe, 0, NULL, false);
    return stub->entry_point();
  }
  //------------------------------------------------------------------------------------------------------------------------
  // Continuation point for throwing of implicit exceptions that are not handled in
  // the current activation. Fabricates an exception oop and initiates normal
  // exception dispatching in this frame. Since we need to preserve callee-saved values
  // (currently only for C2, but done for C1 as well) we need a callee-saved oop map and
  // therefore have to make these stubs into RuntimeStubs rather than BufferBlobs.
  // If the compiler needs all registers to be preserved between the fault
  // point and the exception handler then it must assume responsibility for that in
  // AbstractCompiler::continuation_for_implicit_null_exception or
  // continuation_for_implicit_division_by_zero_exception. All other implicit
  // exceptions (e.g., NullPointerException or AbstractMethodError on entry) are
  // either at call sites or otherwise assume that stack unwinding will be initiated,
  // so caller saved registers were assumed volatile in the compiler.
  //
  // Note: the routine set_pc_not_at_call_for_caller in SharedRuntime.cpp requires
  // that this code be generated into a RuntimeStub.
  address StubGenerator::generate_throw_exception(const char* name, address runtime_entry, bool restore_saved_exception_pc) {

    int insts_size = 256;
    int locs_size  = 32;

    CodeBuffer* code     = new CodeBuffer(insts_size, locs_size, 0, 0, 0, false, NULL, NULL, NULL, false, NULL, name, false);
    OopMapSet* oop_maps  = new OopMapSet();
    MacroAssembler* masm = new MacroAssembler(code);

    address start = __ pc();

    // This is an inlined and slightly modified version of call_VM
    // which has the ability to fetch the return PC out of
    // thread-local storage and also sets up last_Java_sp slightly
    // differently than the real call_VM
    Register java_thread = ebx;
    __ get_thread(java_thread);
    if (restore_saved_exception_pc) {
      __ movl(eax, Address(java_thread, in_bytes(JavaThread::saved_exception_pc_offset())));
      __ pushl(eax);
    }
      
#ifndef COMPILER2
    __ enter(); // required for proper stackwalking of RuntimeStub frame
#endif COMPILER2

    __ subl(esp, framesize * wordSize); // prolog

#ifdef COMPILER2
    if( OptoRuntimeCalleeSavedFloats ) {
      if( UseSSE == 1 ) {
        __ movss(Address(esp,xmm6_off*wordSize),xmm6);
        __ movss(Address(esp,xmm7_off*wordSize),xmm7);
      } else if( UseSSE == 2 ) {
        __ movsd(Address(esp,xmm6_off*wordSize),xmm6);
        __ movsd(Address(esp,xmm7_off*wordSize),xmm7);
      }
    }
#endif /* COMPILER2 */
    __ movl(Address(esp, ebp_off * wordSize), ebp);
    __ movl(Address(esp, edi_off * wordSize), edi);
    __ movl(Address(esp, esi_off * wordSize), esi);

    // push java thread (becomes first argument of C function)
    __ movl(Address(esp, thread_off * wordSize), java_thread);

    // Set up last_Java_sp and last_Java_fp
    __ set_last_Java_frame(java_thread, esp, ebp, NULL);

    // Call runtime
    __ call(runtime_entry, relocInfo::runtime_call_type);
    // Generate oop map
    OopMap* map =  new OopMap(framesize, 0);        
#ifdef COMPILER2
    // SharedInfo is apparently not initialized if -Xint is specified
    if (UseCompiler) {
      map->set_callee_saved(SharedInfo::stack2reg(ebp_off), framesize, 0, OptoReg::Name(EBP_num));
      map->set_callee_saved(SharedInfo::stack2reg(edi_off), framesize, 0, OptoReg::Name(EDI_num));
      map->set_callee_saved(SharedInfo::stack2reg(esi_off), framesize, 0, OptoReg::Name(ESI_num));
      if( OptoRuntimeCalleeSavedFloats ) {
        map->set_callee_saved(SharedInfo::stack2reg(xmm6_off  ), framesize, 0, OptoReg::Name(XMM6a_num));
        map->set_callee_saved(SharedInfo::stack2reg(xmm6_off+1), framesize, 0, OptoReg::Name(XMM6b_num));
        map->set_callee_saved(SharedInfo::stack2reg(xmm7_off  ), framesize, 0, OptoReg::Name(XMM7a_num));
        map->set_callee_saved(SharedInfo::stack2reg(xmm7_off+1), framesize, 0, OptoReg::Name(XMM7b_num));
      }
    }
#endif
#ifdef COMPILER1
    map->set_callee_saved(OptoReg::Name(SharedInfo::stack0+ebp_off), framesize, 0, OptoReg::Name(ebp->encoding()));
    map->set_callee_saved(OptoReg::Name(SharedInfo::stack0+esi_off), framesize, 0, OptoReg::Name(esi->encoding()));
    map->set_callee_saved(OptoReg::Name(SharedInfo::stack0+edi_off), framesize, 0, OptoReg::Name(edi->encoding()));
#endif
    oop_maps->add_gc_map(__ pc() - start, true, map);
      
    // restore the thread (cannot use the pushed argument since arguments
    // may be overwritten by C code generated by an optimizing compiler);
    // however can use the register value directly if it is callee saved.
    __ get_thread(java_thread);

    __ reset_last_Java_frame(java_thread, false);

    // Restore callee save registers.  This must be done after resetting the Java frame
#ifdef COMPILER2
    if( OptoRuntimeCalleeSavedFloats ) {
      if( UseSSE == 1 ) {
        __ movss(xmm6,Address(esp,xmm6_off*wordSize));
        __ movss(xmm7,Address(esp,xmm7_off*wordSize));
      } else if( UseSSE == 2 ) {
        __ movsd(xmm6,Address(esp,xmm6_off*wordSize));
        __ movsd(xmm7,Address(esp,xmm7_off*wordSize));
      }
    }
#endif /* COMPILER2 */
    __ movl(ebp,Address(esp, ebp_off * wordSize));
    __ movl(edi,Address(esp, edi_off * wordSize));
    __ movl(esi,Address(esp, esi_off * wordSize));

    // discard arguments
    __ addl(esp, framesize * wordSize); // epilog

#ifndef COMPILER2
    __ leave(); // required for proper stackwalking of RuntimeStub frame
#endif COMPILER2

    // check for pending exceptions
#ifdef ASSERT
    Label L;
    __ cmpl(Address(java_thread, Thread::pending_exception_offset()), (int)NULL);
    __ jcc(Assembler::notEqual, L);
    __ should_not_reach_here();
    __ bind(L);
#endif ASSERT
    __ jmp(StubRoutines::forward_exception_entry(), relocInfo::runtime_call_type);

    // Note: it seems the frame size reported to the RuntimeStub has
    // to be incremented by 1 to account for the return PC. It
    // definitely must be one more than the amount by which SP was
    // decremented.
    int extra_words = 1;
#ifdef COMPILER1
    ++extra_words; // Not strictly necessary since C1 ignores frame size and uses link
#endif COMPILER1

    RuntimeStub* stub = RuntimeStub::new_runtime_stub(name, code, framesize + extra_words, oop_maps, false);
    return stub->entry_point();
  }