src/hotspot/share/code/icBuffer.cpp
changeset 52857 7e268f863ff0
parent 52384 d6dc479bcdd3
child 52896 98408c7c0b73
equal deleted inserted replaced
52856:5f3b9b633731 52857:7e268f863ff0
    40 #include "runtime/stubRoutines.hpp"
    40 #include "runtime/stubRoutines.hpp"
    41 
    41 
    42 DEF_STUB_INTERFACE(ICStub);
    42 DEF_STUB_INTERFACE(ICStub);
    43 
    43 
    44 StubQueue* InlineCacheBuffer::_buffer    = NULL;
    44 StubQueue* InlineCacheBuffer::_buffer    = NULL;
    45 ICStub*    InlineCacheBuffer::_next_stub = NULL;
       
    46 
    45 
    47 CompiledICHolder* InlineCacheBuffer::_pending_released = NULL;
    46 CompiledICHolder* InlineCacheBuffer::_pending_released = NULL;
    48 int InlineCacheBuffer::_pending_count = 0;
    47 int InlineCacheBuffer::_pending_count = 0;
       
    48 DEBUG_ONLY(volatile int InlineCacheBuffer::_needs_refill = 0;)
    49 
    49 
    50 void ICStub::finalize() {
    50 void ICStub::finalize() {
    51   if (!is_empty()) {
    51   if (!is_empty()) {
    52     ResourceMark rm;
    52     ResourceMark rm;
    53     CompiledIC *ic = CompiledIC_at(CodeCache::find_compiled(ic_site()), ic_site());
    53     CompiledIC *ic = CompiledIC_at(CodeCache::find_compiled(ic_site()), ic_site());
   101 #endif
   101 #endif
   102 
   102 
   103 //-----------------------------------------------------------------------------------------------
   103 //-----------------------------------------------------------------------------------------------
   104 // Implementation of InlineCacheBuffer
   104 // Implementation of InlineCacheBuffer
   105 
   105 
   106 void InlineCacheBuffer::init_next_stub() {
       
   107   ICStub* ic_stub = (ICStub*)buffer()->request_committed (ic_stub_code_size());
       
   108   assert (ic_stub != NULL, "no room for a single stub");
       
   109   set_next_stub(ic_stub);
       
   110 }
       
   111 
   106 
   112 void InlineCacheBuffer::initialize() {
   107 void InlineCacheBuffer::initialize() {
   113   if (_buffer != NULL) return; // already initialized
   108   if (_buffer != NULL) return; // already initialized
   114   _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer");
   109   _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer");
   115   assert (_buffer != NULL, "cannot allocate InlineCacheBuffer");
   110   assert (_buffer != NULL, "cannot allocate InlineCacheBuffer");
   116   init_next_stub();
       
   117 }
   111 }
   118 
   112 
   119 
   113 
   120 ICStub* InlineCacheBuffer::new_ic_stub() {
   114 ICStub* InlineCacheBuffer::new_ic_stub() {
   121   while (true) {
   115   return (ICStub*)buffer()->request_committed(ic_stub_code_size());
   122     ICStub* ic_stub = (ICStub*)buffer()->request_committed(ic_stub_code_size());
   116 }
   123     if (ic_stub != NULL) {
   117 
   124       return ic_stub;
   118 
   125     }
   119 void InlineCacheBuffer::refill_ic_stubs() {
   126     // we ran out of inline cache buffer space; must enter safepoint.
   120   DEBUG_ONLY(Atomic::store(0, &_needs_refill));
   127     // We do this by forcing a safepoint
   121   // we ran out of inline cache buffer space; must enter safepoint.
   128     EXCEPTION_MARK;
   122   // We do this by forcing a safepoint
   129 
   123   EXCEPTION_MARK;
   130     VM_ICBufferFull ibf;
   124 
   131     VMThread::execute(&ibf);
   125   VM_ICBufferFull ibf;
   132     // We could potential get an async. exception at this point.
   126   VMThread::execute(&ibf);
   133     // In that case we will rethrow it to ourselvs.
   127   // We could potential get an async. exception at this point.
   134     if (HAS_PENDING_EXCEPTION) {
   128   // In that case we will rethrow it to ourselvs.
   135       oop exception = PENDING_EXCEPTION;
   129   if (HAS_PENDING_EXCEPTION) {
   136       CLEAR_PENDING_EXCEPTION;
   130     oop exception = PENDING_EXCEPTION;
   137       Thread::send_async_exception(JavaThread::current()->threadObj(), exception);
   131     CLEAR_PENDING_EXCEPTION;
   138     }
   132     Thread::send_async_exception(JavaThread::current()->threadObj(), exception);
   139   }
   133   }
   140   ShouldNotReachHere();
       
   141   return NULL;
       
   142 }
   134 }
   143 
   135 
   144 
   136 
   145 void InlineCacheBuffer::update_inline_caches() {
   137 void InlineCacheBuffer::update_inline_caches() {
   146   if (buffer()->number_of_stubs() > 1) {
   138   assert(_needs_refill == 0,
       
   139          "Forgot to handle a failed IC transition requiring IC stubs");
       
   140   if (buffer()->number_of_stubs() > 0) {
   147     if (TraceICBuffer) {
   141     if (TraceICBuffer) {
   148       tty->print_cr("[updating inline caches with %d stubs]", buffer()->number_of_stubs());
   142       tty->print_cr("[updating inline caches with %d stubs]", buffer()->number_of_stubs());
   149     }
   143     }
   150     buffer()->remove_all();
   144     buffer()->remove_all();
   151     init_next_stub();
       
   152   }
   145   }
   153   release_pending_icholders();
   146   release_pending_icholders();
   154 }
   147 }
   155 
   148 
   156 
   149 
   158   return buffer()->contains(instruction_address);
   151   return buffer()->contains(instruction_address);
   159 }
   152 }
   160 
   153 
   161 
   154 
   162 bool InlineCacheBuffer::is_empty() {
   155 bool InlineCacheBuffer::is_empty() {
   163   return buffer()->number_of_stubs() == 1;    // always has sentinel
   156   return buffer()->number_of_stubs() == 0;
   164 }
   157 }
   165 
   158 
   166 
   159 
   167 void InlineCacheBuffer_init() {
   160 void InlineCacheBuffer_init() {
   168   InlineCacheBuffer::initialize();
   161   InlineCacheBuffer::initialize();
   169 }
   162 }
   170 
   163 
   171 
   164 
   172 void InlineCacheBuffer::create_transition_stub(CompiledIC *ic, void* cached_value, address entry) {
   165 bool InlineCacheBuffer::create_transition_stub(CompiledIC *ic, void* cached_value, address entry) {
   173   MutexLockerEx ml(CompiledIC_lock->owned_by_self() ? NULL : CompiledIC_lock);
       
   174   assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint");
   166   assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint");
   175   assert(CompiledICLocker::is_safe(ic->instruction_address()), "mt unsafe call");
   167   assert(CompiledICLocker::is_safe(ic->instruction_address()), "mt unsafe call");
   176   if (TraceICBuffer) {
   168   if (TraceICBuffer) {
   177     tty->print_cr("  create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT,
   169     tty->print_cr("  create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT,
   178                   p2i(ic->instruction_address()), p2i(entry), p2i(cached_value));
   170                   p2i(ic->instruction_address()), p2i(entry), p2i(cached_value));
   179   }
   171   }
   180 
   172 
       
   173   // allocate and initialize new "out-of-line" inline-cache
       
   174   ICStub* ic_stub = new_ic_stub();
       
   175   if (ic_stub == NULL) {
       
   176     DEBUG_ONLY(Atomic::inc(&_needs_refill));
       
   177     return false;
       
   178   }
       
   179 
   181   // If an transition stub is already associate with the inline cache, then we remove the association.
   180   // If an transition stub is already associate with the inline cache, then we remove the association.
   182   if (ic->is_in_transition_state()) {
   181   if (ic->is_in_transition_state()) {
   183     ICStub* old_stub = ICStub_from_destination_address(ic->stub_address());
   182     ICStub* old_stub = ICStub_from_destination_address(ic->stub_address());
   184     old_stub->clear();
   183     old_stub->clear();
   185   }
   184   }
   186 
   185 
   187   // allocate and initialize new "out-of-line" inline-cache
       
   188   ICStub* ic_stub = get_next_stub();
       
   189   ic_stub->set_stub(ic, cached_value, entry);
   186   ic_stub->set_stub(ic, cached_value, entry);
   190 
   187 
   191   // Update inline cache in nmethod to point to new "out-of-line" allocated inline cache
   188   // Update inline cache in nmethod to point to new "out-of-line" allocated inline cache
   192   ic->set_ic_destination(ic_stub);
   189   ic->set_ic_destination(ic_stub);
   193 
   190   return true;
   194   set_next_stub(new_ic_stub()); // can cause safepoint synchronization
       
   195 }
   191 }
   196 
   192 
   197 
   193 
   198 address InlineCacheBuffer::ic_destination_for(CompiledIC *ic) {
   194 address InlineCacheBuffer::ic_destination_for(CompiledIC *ic) {
   199   ICStub* stub = ICStub_from_destination_address(ic->stub_address());
   195   ICStub* stub = ICStub_from_destination_address(ic->stub_address());
   223 
   219 
   224 // Enqueue this icholder for release during the next safepoint.  It's
   220 // Enqueue this icholder for release during the next safepoint.  It's
   225 // not safe to free them until them since they might be visible to
   221 // not safe to free them until them since they might be visible to
   226 // another thread.
   222 // another thread.
   227 void InlineCacheBuffer::queue_for_release(CompiledICHolder* icholder) {
   223 void InlineCacheBuffer::queue_for_release(CompiledICHolder* icholder) {
   228   MutexLockerEx mex1((CompiledIC_lock->owned_by_self() ||
   224   MutexLockerEx mex(InlineCacheBuffer_lock, Mutex::_no_safepoint_check_flag);
   229                       SafepointSynchronize::is_at_safepoint()) ? NULL : CompiledIC_lock);
       
   230   MutexLockerEx mex2(InlineCacheBuffer_lock);
       
   231   icholder->set_next(_pending_released);
   225   icholder->set_next(_pending_released);
   232   _pending_released = icholder;
   226   _pending_released = icholder;
   233   _pending_count++;
   227   _pending_count++;
   234   if (TraceICBuffer) {
   228   if (TraceICBuffer) {
   235     tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", p2i(icholder));
   229     tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", p2i(icholder));