icBuffer.cpp revision 1472:c18cbe5936b8
1/*
2 * Copyright (c) 1997, 2006, 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 "incls/_precompiled.incl"
26#include "incls/_icBuffer.cpp.incl"
27
28
29DEF_STUB_INTERFACE(ICStub);
30
31StubQueue* InlineCacheBuffer::_buffer    = NULL;
32ICStub*    InlineCacheBuffer::_next_stub = NULL;
33
34
35void ICStub::finalize() {
36  if (!is_empty()) {
37    ResourceMark rm;
38    CompiledIC *ic = CompiledIC_at(ic_site());
39    assert(CodeCache::find_nmethod(ic->instruction_address()) != NULL, "inline cache in non-nmethod?");
40
41    assert(this == ICStub_from_destination_address(ic->stub_address()), "wrong owner of ic buffer");
42    ic->set_cached_oop(cached_oop());
43    ic->set_ic_destination(destination());
44  }
45}
46
47
48address ICStub::destination() const {
49  return InlineCacheBuffer::ic_buffer_entry_point(code_begin());
50}
51
52oop ICStub::cached_oop() const {
53  return InlineCacheBuffer::ic_buffer_cached_oop(code_begin());
54}
55
56
57void ICStub::set_stub(CompiledIC *ic, oop cached_value, address dest_addr) {
58  // We cannot store a pointer to the 'ic' object, since it is resource allocated. Instead we
59  // store the location of the inline cache. Then we have enough information recreate the CompiledIC
60  // object when we need to remove the stub.
61  _ic_site = ic->instruction_address();
62
63  // Assemble new stub
64  InlineCacheBuffer::assemble_ic_buffer_code(code_begin(), cached_value, dest_addr);
65  assert(destination() == dest_addr,   "can recover destination");
66  assert(cached_oop() == cached_value, "can recover destination");
67}
68
69
70void ICStub::clear() {
71  _ic_site = NULL;
72}
73
74
75#ifndef PRODUCT
76// anybody calling to this stub will trap
77
78void ICStub::verify() {
79}
80
81void ICStub::print() {
82  tty->print_cr("ICStub: site: " INTPTR_FORMAT, _ic_site);
83}
84#endif
85
86//-----------------------------------------------------------------------------------------------
87// Implementation of InlineCacheBuffer
88
89void InlineCacheBuffer::init_next_stub() {
90  ICStub* ic_stub = (ICStub*)buffer()->request_committed (ic_stub_code_size());
91  assert (ic_stub != NULL, "no room for a single stub");
92  set_next_stub(ic_stub);
93}
94
95void InlineCacheBuffer::initialize() {
96  if (_buffer != NULL) return; // already initialized
97  _buffer = new StubQueue(new ICStubInterface, 10*K, InlineCacheBuffer_lock, "InlineCacheBuffer");
98  assert (_buffer != NULL, "cannot allocate InlineCacheBuffer");
99  init_next_stub();
100}
101
102
103ICStub* InlineCacheBuffer::new_ic_stub() {
104  while (true) {
105    ICStub* ic_stub = (ICStub*)buffer()->request_committed(ic_stub_code_size());
106    if (ic_stub != NULL) {
107      return ic_stub;
108    }
109    // we ran out of inline cache buffer space; must enter safepoint.
110    // We do this by forcing a safepoint
111    EXCEPTION_MARK;
112
113    VM_ForceSafepoint vfs;
114    VMThread::execute(&vfs);
115    // We could potential get an async. exception at this point.
116    // In that case we will rethrow it to ourselvs.
117    if (HAS_PENDING_EXCEPTION) {
118      oop exception = PENDING_EXCEPTION;
119      CLEAR_PENDING_EXCEPTION;
120      Thread::send_async_exception(JavaThread::current()->threadObj(), exception);
121    }
122  }
123  ShouldNotReachHere();
124  return NULL;
125}
126
127
128void InlineCacheBuffer::update_inline_caches() {
129  if (buffer()->number_of_stubs() > 1) {
130    if (TraceICBuffer) {
131      tty->print_cr("[updating inline caches with %d stubs]", buffer()->number_of_stubs());
132    }
133    buffer()->remove_all();
134    init_next_stub();
135  }
136}
137
138
139bool InlineCacheBuffer::contains(address instruction_address) {
140  return buffer()->contains(instruction_address);
141}
142
143
144bool InlineCacheBuffer::is_empty() {
145  return buffer()->number_of_stubs() == 1;    // always has sentinel
146}
147
148
149void InlineCacheBuffer_init() {
150  InlineCacheBuffer::initialize();
151}
152
153
154void InlineCacheBuffer::create_transition_stub(CompiledIC *ic, oop cached_oop, address entry) {
155  assert(!SafepointSynchronize::is_at_safepoint(), "should not be called during a safepoint");
156  assert (CompiledIC_lock->is_locked(), "");
157  assert(cached_oop == NULL || cached_oop->is_perm(), "must belong to perm. space");
158  if (TraceICBuffer) { tty->print_cr("  create transition stub for " INTPTR_FORMAT, ic->instruction_address()); }
159
160  // If an transition stub is already associate with the inline cache, then we remove the association.
161  if (ic->is_in_transition_state()) {
162    ICStub* old_stub = ICStub_from_destination_address(ic->stub_address());
163    old_stub->clear();
164  }
165
166  // allocate and initialize new "out-of-line" inline-cache
167  ICStub* ic_stub = get_next_stub();
168  ic_stub->set_stub(ic, cached_oop, entry);
169
170  // Update inline cache in nmethod to point to new "out-of-line" allocated inline cache
171  ic->set_ic_destination(ic_stub->code_begin());
172
173  set_next_stub(new_ic_stub()); // can cause safepoint synchronization
174}
175
176
177address InlineCacheBuffer::ic_destination_for(CompiledIC *ic) {
178  ICStub* stub = ICStub_from_destination_address(ic->stub_address());
179  return stub->destination();
180}
181
182
183oop InlineCacheBuffer::cached_oop_for(CompiledIC *ic) {
184  ICStub* stub = ICStub_from_destination_address(ic->stub_address());
185  return stub->cached_oop();
186}
187