Mercurial > hg > truffle
annotate src/share/vm/opto/generateOptoStub.cpp @ 4710:41406797186b
7113012: G1: rename not-fully-young GCs as "mixed"
Summary: Renamed partially-young GCs as mixed and fully-young GCs as young. Change all external output that includes those terms (GC log and GC ergo log) as well as any comments, fields, methods, etc. The changeset also includes very minor code tidying up (added some curly brackets).
Reviewed-by: johnc, brutisso
author | tonyp |
---|---|
date | Fri, 16 Dec 2011 02:14:27 -0500 |
parents | f95d63e2154a |
children | e626685e9f6c |
rev | line source |
---|---|
0 | 1 /* |
1972 | 2 * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. |
0 | 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 * | |
1552
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
20 * or visit www.oracle.com if you need additional information or have any |
c18cbe5936b8
6941466: Oracle rebranding changes for Hotspot repositories
trims
parents:
0
diff
changeset
|
21 * questions. |
0 | 22 * |
23 */ | |
24 | |
1972 | 25 #include "precompiled.hpp" |
26 #include "opto/addnode.hpp" | |
27 #include "opto/callnode.hpp" | |
28 #include "opto/cfgnode.hpp" | |
29 #include "opto/compile.hpp" | |
30 #include "opto/connode.hpp" | |
31 #include "opto/locknode.hpp" | |
32 #include "opto/memnode.hpp" | |
33 #include "opto/mulnode.hpp" | |
34 #include "opto/node.hpp" | |
35 #include "opto/parse.hpp" | |
36 #include "opto/phaseX.hpp" | |
37 #include "opto/rootnode.hpp" | |
38 #include "opto/runtime.hpp" | |
39 #include "opto/type.hpp" | |
0 | 40 |
41 //--------------------gen_stub------------------------------- | |
42 void GraphKit::gen_stub(address C_function, | |
43 const char *name, | |
44 int is_fancy_jump, | |
45 bool pass_tls, | |
46 bool return_pc) { | |
47 ResourceMark rm; | |
48 | |
49 const TypeTuple *jdomain = C->tf()->domain(); | |
50 const TypeTuple *jrange = C->tf()->range(); | |
51 | |
52 // The procedure start | |
53 StartNode* start = new (C, 2) StartNode(root(), jdomain); | |
54 _gvn.set_type_bottom(start); | |
55 | |
56 // Make a map, with JVM state | |
57 uint parm_cnt = jdomain->cnt(); | |
58 uint max_map = MAX2(2*parm_cnt+1, jrange->cnt()); | |
59 // %%% SynchronizationEntryBCI is redundant; use InvocationEntryBci in interfaces | |
60 assert(SynchronizationEntryBCI == InvocationEntryBci, ""); | |
61 JVMState* jvms = new (C) JVMState(0); | |
62 jvms->set_bci(InvocationEntryBci); | |
63 jvms->set_monoff(max_map); | |
64 jvms->set_endoff(max_map); | |
65 { | |
66 SafePointNode *map = new (C, max_map) SafePointNode( max_map, jvms ); | |
67 jvms->set_map(map); | |
68 set_jvms(jvms); | |
69 assert(map == this->map(), "kit.map is set"); | |
70 } | |
71 | |
72 // Make up the parameters | |
73 uint i; | |
74 for( i = 0; i < parm_cnt; i++ ) | |
75 map()->init_req(i, _gvn.transform(new (C, 1) ParmNode(start, i))); | |
76 for( ; i<map()->req(); i++ ) | |
77 map()->init_req(i, top()); // For nicer debugging | |
78 | |
79 // GraphKit requires memory to be a MergeMemNode: | |
80 set_all_memory(map()->memory()); | |
81 | |
82 // Get base of thread-local storage area | |
83 Node* thread = _gvn.transform( new (C, 1) ThreadLocalNode() ); | |
84 | |
85 const int NoAlias = Compile::AliasIdxBot; | |
86 | |
87 Node* adr_last_Java_pc = basic_plus_adr(top(), | |
88 thread, | |
89 in_bytes(JavaThread::frame_anchor_offset()) + | |
90 in_bytes(JavaFrameAnchor::last_Java_pc_offset())); | |
91 #if defined(SPARC) || defined(IA64) | |
92 Node* adr_flags = basic_plus_adr(top(), | |
93 thread, | |
94 in_bytes(JavaThread::frame_anchor_offset()) + | |
95 in_bytes(JavaFrameAnchor::flags_offset())); | |
96 #endif /* defined(SPARC) || defined(IA64) */ | |
97 | |
98 | |
99 // Drop in the last_Java_sp. last_Java_fp is not touched. | |
100 // Always do this after the other "last_Java_frame" fields are set since | |
101 // as soon as last_Java_sp != NULL the has_last_Java_frame is true and | |
102 // users will look at the other fields. | |
103 // | |
104 Node *adr_sp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_sp_offset())); | |
105 #ifndef IA64 | |
106 Node *last_sp = basic_plus_adr(top(), frameptr(), (intptr_t) STACK_BIAS); | |
107 store_to_memory(NULL, adr_sp, last_sp, T_ADDRESS, NoAlias); | |
108 #endif | |
109 | |
110 // Set _thread_in_native | |
111 // The order of stores into TLS is critical! Setting _thread_in_native MUST | |
112 // be last, because a GC is allowed at any time after setting it and the GC | |
113 // will require last_Java_pc and last_Java_sp. | |
114 Node* adr_state = basic_plus_adr(top(), thread, in_bytes(JavaThread::thread_state_offset())); | |
115 | |
116 //----------------------------- | |
117 // Compute signature for C call. Varies from the Java signature! | |
118 const Type **fields = TypeTuple::fields(2*parm_cnt+2); | |
119 uint cnt = TypeFunc::Parms; | |
120 // The C routines gets the base of thread-local storage passed in as an | |
121 // extra argument. Not all calls need it, but its cheap to add here. | |
122 for( ; cnt<parm_cnt; cnt++ ) | |
123 fields[cnt] = jdomain->field_at(cnt); | |
124 fields[cnt++] = TypeRawPtr::BOTTOM; // Thread-local storage | |
125 // Also pass in the caller's PC, if asked for. | |
126 if( return_pc ) | |
127 fields[cnt++] = TypeRawPtr::BOTTOM; // Return PC | |
128 | |
129 const TypeTuple* domain = TypeTuple::make(cnt,fields); | |
130 // The C routine we are about to call cannot return an oop; it can block on | |
131 // exit and a GC will trash the oop while it sits in C-land. Instead, we | |
132 // return the oop through TLS for runtime calls. | |
133 // Also, C routines returning integer subword values leave the high | |
134 // order bits dirty; these must be cleaned up by explicit sign extension. | |
135 const Type* retval = (jrange->cnt() == TypeFunc::Parms) ? Type::TOP : jrange->field_at(TypeFunc::Parms); | |
136 // Make a private copy of jrange->fields(); | |
137 const Type **rfields = TypeTuple::fields(jrange->cnt() - TypeFunc::Parms); | |
138 // Fixup oop returns | |
139 int retval_ptr = retval->isa_oop_ptr(); | |
140 if( retval_ptr ) { | |
141 assert( pass_tls, "Oop must be returned thru TLS" ); | |
142 // Fancy-jumps return address; others return void | |
143 rfields[TypeFunc::Parms] = is_fancy_jump ? TypeRawPtr::BOTTOM : Type::TOP; | |
144 | |
145 } else if( retval->isa_int() ) { // Returning any integer subtype? | |
146 // "Fatten" byte, char & short return types to 'int' to show that | |
147 // the native C code can return values with junk high order bits. | |
148 // We'll sign-extend it below later. | |
149 rfields[TypeFunc::Parms] = TypeInt::INT; // It's "dirty" and needs sign-ext | |
150 | |
151 } else if( jrange->cnt() >= TypeFunc::Parms+1 ) { // Else copy other types | |
152 rfields[TypeFunc::Parms] = jrange->field_at(TypeFunc::Parms); | |
153 if( jrange->cnt() == TypeFunc::Parms+2 ) | |
154 rfields[TypeFunc::Parms+1] = jrange->field_at(TypeFunc::Parms+1); | |
155 } | |
156 const TypeTuple* range = TypeTuple::make(jrange->cnt(),rfields); | |
157 | |
158 // Final C signature | |
159 const TypeFunc *c_sig = TypeFunc::make(domain,range); | |
160 | |
161 //----------------------------- | |
162 // Make the call node | |
163 CallRuntimeNode *call = new (C, c_sig->domain()->cnt()) | |
164 CallRuntimeNode(c_sig, C_function, name, TypePtr::BOTTOM); | |
165 //----------------------------- | |
166 | |
167 // Fix-up the debug info for the call | |
168 call->set_jvms( new (C) JVMState(0) ); | |
169 call->jvms()->set_bci(0); | |
170 call->jvms()->set_offsets(cnt); | |
171 | |
172 // Set fixed predefined input arguments | |
173 cnt = 0; | |
174 for( i=0; i<TypeFunc::Parms; i++ ) | |
175 call->init_req( cnt++, map()->in(i) ); | |
176 // A little too aggressive on the parm copy; return address is not an input | |
177 call->set_req(TypeFunc::ReturnAdr, top()); | |
178 for( ; i<parm_cnt; i++ ) // Regular input arguments | |
179 call->init_req( cnt++, map()->in(i) ); | |
180 | |
181 call->init_req( cnt++, thread ); | |
182 if( return_pc ) // Return PC, if asked for | |
183 call->init_req( cnt++, returnadr() ); | |
184 _gvn.transform_no_reclaim(call); | |
185 | |
186 | |
187 //----------------------------- | |
188 // Now set up the return results | |
189 set_control( _gvn.transform( new (C, 1) ProjNode(call,TypeFunc::Control)) ); | |
190 set_i_o( _gvn.transform( new (C, 1) ProjNode(call,TypeFunc::I_O )) ); | |
191 set_all_memory_call(call); | |
192 if (range->cnt() > TypeFunc::Parms) { | |
193 Node* retnode = _gvn.transform( new (C, 1) ProjNode(call,TypeFunc::Parms) ); | |
194 // C-land is allowed to return sub-word values. Convert to integer type. | |
195 assert( retval != Type::TOP, "" ); | |
196 if (retval == TypeInt::BOOL) { | |
197 retnode = _gvn.transform( new (C, 3) AndINode(retnode, intcon(0xFF)) ); | |
198 } else if (retval == TypeInt::CHAR) { | |
199 retnode = _gvn.transform( new (C, 3) AndINode(retnode, intcon(0xFFFF)) ); | |
200 } else if (retval == TypeInt::BYTE) { | |
201 retnode = _gvn.transform( new (C, 3) LShiftINode(retnode, intcon(24)) ); | |
202 retnode = _gvn.transform( new (C, 3) RShiftINode(retnode, intcon(24)) ); | |
203 } else if (retval == TypeInt::SHORT) { | |
204 retnode = _gvn.transform( new (C, 3) LShiftINode(retnode, intcon(16)) ); | |
205 retnode = _gvn.transform( new (C, 3) RShiftINode(retnode, intcon(16)) ); | |
206 } | |
207 map()->set_req( TypeFunc::Parms, retnode ); | |
208 } | |
209 | |
210 //----------------------------- | |
211 | |
212 // Clear last_Java_sp | |
213 #ifdef IA64 | |
214 if( os::is_MP() ) insert_mem_bar(Op_MemBarRelease); | |
215 #endif | |
216 | |
217 store_to_memory(NULL, adr_sp, null(), T_ADDRESS, NoAlias); | |
218 #ifdef IA64 | |
219 if (os::is_MP() && UseMembar) insert_mem_bar(new MemBarVolatileNode()); | |
220 #endif // def IA64 | |
221 // Clear last_Java_pc and (optionally)_flags | |
222 store_to_memory(NULL, adr_last_Java_pc, null(), T_ADDRESS, NoAlias); | |
223 #if defined(SPARC) || defined(IA64) | |
224 store_to_memory(NULL, adr_flags, intcon(0), T_INT, NoAlias); | |
225 #endif /* defined(SPARC) || defined(IA64) */ | |
226 #ifdef IA64 | |
227 Node* adr_last_Java_fp = basic_plus_adr(top(), thread, in_bytes(JavaThread::last_Java_fp_offset())); | |
228 if( os::is_MP() ) insert_mem_bar(Op_MemBarRelease); | |
229 store_to_memory(NULL, adr_last_Java_fp, null(), T_ADDRESS, NoAlias); | |
230 #endif | |
231 | |
232 // For is-fancy-jump, the C-return value is also the branch target | |
233 Node* target = map()->in(TypeFunc::Parms); | |
234 // Runtime call returning oop in TLS? Fetch it out | |
235 if( pass_tls ) { | |
236 Node* adr = basic_plus_adr(top(), thread, in_bytes(JavaThread::vm_result_offset())); | |
237 Node* vm_result = make_load(NULL, adr, TypeOopPtr::BOTTOM, T_OBJECT, NoAlias, false); | |
238 map()->set_req(TypeFunc::Parms, vm_result); // vm_result passed as result | |
239 // clear thread-local-storage(tls) | |
240 store_to_memory(NULL, adr, null(), T_ADDRESS, NoAlias); | |
241 } | |
242 | |
243 //----------------------------- | |
244 // check exception | |
245 Node* adr = basic_plus_adr(top(), thread, in_bytes(Thread::pending_exception_offset())); | |
246 Node* pending = make_load(NULL, adr, TypeOopPtr::BOTTOM, T_OBJECT, NoAlias, false); | |
247 | |
248 Node* exit_memory = reset_memory(); | |
249 | |
250 Node* cmp = _gvn.transform( new (C, 3) CmpPNode(pending, null()) ); | |
251 Node* bo = _gvn.transform( new (C, 2) BoolNode(cmp, BoolTest::ne) ); | |
252 IfNode *iff = create_and_map_if(control(), bo, PROB_MIN, COUNT_UNKNOWN); | |
253 | |
254 Node* if_null = _gvn.transform( new (C, 1) IfFalseNode(iff) ); | |
255 Node* if_not_null = _gvn.transform( new (C, 1) IfTrueNode(iff) ); | |
256 | |
257 assert (StubRoutines::forward_exception_entry() != NULL, "must be generated before"); | |
258 Node *exc_target = makecon(TypeRawPtr::make( StubRoutines::forward_exception_entry() )); | |
259 Node *to_exc = new (C, TypeFunc::Parms+2) TailCallNode(if_not_null, | |
260 i_o(), | |
261 exit_memory, | |
262 frameptr(), | |
263 returnadr(), | |
264 exc_target, null()); | |
265 root()->add_req(_gvn.transform(to_exc)); // bind to root to keep live | |
266 C->init_start(start); | |
267 | |
268 //----------------------------- | |
269 // If this is a normal subroutine return, issue the return and be done. | |
270 Node *ret; | |
271 switch( is_fancy_jump ) { | |
272 case 0: // Make a return instruction | |
273 // Return to caller, free any space for return address | |
274 ret = new (C, TypeFunc::Parms) ReturnNode(TypeFunc::Parms, if_null, | |
275 i_o(), | |
276 exit_memory, | |
277 frameptr(), | |
278 returnadr()); | |
279 if (C->tf()->range()->cnt() > TypeFunc::Parms) | |
280 ret->add_req( map()->in(TypeFunc::Parms) ); | |
281 break; | |
282 case 1: // This is a fancy tail-call jump. Jump to computed address. | |
283 // Jump to new callee; leave old return address alone. | |
284 ret = new (C, TypeFunc::Parms+2) TailCallNode(if_null, | |
285 i_o(), | |
286 exit_memory, | |
287 frameptr(), | |
288 returnadr(), | |
289 target, map()->in(TypeFunc::Parms)); | |
290 break; | |
291 case 2: // Pop return address & jump | |
292 // Throw away old return address; jump to new computed address | |
293 //assert(C_function == CAST_FROM_FN_PTR(address, OptoRuntime::rethrow_C), "fancy_jump==2 only for rethrow"); | |
294 ret = new (C, TypeFunc::Parms+2) TailJumpNode(if_null, | |
295 i_o(), | |
296 exit_memory, | |
297 frameptr(), | |
298 target, map()->in(TypeFunc::Parms)); | |
299 break; | |
300 default: | |
301 ShouldNotReachHere(); | |
302 } | |
303 root()->add_req(_gvn.transform(ret)); | |
304 } |