Mercurial > hg > truffle
comparison src/cpu/ppc/vm/vtableStubs_ppc_64.cpp @ 14408:ec28f9c041ff
8019972: PPC64 (part 9): platform files for interpreter only VM.
Summary: With this change the HotSpot core build works on Linux/PPC64. The VM succesfully executes simple test programs.
Reviewed-by: kvn
author | goetz |
---|---|
date | Fri, 02 Aug 2013 16:46:45 +0200 |
parents | |
children | eb178e97560c |
comparison
equal
deleted
inserted
replaced
14407:94c202aa2646 | 14408:ec28f9c041ff |
---|---|
1 /* | |
2 * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. | |
3 * Copyright 2012, 2013 SAP AG. All rights reserved. | |
4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. | |
5 * | |
6 * This code is free software; you can redistribute it and/or modify it | |
7 * under the terms of the GNU General Public License version 2 only, as | |
8 * published by the Free Software Foundation. | |
9 * | |
10 * This code is distributed in the hope that it will be useful, but WITHOUT | |
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License | |
13 * version 2 for more details (a copy is included in the LICENSE file that | |
14 * accompanied this code). | |
15 * | |
16 * You should have received a copy of the GNU General Public License version | |
17 * 2 along with this work; if not, write to the Free Software Foundation, | |
18 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |
19 * | |
20 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA | |
21 * or visit www.oracle.com if you need additional information or have any | |
22 * questions. | |
23 * | |
24 */ | |
25 | |
26 #include "precompiled.hpp" | |
27 #include "asm/assembler.hpp" | |
28 #include "asm/macroAssembler.inline.hpp" | |
29 #include "code/vtableStubs.hpp" | |
30 #include "interp_masm_ppc_64.hpp" | |
31 #include "memory/resourceArea.hpp" | |
32 #include "oops/instanceKlass.hpp" | |
33 #include "oops/klassVtable.hpp" | |
34 #include "runtime/sharedRuntime.hpp" | |
35 #include "vmreg_ppc.inline.hpp" | |
36 #ifdef COMPILER2 | |
37 #include "opto/runtime.hpp" | |
38 #endif | |
39 | |
40 #define __ masm-> | |
41 | |
42 #ifdef PRODUCT | |
43 #define BLOCK_COMMENT(str) // nothing | |
44 #else | |
45 #define BLOCK_COMMENT(str) __ block_comment(str) | |
46 #endif | |
47 #define BIND(label) bind(label); BLOCK_COMMENT(#label ":") | |
48 | |
49 #ifndef PRODUCT | |
50 extern "C" void bad_compiled_vtable_index(JavaThread* thread, oopDesc* receiver, int index); | |
51 #endif | |
52 | |
53 // Used by compiler only; may use only caller saved, non-argument | |
54 // registers. | |
55 VtableStub* VtableStubs::create_vtable_stub(int vtable_index) { | |
56 // PPC port: use fixed size. | |
57 const int code_length = VtableStub::pd_code_size_limit(true); | |
58 VtableStub* s = new (code_length) VtableStub(true, vtable_index); | |
59 ResourceMark rm; | |
60 CodeBuffer cb(s->entry_point(), code_length); | |
61 MacroAssembler* masm = new MacroAssembler(&cb); | |
62 address start_pc; | |
63 | |
64 #ifndef PRODUCT | |
65 if (CountCompiledCalls) { | |
66 __ load_const(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr()); | |
67 __ lwz(R12_scratch2, 0, R11_scratch1); | |
68 __ addi(R12_scratch2, R12_scratch2, 1); | |
69 __ stw(R12_scratch2, 0, R11_scratch1); | |
70 } | |
71 #endif | |
72 | |
73 assert(VtableStub::receiver_location() == R3_ARG1->as_VMReg(), "receiver expected in R3_ARG1"); | |
74 | |
75 // Get receiver klass. | |
76 const Register rcvr_klass = R11_scratch1; | |
77 | |
78 // We might implicit NULL fault here. | |
79 address npe_addr = __ pc(); // npe = null pointer exception | |
80 __ load_klass_with_trap_null_check(rcvr_klass, R3); | |
81 | |
82 // Set methodOop (in case of interpreted method), and destination address. | |
83 int entry_offset = InstanceKlass::vtable_start_offset() + vtable_index*vtableEntry::size(); | |
84 | |
85 #ifndef PRODUCT | |
86 if (DebugVtables) { | |
87 Label L; | |
88 // Check offset vs vtable length. | |
89 const Register vtable_len = R12_scratch2; | |
90 __ lwz(vtable_len, InstanceKlass::vtable_length_offset()*wordSize, rcvr_klass); | |
91 __ cmpwi(CCR0, vtable_len, vtable_index*vtableEntry::size()); | |
92 __ bge(CCR0, L); | |
93 __ li(R12_scratch2, vtable_index); | |
94 __ call_VM(noreg, CAST_FROM_FN_PTR(address, bad_compiled_vtable_index), R3_ARG1, R12_scratch2, false); | |
95 __ bind(L); | |
96 } | |
97 #endif | |
98 | |
99 int v_off = entry_offset*wordSize + vtableEntry::method_offset_in_bytes(); | |
100 | |
101 __ ld(R19_method, v_off, rcvr_klass); | |
102 | |
103 #ifndef PRODUCT | |
104 if (DebugVtables) { | |
105 Label L; | |
106 __ cmpdi(CCR0, R19_method, 0); | |
107 __ bne(CCR0, L); | |
108 __ stop("Vtable entry is ZERO", 102); | |
109 __ bind(L); | |
110 } | |
111 #endif | |
112 | |
113 // If the vtable entry is null, the method is abstract. | |
114 address ame_addr = __ pc(); // ame = abstract method error | |
115 | |
116 __ ld_with_trap_null_check(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); | |
117 __ mtctr(R12_scratch2); | |
118 __ bctr(); | |
119 masm->flush(); | |
120 | |
121 guarantee(__ pc() <= s->code_end(), "overflowed buffer"); | |
122 | |
123 s->set_exception_points(npe_addr, ame_addr); | |
124 | |
125 return s; | |
126 } | |
127 | |
128 VtableStub* VtableStubs::create_itable_stub(int vtable_index) { | |
129 // PPC port: use fixed size. | |
130 const int code_length = VtableStub::pd_code_size_limit(false); | |
131 VtableStub* s = new (code_length) VtableStub(false, vtable_index); | |
132 ResourceMark rm; | |
133 CodeBuffer cb(s->entry_point(), code_length); | |
134 MacroAssembler* masm = new MacroAssembler(&cb); | |
135 address start_pc; | |
136 | |
137 #ifndef PRODUCT | |
138 if (CountCompiledCalls) { | |
139 __ load_const(R11_scratch1, SharedRuntime::nof_megamorphic_calls_addr()); | |
140 __ lwz(R12_scratch2, 0, R11_scratch1); | |
141 __ addi(R12_scratch2, R12_scratch2, 1); | |
142 __ stw(R12_scratch2, 0, R11_scratch1); | |
143 } | |
144 #endif | |
145 | |
146 assert(VtableStub::receiver_location() == R3_ARG1->as_VMReg(), "receiver expected in R3_ARG1"); | |
147 | |
148 // Entry arguments: | |
149 // R19_method: Interface | |
150 // R3_ARG1: Receiver | |
151 // | |
152 | |
153 const Register rcvr_klass = R11_scratch1; | |
154 const Register vtable_len = R12_scratch2; | |
155 const Register itable_entry_addr = R21_tmp1; | |
156 const Register itable_interface = R22_tmp2; | |
157 | |
158 // Get receiver klass. | |
159 | |
160 // We might implicit NULL fault here. | |
161 address npe_addr = __ pc(); // npe = null pointer exception | |
162 __ load_klass_with_trap_null_check(rcvr_klass, R3_ARG1); | |
163 | |
164 //__ ld(rcvr_klass, oopDesc::klass_offset_in_bytes(), R3_ARG1); | |
165 | |
166 BLOCK_COMMENT("Load start of itable entries into itable_entry."); | |
167 __ lwz(vtable_len, InstanceKlass::vtable_length_offset() * wordSize, rcvr_klass); | |
168 __ slwi(vtable_len, vtable_len, exact_log2(vtableEntry::size() * wordSize)); | |
169 __ add(itable_entry_addr, vtable_len, rcvr_klass); | |
170 | |
171 // Loop over all itable entries until desired interfaceOop(Rinterface) found. | |
172 BLOCK_COMMENT("Increment itable_entry_addr in loop."); | |
173 const int vtable_base_offset = InstanceKlass::vtable_start_offset() * wordSize; | |
174 __ addi(itable_entry_addr, itable_entry_addr, vtable_base_offset + itableOffsetEntry::interface_offset_in_bytes()); | |
175 | |
176 const int itable_offset_search_inc = itableOffsetEntry::size() * wordSize; | |
177 Label search; | |
178 __ bind(search); | |
179 __ ld(itable_interface, 0, itable_entry_addr); | |
180 | |
181 // Handle IncompatibleClassChangeError in itable stubs. | |
182 // If the entry is NULL then we've reached the end of the table | |
183 // without finding the expected interface, so throw an exception. | |
184 BLOCK_COMMENT("Handle IncompatibleClassChangeError in itable stubs."); | |
185 Label throw_icce; | |
186 __ cmpdi(CCR1, itable_interface, 0); | |
187 __ cmpd(CCR0, itable_interface, R19_method); | |
188 __ addi(itable_entry_addr, itable_entry_addr, itable_offset_search_inc); | |
189 __ beq(CCR1, throw_icce); | |
190 __ bne(CCR0, search); | |
191 | |
192 // Entry found and itable_entry_addr points to it, get offset of vtable for interface. | |
193 | |
194 const Register vtable_offset = R12_scratch2; | |
195 const Register itable_method = R11_scratch1; | |
196 | |
197 const int vtable_offset_offset = (itableOffsetEntry::offset_offset_in_bytes() - | |
198 itableOffsetEntry::interface_offset_in_bytes()) - | |
199 itable_offset_search_inc; | |
200 __ lwz(vtable_offset, vtable_offset_offset, itable_entry_addr); | |
201 | |
202 // Compute itableMethodEntry and get methodOop and entry point for compiler. | |
203 const int method_offset = (itableMethodEntry::size() * wordSize * vtable_index) + | |
204 itableMethodEntry::method_offset_in_bytes(); | |
205 | |
206 __ add(itable_method, rcvr_klass, vtable_offset); | |
207 __ ld(R19_method, method_offset, itable_method); | |
208 | |
209 #ifndef PRODUCT | |
210 if (DebugVtables) { | |
211 Label ok; | |
212 __ cmpd(CCR0, R19_method, 0); | |
213 __ bne(CCR0, ok); | |
214 __ stop("methodOop is null", 103); | |
215 __ bind(ok); | |
216 } | |
217 #endif | |
218 | |
219 // If the vtable entry is null, the method is abstract. | |
220 address ame_addr = __ pc(); // ame = abstract method error | |
221 | |
222 // Must do an explicit check if implicit checks are disabled. | |
223 assert(!MacroAssembler::needs_explicit_null_check(in_bytes(Method::from_compiled_offset())), "sanity"); | |
224 if (!ImplicitNullChecks NOT_LINUX(|| true) /*!os::zero_page_read_protected()*/) { | |
225 if (TrapBasedNullChecks) { | |
226 __ trap_null_check(R19_method); | |
227 } else { | |
228 __ cmpdi(CCR0, R19_method, 0); | |
229 __ beq(CCR0, throw_icce); | |
230 } | |
231 } | |
232 __ ld(R12_scratch2, in_bytes(Method::from_compiled_offset()), R19_method); | |
233 __ mtctr(R12_scratch2); | |
234 __ bctr(); | |
235 | |
236 // Handle IncompatibleClassChangeError in itable stubs. | |
237 // More detailed error message. | |
238 // We force resolving of the call site by jumping to the "handle | |
239 // wrong method" stub, and so let the interpreter runtime do all the | |
240 // dirty work. | |
241 __ bind(throw_icce); | |
242 __ load_const(R11_scratch1, SharedRuntime::get_handle_wrong_method_stub()); | |
243 __ mtctr(R11_scratch1); | |
244 __ bctr(); | |
245 | |
246 masm->flush(); | |
247 | |
248 guarantee(__ pc() <= s->code_end(), "overflowed buffer"); | |
249 | |
250 s->set_exception_points(npe_addr, ame_addr); | |
251 return s; | |
252 } | |
253 | |
254 int VtableStub::pd_code_size_limit(bool is_vtable_stub) { | |
255 if (TraceJumps || DebugVtables || CountCompiledCalls || VerifyOops) { | |
256 return 1000; | |
257 } else { | |
258 if (is_vtable_stub) { | |
259 return 20 + 16 + 8; // Plain + (cOops & Traps) + safety | |
260 } else { | |
261 return 16 + 96; | |
262 } | |
263 } | |
264 } | |
265 | |
266 int VtableStub::pd_code_alignment() { | |
267 const unsigned int icache_line_size = 32; | |
268 return icache_line_size; | |
269 } |