vtableStubs_x86_32.cpp revision 304:dc7f315e41f7
1/*
2 * Copyright 1997-2006 Sun Microsystems, Inc.  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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
24
25#include "incls/_precompiled.incl"
26#include "incls/_vtableStubs_x86_32.cpp.incl"
27
28// machine-dependent part of VtableStubs: create VtableStub of correct size and
29// initialize its code
30
31#define __ masm->
32
33#ifndef PRODUCT
34extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index);
35#endif
36
37// used by compiler only; may use only caller saved registers rax, rbx, rcx.
38// rdx holds first int arg, rsi, rdi, rbp are callee-save & must be preserved.
39// Leave receiver in rcx; required behavior when +OptoArgsInRegisters
40// is modifed to put first oop in rcx.
41//
42VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
43  const int i486_code_length = VtableStub::pd_code_size_limit(true);
44  VtableStub* s = new(i486_code_length) VtableStub(true, vtable_index);
45  ResourceMark rm;
46  CodeBuffer cb(s->entry_point(), i486_code_length);
47  MacroAssembler* masm = new MacroAssembler(&cb);
48
49#ifndef PRODUCT
50
51  if (CountCompiledCalls) {
52    __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
53  }
54#endif /* PRODUCT */
55
56  // get receiver (need to skip return address on top of stack)
57  assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
58
59  // get receiver klass
60  address npe_addr = __ pc();
61  __ movptr(rax, Address(rcx, oopDesc::klass_offset_in_bytes()));
62  // compute entry offset (in words)
63  int entry_offset = instanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size();
64#ifndef PRODUCT
65  if (DebugVtables) {
66    Label L;
67    // check offset vs vtable length
68    __ cmpl(Address(rax, instanceKlass::vtable_length_offset()*wordSize), vtable_index*vtableEntry::size());
69    __ jcc(Assembler::greater, L);
70    __ movl(rbx, vtable_index);
71    __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), rcx, rbx);
72    __ bind(L);
73  }
74#endif // PRODUCT
75
76  const Register method = rbx;
77
78  // load methodOop and target address
79  __ movptr(method, Address(rax, entry_offset*wordSize + vtableEntry::method_offset_in_bytes()));
80  if (DebugVtables) {
81    Label L;
82    __ cmpptr(method, (int32_t)NULL_WORD);
83    __ jcc(Assembler::equal, L);
84    __ cmpptr(Address(method, methodOopDesc::from_compiled_offset()), (int32_t)NULL_WORD);
85    __ jcc(Assembler::notZero, L);
86    __ stop("Vtable entry is NULL");
87    __ bind(L);
88  }
89
90  // rax,: receiver klass
91  // method (rbx): methodOop
92  // rcx: receiver
93  address ame_addr = __ pc();
94  __ jmp( Address(method, methodOopDesc::from_compiled_offset()));
95
96  masm->flush();
97  s->set_exception_points(npe_addr, ame_addr);
98  return s;
99}
100
101
102VtableStub* VtableStubs::create_itable_stub(int vtable_index) {
103  // Note well: pd_code_size_limit is the absolute minimum we can get away with.  If you
104  //            add code here, bump the code stub size returned by pd_code_size_limit!
105  const int i486_code_length = VtableStub::pd_code_size_limit(false);
106  VtableStub* s = new(i486_code_length) VtableStub(false, vtable_index);
107  ResourceMark rm;
108  CodeBuffer cb(s->entry_point(), i486_code_length);
109  MacroAssembler* masm = new MacroAssembler(&cb);
110
111  // Entry arguments:
112  //  rax,: Interface
113  //  rcx: Receiver
114
115#ifndef PRODUCT
116  if (CountCompiledCalls) {
117    __ incrementl(ExternalAddress((address) SharedRuntime::nof_megamorphic_calls_addr()));
118  }
119#endif /* PRODUCT */
120  // get receiver (need to skip return address on top of stack)
121
122  assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
123
124  // get receiver klass (also an implicit null-check)
125  address npe_addr = __ pc();
126  __ movptr(rbx, Address(rcx, oopDesc::klass_offset_in_bytes()));
127
128  __ mov(rsi, rbx);   // Save klass in free register
129  // Most registers are in use, so save a few
130  __ push(rdx);
131  // compute itable entry offset (in words)
132  const int base = instanceKlass::vtable_start_offset() * wordSize;
133  assert(vtableEntry::size() * wordSize == 4, "adjust the scaling in the code below");
134  __ movl(rdx, Address(rbx, instanceKlass::vtable_length_offset() * wordSize)); // Get length of vtable
135  __ lea(rbx, Address(rbx, rdx, Address::times_ptr, base));
136  if (HeapWordsPerLong > 1) {
137    // Round up to align_object_offset boundary
138    __ round_to(rbx, BytesPerLong);
139  }
140
141  Label hit, next, entry, throw_icce;
142
143  __ jmpb(entry);
144
145  __ bind(next);
146  __ addptr(rbx, itableOffsetEntry::size() * wordSize);
147
148  __ bind(entry);
149
150  // If the entry is NULL then we've reached the end of the table
151  // without finding the expected interface, so throw an exception
152  __ movptr(rdx, Address(rbx, itableOffsetEntry::interface_offset_in_bytes()));
153  __ testptr(rdx, rdx);
154  __ jcc(Assembler::zero, throw_icce);
155  __ cmpptr(rax, rdx);
156  __ jcc(Assembler::notEqual, next);
157
158  // We found a hit, move offset into rbx,
159  __ movl(rdx, Address(rbx, itableOffsetEntry::offset_offset_in_bytes()));
160
161  // Compute itableMethodEntry.
162  const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + itableMethodEntry::method_offset_in_bytes();
163
164  // Get methodOop and entrypoint for compiler
165  const Register method = rbx;
166  __ movptr(method, Address(rsi, rdx, Address::times_1, method_offset));
167
168  // Restore saved register, before possible trap.
169  __ pop(rdx);
170
171  // method (rbx): methodOop
172  // rcx: receiver
173
174#ifdef ASSERT
175  if (DebugVtables) {
176      Label L1;
177      __ cmpptr(method, (int32_t)NULL_WORD);
178      __ jcc(Assembler::equal, L1);
179      __ cmpptr(Address(method, methodOopDesc::from_compiled_offset()), (int32_t)NULL_WORD);
180      __ jcc(Assembler::notZero, L1);
181      __ stop("methodOop is null");
182      __ bind(L1);
183    }
184#endif // ASSERT
185
186  address ame_addr = __ pc();
187  __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
188
189  __ bind(throw_icce);
190  // Restore saved register
191  __ pop(rdx);
192  __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
193
194  masm->flush();
195
196  guarantee(__ pc() <= s->code_end(), "overflowed buffer");
197
198  s->set_exception_points(npe_addr, ame_addr);
199  return s;
200}
201
202
203
204int VtableStub::pd_code_size_limit(bool is_vtable_stub) {
205  if (is_vtable_stub) {
206    // Vtable stub size
207    return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
208  } else {
209    // Itable stub size
210    return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0);
211  }
212}
213
214int VtableStub::pd_code_alignment() {
215  return wordSize;
216}
217