duke@435: /* trims@1907: * Copyright (c) 1997, 2006, Oracle and/or its affiliates. All rights reserved. duke@435: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. duke@435: * duke@435: * This code is free software; you can redistribute it and/or modify it duke@435: * under the terms of the GNU General Public License version 2 only, as duke@435: * published by the Free Software Foundation. duke@435: * duke@435: * This code is distributed in the hope that it will be useful, but WITHOUT duke@435: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or duke@435: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License duke@435: * version 2 for more details (a copy is included in the LICENSE file that duke@435: * accompanied this code). duke@435: * duke@435: * You should have received a copy of the GNU General Public License version duke@435: * 2 along with this work; if not, write to the Free Software Foundation, duke@435: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. duke@435: * trims@1907: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA trims@1907: * or visit www.oracle.com if you need additional information or have any trims@1907: * questions. duke@435: * duke@435: */ duke@435: duke@435: #include "incls/_precompiled.incl" duke@435: #include "incls/_icBuffer.cpp.incl" duke@435: duke@435: duke@435: DEF_STUB_INTERFACE(ICStub); duke@435: duke@435: StubQueue* InlineCacheBuffer::_buffer = NULL; duke@435: ICStub* InlineCacheBuffer::_next_stub = NULL; duke@435: duke@435: duke@435: void ICStub::finalize() { duke@435: if (!is_empty()) { duke@435: ResourceMark rm; duke@435: CompiledIC *ic = CompiledIC_at(ic_site()); duke@435: assert(CodeCache::find_nmethod(ic->instruction_address()) != NULL, "inline cache in non-nmethod?"); duke@435: duke@435: assert(this == ICStub_from_destination_address(ic->stub_address()), "wrong owner of ic buffer"); duke@435: ic->set_cached_oop(cached_oop()); duke@435: ic->set_ic_destination(destination()); duke@435: } duke@435: } duke@435: duke@435: duke@435: address ICStub::destination() const { duke@435: return InlineCacheBuffer::ic_buffer_entry_point(code_begin()); duke@435: } duke@435: duke@435: oop ICStub::cached_oop() const { duke@435: return InlineCacheBuffer::ic_buffer_cached_oop(code_begin()); duke@435: } duke@435: duke@435: duke@435: void ICStub::set_stub(CompiledIC *ic, oop cached_value, address dest_addr) { duke@435: // We cannot store a pointer to the 'ic' object, since it is resource allocated. Instead we duke@435: // store the location of the inline cache. Then we have enough information recreate the CompiledIC duke@435: // object when we need to remove the stub. duke@435: _ic_site = ic->instruction_address(); duke@435: duke@435: // Assemble new stub duke@435: InlineCacheBuffer::assemble_ic_buffer_code(code_begin(), cached_value, dest_addr); duke@435: assert(destination() == dest_addr, "can recover destination"); duke@435: assert(cached_oop() == cached_value, "can recover destination"); duke@435: } duke@435: duke@435: duke@435: void ICStub::clear() { duke@435: _ic_site = NULL; duke@435: } duke@435: duke@435: duke@435: #ifndef PRODUCT duke@435: // anybody calling to this stub will trap duke@435: duke@435: void ICStub::verify() { duke@435: } duke@435: duke@435: void ICStub::print() { duke@435: tty->print_cr("ICStub: site: " INTPTR_FORMAT, _ic_site); duke@435: } duke@435: #endif duke@435: duke@435: //----------------------------------------------------------------------------------------------- duke@435: // Implementation of InlineCacheBuffer duke@435: duke@435: void InlineCacheBuffer::init_next_stub() { duke@435: ICStub* ic_stub = (ICStub*)buffer()->request_committed (ic_stub_code_size()); duke@435: assert (ic_stub != NULL, "no room for a single stub"); duke@435: set_next_stub(ic_stub); duke@435: } duke@435: duke@435: void InlineCacheBuffer::initialize() { duke@435: if (_buffer != NULL) return; // already initialized duke@435: _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer"); duke@435: assert (_buffer != NULL, "cannot allocate InlineCacheBuffer"); duke@435: init_next_stub(); duke@435: } duke@435: duke@435: duke@435: ICStub* InlineCacheBuffer::new_ic_stub() { duke@435: while (true) { duke@435: ICStub* ic_stub = (ICStub*)buffer()->request_committed(ic_stub_code_size()); duke@435: if (ic_stub != NULL) { duke@435: return ic_stub; duke@435: } duke@435: // we ran out of inline cache buffer space; must enter safepoint. duke@435: // We do this by forcing a safepoint duke@435: EXCEPTION_MARK; duke@435: duke@435: VM_ForceSafepoint vfs; duke@435: VMThread::execute(&vfs); duke@435: // We could potential get an async. exception at this point. duke@435: // In that case we will rethrow it to ourselvs. duke@435: if (HAS_PENDING_EXCEPTION) { duke@435: oop exception = PENDING_EXCEPTION; duke@435: CLEAR_PENDING_EXCEPTION; duke@435: Thread::send_async_exception(JavaThread::current()->threadObj(), exception); duke@435: } duke@435: } duke@435: ShouldNotReachHere(); duke@435: return NULL; duke@435: } duke@435: duke@435: duke@435: void InlineCacheBuffer::update_inline_caches() { duke@435: if (buffer()->number_of_stubs() > 1) { duke@435: if (TraceICBuffer) { duke@435: tty->print_cr("[updating inline caches with %d stubs]", buffer()->number_of_stubs()); duke@435: } duke@435: buffer()->remove_all(); duke@435: init_next_stub(); duke@435: } duke@435: } duke@435: duke@435: duke@435: bool InlineCacheBuffer::contains(address instruction_address) { duke@435: return buffer()->contains(instruction_address); duke@435: } duke@435: duke@435: duke@435: bool InlineCacheBuffer::is_empty() { duke@435: return buffer()->number_of_stubs() == 1; // always has sentinel duke@435: } duke@435: duke@435: duke@435: void InlineCacheBuffer_init() { duke@435: InlineCacheBuffer::initialize(); duke@435: } duke@435: duke@435: duke@435: void InlineCacheBuffer::create_transition_stub(CompiledIC *ic, oop cached_oop, address entry) { duke@435: assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint"); duke@435: assert (CompiledIC_lock->is_locked(), ""); duke@435: assert(cached_oop == NULL || cached_oop->is_perm(), "must belong to perm. space"); duke@435: if (TraceICBuffer) { tty->print_cr(" create transition stub for " INTPTR_FORMAT, ic->instruction_address()); } duke@435: duke@435: // If an transition stub is already associate with the inline cache, then we remove the association. duke@435: if (ic->is_in_transition_state()) { duke@435: ICStub* old_stub = ICStub_from_destination_address(ic->stub_address()); duke@435: old_stub->clear(); duke@435: } duke@435: duke@435: // allocate and initialize new "out-of-line" inline-cache duke@435: ICStub* ic_stub = get_next_stub(); duke@435: ic_stub->set_stub(ic, cached_oop, entry); duke@435: duke@435: // Update inline cache in nmethod to point to new "out-of-line" allocated inline cache duke@435: ic->set_ic_destination(ic_stub->code_begin()); duke@435: duke@435: set_next_stub(new_ic_stub()); // can cause safepoint synchronization duke@435: } duke@435: duke@435: duke@435: address InlineCacheBuffer::ic_destination_for(CompiledIC *ic) { duke@435: ICStub* stub = ICStub_from_destination_address(ic->stub_address()); duke@435: return stub->destination(); duke@435: } duke@435: duke@435: duke@435: oop InlineCacheBuffer::cached_oop_for(CompiledIC *ic) { duke@435: ICStub* stub = ICStub_from_destination_address(ic->stub_address()); duke@435: return stub->cached_oop(); duke@435: }