comparison src/cpu/x86/vm/vtableStubs_x86_32.cpp @ 623:9adddb8c0fc8

6812831: factor duplicated assembly code for megamorphic invokeinterface (for 6655638) Summary: Code in vtableStubs and templateTable moved into MacroAssembler. Reviewed-by: kvn
author jrose
date Fri, 06 Mar 2009 21:36:50 -0800
parents 9ee9cf798b59
children 1d037ecd7960
comparison
equal deleted inserted replaced
622:56aae7be60d4 623:9adddb8c0fc8
32 32
33 #ifndef PRODUCT 33 #ifndef PRODUCT
34 extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index); 34 extern "C" void bad_compiled_vtable_index(JavaThread* thread, oop receiver, int index);
35 #endif 35 #endif
36 36
37 // used by compiler only; may use only caller saved registers rax, rbx, rcx. 37 // These stubs are used by the compiler only.
38 // rdx holds first int arg, rsi, rdi, rbp are callee-save & must be preserved. 38 // Argument registers, which must be preserved:
39 // Leave receiver in rcx; required behavior when +OptoArgsInRegisters 39 // rcx - receiver (always first argument)
40 // is modifed to put first oop in rcx. 40 // rdx - second argument (if any)
41 // Other registers that might be usable:
42 // rax - inline cache register (is interface for itable stub)
43 // rbx - method (used when calling out to interpreter)
44 // Available now, but may become callee-save at some point:
45 // rsi, rdi
46 // Note that rax and rdx are also used for return values.
41 // 47 //
42 VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { 48 VtableStub* VtableStubs::create_vtable_stub(int vtable_index) {
43 const int i486_code_length = VtableStub::pd_code_size_limit(true); 49 const int i486_code_length = VtableStub::pd_code_size_limit(true);
44 VtableStub* s = new(i486_code_length) VtableStub(true, vtable_index); 50 VtableStub* s = new(i486_code_length) VtableStub(true, vtable_index);
45 ResourceMark rm; 51 ResourceMark rm;
92 // rcx: receiver 98 // rcx: receiver
93 address ame_addr = __ pc(); 99 address ame_addr = __ pc();
94 __ jmp( Address(method, methodOopDesc::from_compiled_offset())); 100 __ jmp( Address(method, methodOopDesc::from_compiled_offset()));
95 101
96 masm->flush(); 102 masm->flush();
103
104 if (PrintMiscellaneous && (WizardMode || Verbose)) {
105 tty->print_cr("vtable #%d at "PTR_FORMAT"[%d] left over: %d",
106 vtable_index, s->entry_point(),
107 (int)(s->code_end() - s->entry_point()),
108 (int)(s->code_end() - __ pc()));
109 }
110 guarantee(__ pc() <= s->code_end(), "overflowed buffer");
111
97 s->set_exception_points(npe_addr, ame_addr); 112 s->set_exception_points(npe_addr, ame_addr);
98 return s; 113 return s;
99 } 114 }
100 115
101 116
102 VtableStub* VtableStubs::create_itable_stub(int vtable_index) { 117 VtableStub* VtableStubs::create_itable_stub(int itable_index) {
103 // Note well: pd_code_size_limit is the absolute minimum we can get away with. If you 118 // 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! 119 // 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); 120 const int i486_code_length = VtableStub::pd_code_size_limit(false);
106 VtableStub* s = new(i486_code_length) VtableStub(false, vtable_index); 121 VtableStub* s = new(i486_code_length) VtableStub(false, itable_index);
107 ResourceMark rm; 122 ResourceMark rm;
108 CodeBuffer cb(s->entry_point(), i486_code_length); 123 CodeBuffer cb(s->entry_point(), i486_code_length);
109 MacroAssembler* masm = new MacroAssembler(&cb); 124 MacroAssembler* masm = new MacroAssembler(&cb);
110 125
111 // Entry arguments: 126 // Entry arguments:
121 136
122 assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx"); 137 assert(VtableStub::receiver_location() == rcx->as_VMReg(), "receiver expected in rcx");
123 138
124 // get receiver klass (also an implicit null-check) 139 // get receiver klass (also an implicit null-check)
125 address npe_addr = __ pc(); 140 address npe_addr = __ pc();
126 __ movptr(rbx, Address(rcx, oopDesc::klass_offset_in_bytes())); 141 __ movptr(rsi, Address(rcx, oopDesc::klass_offset_in_bytes()));
127 142
128 __ mov(rsi, rbx); // Save klass in free register 143 // Most registers are in use; we'll use rax, rbx, rsi, rdi
129 // Most registers are in use, so save a few 144 // (If we need to make rsi, rdi callee-save, do a push/pop here.)
130 __ push(rdx); 145 const Register method = rbx;
131 // compute itable entry offset (in words) 146 Label throw_icce;
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 147
164 // Get methodOop and entrypoint for compiler 148 // Get methodOop and entrypoint for compiler
165 const Register method = rbx; 149 __ lookup_interface_method(// inputs: rec. class, interface, itable index
166 __ movptr(method, Address(rsi, rdx, Address::times_1, method_offset)); 150 rsi, rax, itable_index,
167 151 // outputs: method, scan temp. reg
168 // Restore saved register, before possible trap. 152 method, rdi,
169 __ pop(rdx); 153 throw_icce);
170 154
171 // method (rbx): methodOop 155 // method (rbx): methodOop
172 // rcx: receiver 156 // rcx: receiver
173 157
174 #ifdef ASSERT 158 #ifdef ASSERT
185 169
186 address ame_addr = __ pc(); 170 address ame_addr = __ pc();
187 __ jmp(Address(method, methodOopDesc::from_compiled_offset())); 171 __ jmp(Address(method, methodOopDesc::from_compiled_offset()));
188 172
189 __ bind(throw_icce); 173 __ bind(throw_icce);
190 // Restore saved register
191 __ pop(rdx);
192 __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry())); 174 __ jump(RuntimeAddress(StubRoutines::throw_IncompatibleClassChangeError_entry()));
193
194 masm->flush(); 175 masm->flush();
195 176
177 if (PrintMiscellaneous && (WizardMode || Verbose)) {
178 tty->print_cr("itable #%d at "PTR_FORMAT"[%d] left over: %d",
179 itable_index, s->entry_point(),
180 (int)(s->code_end() - s->entry_point()),
181 (int)(s->code_end() - __ pc()));
182 }
196 guarantee(__ pc() <= s->code_end(), "overflowed buffer"); 183 guarantee(__ pc() <= s->code_end(), "overflowed buffer");
197 184
198 s->set_exception_points(npe_addr, ame_addr); 185 s->set_exception_points(npe_addr, ame_addr);
199 return s; 186 return s;
200 } 187 }
205 if (is_vtable_stub) { 192 if (is_vtable_stub) {
206 // Vtable stub size 193 // Vtable stub size
207 return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0); 194 return (DebugVtables ? 210 : 16) + (CountCompiledCalls ? 6 : 0);
208 } else { 195 } else {
209 // Itable stub size 196 // Itable stub size
210 return (DebugVtables ? 144 : 64) + (CountCompiledCalls ? 6 : 0); 197 return (DebugVtables ? 256 : 66) + (CountCompiledCalls ? 6 : 0);
211 } 198 }
212 } 199 }
213 200
214 int VtableStub::pd_code_alignment() { 201 int VtableStub::pd_code_alignment() {
215 return wordSize; 202 return wordSize;