icBuffer.cpp revision 3883:cd3d6a6b95d9
1/*
2 * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 *
23 */
24
25#include "precompiled.hpp"
26#include "code/codeCache.hpp"
27#include "code/compiledIC.hpp"
28#include "code/icBuffer.hpp"
29#include "code/nmethod.hpp"
30#include "code/scopeDesc.hpp"
31#include "gc_interface/collectedHeap.inline.hpp"
32#include "interpreter/interpreter.hpp"
33#include "interpreter/linkResolver.hpp"
34#include "memory/resourceArea.hpp"
35#include "memory/universe.inline.hpp"
36#include "oops/method.hpp"
37#include "oops/oop.inline.hpp"
38#include "oops/oop.inline2.hpp"
39#include "runtime/mutexLocker.hpp"
40#include "runtime/stubRoutines.hpp"
41
42
43DEF_STUB_INTERFACE(ICStub);
44
45StubQueue* InlineCacheBuffer::_buffer    = NULL;
46ICStub*    InlineCacheBuffer::_next_stub = NULL;
47
48CompiledICHolder* InlineCacheBuffer::_pending_released = NULL;
49int InlineCacheBuffer::_pending_count = 0;
50
51void ICStub::finalize() {
52  if (!is_empty()) {
53    ResourceMark rm;
54    CompiledIC *ic = CompiledIC_at(CodeCache::find_nmethod(ic_site()), ic_site());
55    assert(CodeCache::find_nmethod(ic->instruction_address()) != NULL, "inline cache in non-nmethod?");
56
57    assert(this == ICStub_from_destination_address(ic->stub_address()), "wrong owner of ic buffer");
58    ic->set_ic_destination_and_value(destination(), cached_value());
59  }
60}
61
62
63address ICStub::destination() const {
64  return InlineCacheBuffer::ic_buffer_entry_point(code_begin());
65}
66
67void* ICStub::cached_value() const {
68  return InlineCacheBuffer::ic_buffer_cached_value(code_begin());
69}
70
71
72void ICStub::set_stub(CompiledIC *ic, void* cached_val, address dest_addr) {
73  // We cannot store a pointer to the 'ic' object, since it is resource allocated. Instead we
74  // store the location of the inline cache. Then we have enough information recreate the CompiledIC
75  // object when we need to remove the stub.
76  _ic_site = ic->instruction_address();
77
78  // Assemble new stub
79  InlineCacheBuffer::assemble_ic_buffer_code(code_begin(), cached_val, dest_addr);
80  assert(destination() == dest_addr,   "can recover destination");
81  assert(cached_value() == cached_val, "can recover destination");
82}
83
84
85void ICStub::clear() {
86  if (CompiledIC::is_icholder_entry(destination())) {
87    InlineCacheBuffer::queue_for_release((CompiledICHolder*)cached_value());
88  }
89  _ic_site = NULL;
90}
91
92
93#ifndef PRODUCT
94// anybody calling to this stub will trap
95
96void ICStub::verify() {
97}
98
99void ICStub::print() {
100  tty->print_cr("ICStub: site: " INTPTR_FORMAT, _ic_site);
101}
102#endif
103
104//-----------------------------------------------------------------------------------------------
105// Implementation of InlineCacheBuffer
106
107void InlineCacheBuffer::init_next_stub() {
108  ICStub* ic_stub = (ICStub*)buffer()->request_committed (ic_stub_code_size());
109  assert (ic_stub != NULL, "no room for a single stub");
110  set_next_stub(ic_stub);
111}
112
113void InlineCacheBuffer::initialize() {
114  if (_buffer != NULL) return; // already initialized
115  _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer");
116  assert (_buffer != NULL, "cannot allocate InlineCacheBuffer");
117  init_next_stub();
118}
119
120
121ICStub* InlineCacheBuffer::new_ic_stub() {
122  while (true) {
123    ICStub* ic_stub = (ICStub*)buffer()->request_committed(ic_stub_code_size());
124    if (ic_stub != NULL) {
125      return ic_stub;
126    }
127    // we ran out of inline cache buffer space; must enter safepoint.
128    // We do this by forcing a safepoint
129    EXCEPTION_MARK;
130
131    VM_ForceSafepoint vfs;
132    VMThread::execute(&vfs);
133    // We could potential get an async. exception at this point.
134    // In that case we will rethrow it to ourselvs.
135    if (HAS_PENDING_EXCEPTION) {
136      oop exception = PENDING_EXCEPTION;
137      CLEAR_PENDING_EXCEPTION;
138      Thread::send_async_exception(JavaThread::current()->threadObj(), exception);
139    }
140  }
141  ShouldNotReachHere();
142  return NULL;
143}
144
145
146void InlineCacheBuffer::update_inline_caches() {
147  if (buffer()->number_of_stubs() > 1) {
148    if (TraceICBuffer) {
149      tty->print_cr("[updating inline caches with %d stubs]", buffer()->number_of_stubs());
150    }
151    buffer()->remove_all();
152    init_next_stub();
153  }
154  release_pending_icholders();
155}
156
157
158bool InlineCacheBuffer::contains(address instruction_address) {
159  return buffer()->contains(instruction_address);
160}
161
162
163bool InlineCacheBuffer::is_empty() {
164  return buffer()->number_of_stubs() == 1;    // always has sentinel
165}
166
167
168void InlineCacheBuffer_init() {
169  InlineCacheBuffer::initialize();
170}
171
172
173void InlineCacheBuffer::create_transition_stub(CompiledIC *ic, void* cached_value, address entry) {
174  assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint");
175  assert (CompiledIC_lock->is_locked(), "");
176  if (TraceICBuffer) {
177    tty->print_cr("  create transition stub for " INTPTR_FORMAT " destination " INTPTR_FORMAT " cached value " INTPTR_FORMAT,
178                  ic->instruction_address(), entry, cached_value);
179  }
180
181  // If an transition stub is already associate with the inline cache, then we remove the association.
182  if (ic->is_in_transition_state()) {
183    ICStub* old_stub = ICStub_from_destination_address(ic->stub_address());
184    old_stub->clear();
185  }
186
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);
190
191  // Update inline cache in nmethod to point to new "out-of-line" allocated inline cache
192  ic->set_ic_destination(ic_stub);
193
194  set_next_stub(new_ic_stub()); // can cause safepoint synchronization
195}
196
197
198address InlineCacheBuffer::ic_destination_for(CompiledIC *ic) {
199  ICStub* stub = ICStub_from_destination_address(ic->stub_address());
200  return stub->destination();
201}
202
203
204void* InlineCacheBuffer::cached_value_for(CompiledIC *ic) {
205  ICStub* stub = ICStub_from_destination_address(ic->stub_address());
206  return stub->cached_value();
207}
208
209
210// Free CompiledICHolder*s that are no longer in use
211void InlineCacheBuffer::release_pending_icholders() {
212  assert(SafepointSynchronize::is_at_safepoint(), "should only be called during a safepoint");
213  CompiledICHolder* holder = _pending_released;
214  _pending_released = NULL;
215  while (holder != NULL) {
216    CompiledICHolder* next = holder->next();
217    delete holder;
218    holder = next;
219    _pending_count--;
220  }
221  assert(_pending_count == 0, "wrong count");
222}
223
224// 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
226// another thread.
227void InlineCacheBuffer::queue_for_release(CompiledICHolder* icholder) {
228  MutexLockerEx mex(InlineCacheBuffer_lock);
229  icholder->set_next(_pending_released);
230  _pending_released = icholder;
231  _pending_count++;
232  if (TraceICBuffer) {
233    tty->print_cr("enqueueing icholder " INTPTR_FORMAT " to be freed", icholder);
234  }
235}
236