File: | jdk/src/hotspot/share/opto/buildOopMap.cpp |
Warning: | line 117, column 17 Value stored to 'jvms' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (c) 2002, 2021, 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 "precompiled.hpp" |
26 | #include "code/vmreg.inline.hpp" |
27 | #include "compiler/oopMap.hpp" |
28 | #include "memory/resourceArea.hpp" |
29 | #include "opto/addnode.hpp" |
30 | #include "opto/callnode.hpp" |
31 | #include "opto/compile.hpp" |
32 | #include "opto/machnode.hpp" |
33 | #include "opto/matcher.hpp" |
34 | #include "opto/output.hpp" |
35 | #include "opto/phase.hpp" |
36 | #include "opto/regalloc.hpp" |
37 | #include "opto/rootnode.hpp" |
38 | #include "utilities/align.hpp" |
39 | |
40 | // The functions in this file builds OopMaps after all scheduling is done. |
41 | // |
42 | // OopMaps contain a list of all registers and stack-slots containing oops (so |
43 | // they can be updated by GC). OopMaps also contain a list of derived-pointer |
44 | // base-pointer pairs. When the base is moved, the derived pointer moves to |
45 | // follow it. Finally, any registers holding callee-save values are also |
46 | // recorded. These might contain oops, but only the caller knows. |
47 | // |
48 | // BuildOopMaps implements a simple forward reaching-defs solution. At each |
49 | // GC point we'll have the reaching-def Nodes. If the reaching Nodes are |
50 | // typed as pointers (no offset), then they are oops. Pointers+offsets are |
51 | // derived pointers, and bases can be found from them. Finally, we'll also |
52 | // track reaching callee-save values. Note that a copy of a callee-save value |
53 | // "kills" it's source, so that only 1 copy of a callee-save value is alive at |
54 | // a time. |
55 | // |
56 | // We run a simple bitvector liveness pass to help trim out dead oops. Due to |
57 | // irreducible loops, we can have a reaching def of an oop that only reaches |
58 | // along one path and no way to know if it's valid or not on the other path. |
59 | // The bitvectors are quite dense and the liveness pass is fast. |
60 | // |
61 | // At GC points, we consult this information to build OopMaps. All reaching |
62 | // defs typed as oops are added to the OopMap. Only 1 instance of a |
63 | // callee-save register can be recorded. For derived pointers, we'll have to |
64 | // find and record the register holding the base. |
65 | // |
66 | // The reaching def's is a simple 1-pass worklist approach. I tried a clever |
67 | // breadth-first approach but it was worse (showed O(n^2) in the |
68 | // pick-next-block code). |
69 | // |
70 | // The relevant data is kept in a struct of arrays (it could just as well be |
71 | // an array of structs, but the struct-of-arrays is generally a little more |
72 | // efficient). The arrays are indexed by register number (including |
73 | // stack-slots as registers) and so is bounded by 200 to 300 elements in |
74 | // practice. One array will map to a reaching def Node (or NULL for |
75 | // conflict/dead). The other array will map to a callee-saved register or |
76 | // OptoReg::Bad for not-callee-saved. |
77 | |
78 | |
79 | // Structure to pass around |
80 | struct OopFlow : public ResourceObj { |
81 | short *_callees; // Array mapping register to callee-saved |
82 | Node **_defs; // array mapping register to reaching def |
83 | // or NULL if dead/conflict |
84 | // OopFlow structs, when not being actively modified, describe the _end_ of |
85 | // this block. |
86 | Block *_b; // Block for this struct |
87 | OopFlow *_next; // Next free OopFlow |
88 | // or NULL if dead/conflict |
89 | Compile* C; |
90 | |
91 | OopFlow( short *callees, Node **defs, Compile* c ) : _callees(callees), _defs(defs), |
92 | _b(NULL__null), _next(NULL__null), C(c) { } |
93 | |
94 | // Given reaching-defs for this block start, compute it for this block end |
95 | void compute_reach( PhaseRegAlloc *regalloc, int max_reg, Dict *safehash ); |
96 | |
97 | // Merge these two OopFlows into the 'this' pointer. |
98 | void merge( OopFlow *flow, int max_reg ); |
99 | |
100 | // Copy a 'flow' over an existing flow |
101 | void clone( OopFlow *flow, int max_size); |
102 | |
103 | // Make a new OopFlow from scratch |
104 | static OopFlow *make( Arena *A, int max_size, Compile* C ); |
105 | |
106 | // Build an oopmap from the current flow info |
107 | OopMap *build_oop_map( Node *n, int max_reg, PhaseRegAlloc *regalloc, int* live ); |
108 | }; |
109 | |
110 | // Given reaching-defs for this block start, compute it for this block end |
111 | void OopFlow::compute_reach( PhaseRegAlloc *regalloc, int max_reg, Dict *safehash ) { |
112 | |
113 | for( uint i=0; i<_b->number_of_nodes(); i++ ) { |
114 | Node *n = _b->get_node(i); |
115 | |
116 | if( n->jvms() ) { // Build an OopMap here? |
117 | JVMState *jvms = n->jvms(); |
Value stored to 'jvms' during its initialization is never read | |
118 | // no map needed for leaf calls |
119 | if( n->is_MachSafePoint() && !n->is_MachCallLeaf() ) { |
120 | int *live = (int*) (*safehash)[n]; |
121 | assert( live, "must find live" )do { if (!(live)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 121, "assert(" "live" ") failed", "must find live"); ::breakpoint (); } } while (0); |
122 | n->as_MachSafePoint()->set_oop_map( build_oop_map(n,max_reg,regalloc, live) ); |
123 | } |
124 | } |
125 | |
126 | // Assign new reaching def's. |
127 | // Note that I padded the _defs and _callees arrays so it's legal |
128 | // to index at _defs[OptoReg::Bad]. |
129 | OptoReg::Name first = regalloc->get_reg_first(n); |
130 | OptoReg::Name second = regalloc->get_reg_second(n); |
131 | _defs[first] = n; |
132 | _defs[second] = n; |
133 | |
134 | // Pass callee-save info around copies |
135 | int idx = n->is_Copy(); |
136 | if( idx ) { // Copies move callee-save info |
137 | OptoReg::Name old_first = regalloc->get_reg_first(n->in(idx)); |
138 | OptoReg::Name old_second = regalloc->get_reg_second(n->in(idx)); |
139 | int tmp_first = _callees[old_first]; |
140 | int tmp_second = _callees[old_second]; |
141 | _callees[old_first] = OptoReg::Bad; // callee-save is moved, dead in old location |
142 | _callees[old_second] = OptoReg::Bad; |
143 | _callees[first] = tmp_first; |
144 | _callees[second] = tmp_second; |
145 | } else if( n->is_Phi() ) { // Phis do not mod callee-saves |
146 | assert( _callees[first] == _callees[regalloc->get_reg_first(n->in(1))], "" )do { if (!(_callees[first] == _callees[regalloc->get_reg_first (n->in(1))])) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 146, "assert(" "_callees[first] == _callees[regalloc->get_reg_first(n->in(1))]" ") failed", ""); ::breakpoint(); } } while (0); |
147 | assert( _callees[second] == _callees[regalloc->get_reg_second(n->in(1))], "" )do { if (!(_callees[second] == _callees[regalloc->get_reg_second (n->in(1))])) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 147, "assert(" "_callees[second] == _callees[regalloc->get_reg_second(n->in(1))]" ") failed", ""); ::breakpoint(); } } while (0); |
148 | assert( _callees[first] == _callees[regalloc->get_reg_first(n->in(n->req()-1))], "" )do { if (!(_callees[first] == _callees[regalloc->get_reg_first (n->in(n->req()-1))])) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 148, "assert(" "_callees[first] == _callees[regalloc->get_reg_first(n->in(n->req()-1))]" ") failed", ""); ::breakpoint(); } } while (0); |
149 | assert( _callees[second] == _callees[regalloc->get_reg_second(n->in(n->req()-1))], "" )do { if (!(_callees[second] == _callees[regalloc->get_reg_second (n->in(n->req()-1))])) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 149, "assert(" "_callees[second] == _callees[regalloc->get_reg_second(n->in(n->req()-1))]" ") failed", ""); ::breakpoint(); } } while (0); |
150 | } else { |
151 | _callees[first] = OptoReg::Bad; // No longer holding a callee-save value |
152 | _callees[second] = OptoReg::Bad; |
153 | |
154 | // Find base case for callee saves |
155 | if( n->is_Proj() && n->in(0)->is_Start() ) { |
156 | if( OptoReg::is_reg(first) && |
157 | regalloc->_matcher.is_save_on_entry(first) ) |
158 | _callees[first] = first; |
159 | if( OptoReg::is_reg(second) && |
160 | regalloc->_matcher.is_save_on_entry(second) ) |
161 | _callees[second] = second; |
162 | } |
163 | } |
164 | } |
165 | } |
166 | |
167 | // Merge the given flow into the 'this' flow |
168 | void OopFlow::merge( OopFlow *flow, int max_reg ) { |
169 | assert( _b == NULL, "merging into a happy flow" )do { if (!(_b == __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 169, "assert(" "_b == __null" ") failed", "merging into a happy flow" ); ::breakpoint(); } } while (0); |
170 | assert( flow->_b, "this flow is still alive" )do { if (!(flow->_b)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 170, "assert(" "flow->_b" ") failed", "this flow is still alive" ); ::breakpoint(); } } while (0); |
171 | assert( flow != this, "no self flow" )do { if (!(flow != this)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 171, "assert(" "flow != this" ") failed", "no self flow"); :: breakpoint(); } } while (0); |
172 | |
173 | // Do the merge. If there are any differences, drop to 'bottom' which |
174 | // is OptoReg::Bad or NULL depending. |
175 | for( int i=0; i<max_reg; i++ ) { |
176 | // Merge the callee-save's |
177 | if( _callees[i] != flow->_callees[i] ) |
178 | _callees[i] = OptoReg::Bad; |
179 | // Merge the reaching defs |
180 | if( _defs[i] != flow->_defs[i] ) |
181 | _defs[i] = NULL__null; |
182 | } |
183 | |
184 | } |
185 | |
186 | void OopFlow::clone( OopFlow *flow, int max_size ) { |
187 | _b = flow->_b; |
188 | memcpy( _callees, flow->_callees, sizeof(short)*max_size); |
189 | memcpy( _defs , flow->_defs , sizeof(Node*)*max_size); |
190 | } |
191 | |
192 | OopFlow *OopFlow::make( Arena *A, int max_size, Compile* C ) { |
193 | short *callees = NEW_ARENA_ARRAY(A,short,max_size+1)(short*) (A)->Amalloc((max_size+1) * sizeof(short)); |
194 | Node **defs = NEW_ARENA_ARRAY(A,Node*,max_size+1)(Node**) (A)->Amalloc((max_size+1) * sizeof(Node*)); |
195 | debug_only( memset(defs,0,(max_size+1)*sizeof(Node*)) )memset(defs,0,(max_size+1)*sizeof(Node*)); |
196 | OopFlow *flow = new (A) OopFlow(callees+1, defs+1, C); |
197 | assert( &flow->_callees[OptoReg::Bad] == callees, "Ok to index at OptoReg::Bad" )do { if (!(&flow->_callees[OptoReg::Bad] == callees)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 197, "assert(" "&flow->_callees[OptoReg::Bad] == callees" ") failed", "Ok to index at OptoReg::Bad"); ::breakpoint(); } } while (0); |
198 | assert( &flow->_defs [OptoReg::Bad] == defs , "Ok to index at OptoReg::Bad" )do { if (!(&flow->_defs [OptoReg::Bad] == defs)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 198, "assert(" "&flow->_defs [OptoReg::Bad] == defs" ") failed", "Ok to index at OptoReg::Bad"); ::breakpoint(); } } while (0); |
199 | return flow; |
200 | } |
201 | |
202 | static int get_live_bit( int *live, int reg ) { |
203 | return live[reg>>LogBitsPerInt] & (1<<(reg&(BitsPerInt-1))); } |
204 | static void set_live_bit( int *live, int reg ) { |
205 | live[reg>>LogBitsPerInt] |= (1<<(reg&(BitsPerInt-1))); } |
206 | static void clr_live_bit( int *live, int reg ) { |
207 | live[reg>>LogBitsPerInt] &= ~(1<<(reg&(BitsPerInt-1))); } |
208 | |
209 | // Build an oopmap from the current flow info |
210 | OopMap *OopFlow::build_oop_map( Node *n, int max_reg, PhaseRegAlloc *regalloc, int* live ) { |
211 | int framesize = regalloc->_framesize; |
212 | int max_inarg_slot = OptoReg::reg2stack(regalloc->_matcher._new_SP); |
213 | debug_only( char *dup_check = NEW_RESOURCE_ARRAY(char,OptoReg::stack0());char *dup_check = (char*) resource_allocate_bytes((OptoReg::stack0 ()) * sizeof(char)); memset(dup_check,0,OptoReg::stack0()) |
214 | memset(dup_check,0,OptoReg::stack0()) )char *dup_check = (char*) resource_allocate_bytes((OptoReg::stack0 ()) * sizeof(char)); memset(dup_check,0,OptoReg::stack0()); |
215 | |
216 | OopMap *omap = new OopMap( framesize, max_inarg_slot ); |
217 | MachCallNode *mcall = n->is_MachCall() ? n->as_MachCall() : NULL__null; |
218 | JVMState* jvms = n->jvms(); |
219 | |
220 | // For all registers do... |
221 | for( int reg=0; reg<max_reg; reg++ ) { |
222 | if( get_live_bit(live,reg) == 0 ) |
223 | continue; // Ignore if not live |
224 | |
225 | // %%% C2 can use 2 OptoRegs when the physical register is only one 64bit |
226 | // register in that case we'll get an non-concrete register for the second |
227 | // half. We only need to tell the map the register once! |
228 | // |
229 | // However for the moment we disable this change and leave things as they |
230 | // were. |
231 | |
232 | VMReg r = OptoReg::as_VMReg(OptoReg::Name(reg), framesize, max_inarg_slot); |
233 | |
234 | // See if dead (no reaching def). |
235 | Node *def = _defs[reg]; // Get reaching def |
236 | assert( def, "since live better have reaching def" )do { if (!(def)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 236, "assert(" "def" ") failed", "since live better have reaching def" ); ::breakpoint(); } } while (0); |
237 | |
238 | // Classify the reaching def as oop, derived, callee-save, dead, or other |
239 | const Type *t = def->bottom_type(); |
240 | if( t->isa_oop_ptr() ) { // Oop or derived? |
241 | assert( !OptoReg::is_valid(_callees[reg]), "oop can't be callee save" )do { if (!(!OptoReg::is_valid(_callees[reg]))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 241, "assert(" "!OptoReg::is_valid(_callees[reg])" ") failed" , "oop can't be callee save"); ::breakpoint(); } } while (0); |
242 | #ifdef _LP641 |
243 | // 64-bit pointers record oop-ishness on 2 aligned adjacent registers. |
244 | // Make sure both are record from the same reaching def, but do not |
245 | // put both into the oopmap. |
246 | if( (reg&1) == 1 ) { // High half of oop-pair? |
247 | assert( _defs[reg-1] == _defs[reg], "both halves from same reaching def" )do { if (!(_defs[reg-1] == _defs[reg])) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 247, "assert(" "_defs[reg-1] == _defs[reg]" ") failed", "both halves from same reaching def" ); ::breakpoint(); } } while (0); |
248 | continue; // Do not record high parts in oopmap |
249 | } |
250 | #endif |
251 | |
252 | // Check for a legal reg name in the oopMap and bailout if it is not. |
253 | if (!omap->legal_vm_reg_name(r)) { |
254 | regalloc->C->record_method_not_compilable("illegal oopMap register name"); |
255 | continue; |
256 | } |
257 | if( t->is_ptr()->_offset == 0 ) { // Not derived? |
258 | if( mcall ) { |
259 | // Outgoing argument GC mask responsibility belongs to the callee, |
260 | // not the caller. Inspect the inputs to the call, to see if |
261 | // this live-range is one of them. |
262 | uint cnt = mcall->tf()->domain()->cnt(); |
263 | uint j; |
264 | for( j = TypeFunc::Parms; j < cnt; j++) |
265 | if( mcall->in(j) == def ) |
266 | break; // reaching def is an argument oop |
267 | if( j < cnt ) // arg oops dont go in GC map |
268 | continue; // Continue on to the next register |
269 | } |
270 | omap->set_oop(r); |
271 | } else { // Else it's derived. |
272 | // Find the base of the derived value. |
273 | uint i; |
274 | // Fast, common case, scan |
275 | for( i = jvms->oopoff(); i < n->req(); i+=2 ) |
276 | if( n->in(i) == def ) break; // Common case |
277 | if( i == n->req() ) { // Missed, try a more generous scan |
278 | // Scan again, but this time peek through copies |
279 | for( i = jvms->oopoff(); i < n->req(); i+=2 ) { |
280 | Node *m = n->in(i); // Get initial derived value |
281 | while( 1 ) { |
282 | Node *d = def; // Get initial reaching def |
283 | while( 1 ) { // Follow copies of reaching def to end |
284 | if( m == d ) goto found; // breaks 3 loops |
285 | int idx = d->is_Copy(); |
286 | if( !idx ) break; |
287 | d = d->in(idx); // Link through copy |
288 | } |
289 | int idx = m->is_Copy(); |
290 | if( !idx ) break; |
291 | m = m->in(idx); |
292 | } |
293 | } |
294 | guarantee( 0, "must find derived/base pair" )do { if (!(0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 294, "guarantee(" "0" ") failed", "must find derived/base pair" ); ::breakpoint(); } } while (0); |
295 | } |
296 | found: ; |
297 | Node *base = n->in(i+1); // Base is other half of pair |
298 | int breg = regalloc->get_reg_first(base); |
299 | VMReg b = OptoReg::as_VMReg(OptoReg::Name(breg), framesize, max_inarg_slot); |
300 | |
301 | // I record liveness at safepoints BEFORE I make the inputs |
302 | // live. This is because argument oops are NOT live at a |
303 | // safepoint (or at least they cannot appear in the oopmap). |
304 | // Thus bases of base/derived pairs might not be in the |
305 | // liveness data but they need to appear in the oopmap. |
306 | if( get_live_bit(live,breg) == 0 ) {// Not live? |
307 | // Flag it, so next derived pointer won't re-insert into oopmap |
308 | set_live_bit(live,breg); |
309 | // Already missed our turn? |
310 | if( breg < reg ) { |
311 | omap->set_oop(b); |
312 | } |
313 | } |
314 | omap->set_derived_oop(r, b); |
315 | } |
316 | |
317 | } else if( t->isa_narrowoop() ) { |
318 | assert( !OptoReg::is_valid(_callees[reg]), "oop can't be callee save" )do { if (!(!OptoReg::is_valid(_callees[reg]))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 318, "assert(" "!OptoReg::is_valid(_callees[reg])" ") failed" , "oop can't be callee save"); ::breakpoint(); } } while (0); |
319 | // Check for a legal reg name in the oopMap and bailout if it is not. |
320 | if (!omap->legal_vm_reg_name(r)) { |
321 | regalloc->C->record_method_not_compilable("illegal oopMap register name"); |
322 | continue; |
323 | } |
324 | if( mcall ) { |
325 | // Outgoing argument GC mask responsibility belongs to the callee, |
326 | // not the caller. Inspect the inputs to the call, to see if |
327 | // this live-range is one of them. |
328 | uint cnt = mcall->tf()->domain()->cnt(); |
329 | uint j; |
330 | for( j = TypeFunc::Parms; j < cnt; j++) |
331 | if( mcall->in(j) == def ) |
332 | break; // reaching def is an argument oop |
333 | if( j < cnt ) // arg oops dont go in GC map |
334 | continue; // Continue on to the next register |
335 | } |
336 | omap->set_narrowoop(r); |
337 | } else if( OptoReg::is_valid(_callees[reg])) { // callee-save? |
338 | // It's a callee-save value |
339 | assert( dup_check[_callees[reg]]==0, "trying to callee save same reg twice" )do { if (!(dup_check[_callees[reg]]==0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 339, "assert(" "dup_check[_callees[reg]]==0" ") failed", "trying to callee save same reg twice" ); ::breakpoint(); } } while (0); |
340 | debug_only( dup_check[_callees[reg]]=1; )dup_check[_callees[reg]]=1; |
341 | VMReg callee = OptoReg::as_VMReg(OptoReg::Name(_callees[reg])); |
342 | omap->set_callee_saved(r, callee); |
343 | |
344 | } else { |
345 | // Other - some reaching non-oop value |
346 | #ifdef ASSERT1 |
347 | if( t->isa_rawptr() && C->cfg()->_raw_oops.member(def) ) { |
348 | def->dump(); |
349 | n->dump(); |
350 | assert(false, "there should be a oop in OopMap instead of a live raw oop at safepoint")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 350, "assert(" "false" ") failed", "there should be a oop in OopMap instead of a live raw oop at safepoint" ); ::breakpoint(); } } while (0); |
351 | } |
352 | #endif |
353 | } |
354 | |
355 | } |
356 | |
357 | #ifdef ASSERT1 |
358 | /* Nice, Intel-only assert |
359 | int cnt_callee_saves=0; |
360 | int reg2 = 0; |
361 | while (OptoReg::is_reg(reg2)) { |
362 | if( dup_check[reg2] != 0) cnt_callee_saves++; |
363 | assert( cnt_callee_saves==3 || cnt_callee_saves==5, "missed some callee-save" ); |
364 | reg2++; |
365 | } |
366 | */ |
367 | #endif |
368 | |
369 | #ifdef ASSERT1 |
370 | for( OopMapStream oms1(omap); !oms1.is_done(); oms1.next()) { |
371 | OopMapValue omv1 = oms1.current(); |
372 | if (omv1.type() != OopMapValue::derived_oop_value) { |
373 | continue; |
374 | } |
375 | bool found = false; |
376 | for( OopMapStream oms2(omap); !oms2.is_done(); oms2.next()) { |
377 | OopMapValue omv2 = oms2.current(); |
378 | if (omv2.type() != OopMapValue::oop_value) { |
379 | continue; |
380 | } |
381 | if( omv1.content_reg() == omv2.reg() ) { |
382 | found = true; |
383 | break; |
384 | } |
385 | } |
386 | assert( found, "derived with no base in oopmap" )do { if (!(found)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 386, "assert(" "found" ") failed", "derived with no base in oopmap" ); ::breakpoint(); } } while (0); |
387 | } |
388 | #endif |
389 | |
390 | return omap; |
391 | } |
392 | |
393 | // Compute backwards liveness on registers |
394 | static void do_liveness(PhaseRegAlloc* regalloc, PhaseCFG* cfg, Block_List* worklist, int max_reg_ints, Arena* A, Dict* safehash) { |
395 | int* live = NEW_ARENA_ARRAY(A, int, (cfg->number_of_blocks() + 1) * max_reg_ints)(int*) (A)->Amalloc(((cfg->number_of_blocks() + 1) * max_reg_ints ) * sizeof(int)); |
396 | int* tmp_live = &live[cfg->number_of_blocks() * max_reg_ints]; |
397 | Node* root = cfg->get_root_node(); |
398 | // On CISC platforms, get the node representing the stack pointer that regalloc |
399 | // used for spills |
400 | Node *fp = NodeSentinel(Node*)-1; |
401 | if (UseCISCSpill && root->req() > 1) { |
402 | fp = root->in(1)->in(TypeFunc::FramePtr); |
403 | } |
404 | memset(live, 0, cfg->number_of_blocks() * (max_reg_ints << LogBytesPerInt)); |
405 | // Push preds onto worklist |
406 | for (uint i = 1; i < root->req(); i++) { |
407 | Block* block = cfg->get_block_for_node(root->in(i)); |
408 | worklist->push(block); |
409 | } |
410 | |
411 | // ZKM.jar includes tiny infinite loops which are unreached from below. |
412 | // If we missed any blocks, we'll retry here after pushing all missed |
413 | // blocks on the worklist. Normally this outer loop never trips more |
414 | // than once. |
415 | while (1) { |
416 | |
417 | while( worklist->size() ) { // Standard worklist algorithm |
418 | Block *b = worklist->rpop(); |
419 | |
420 | // Copy first successor into my tmp_live space |
421 | int s0num = b->_succs[0]->_pre_order; |
422 | int *t = &live[s0num*max_reg_ints]; |
423 | for( int i=0; i<max_reg_ints; i++ ) |
424 | tmp_live[i] = t[i]; |
425 | |
426 | // OR in the remaining live registers |
427 | for( uint j=1; j<b->_num_succs; j++ ) { |
428 | uint sjnum = b->_succs[j]->_pre_order; |
429 | int *t = &live[sjnum*max_reg_ints]; |
430 | for( int i=0; i<max_reg_ints; i++ ) |
431 | tmp_live[i] |= t[i]; |
432 | } |
433 | |
434 | // Now walk tmp_live up the block backwards, computing live |
435 | for( int k=b->number_of_nodes()-1; k>=0; k-- ) { |
436 | Node *n = b->get_node(k); |
437 | // KILL def'd bits |
438 | int first = regalloc->get_reg_first(n); |
439 | int second = regalloc->get_reg_second(n); |
440 | if( OptoReg::is_valid(first) ) clr_live_bit(tmp_live,first); |
441 | if( OptoReg::is_valid(second) ) clr_live_bit(tmp_live,second); |
442 | |
443 | MachNode *m = n->is_Mach() ? n->as_Mach() : NULL__null; |
444 | |
445 | // Check if m is potentially a CISC alternate instruction (i.e, possibly |
446 | // synthesized by RegAlloc from a conventional instruction and a |
447 | // spilled input) |
448 | bool is_cisc_alternate = false; |
449 | if (UseCISCSpill && m) { |
450 | is_cisc_alternate = m->is_cisc_alternate(); |
451 | } |
452 | |
453 | // GEN use'd bits |
454 | for( uint l=1; l<n->req(); l++ ) { |
455 | Node *def = n->in(l); |
456 | assert(def != 0, "input edge required")do { if (!(def != 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 456, "assert(" "def != 0" ") failed", "input edge required" ); ::breakpoint(); } } while (0); |
457 | int first = regalloc->get_reg_first(def); |
458 | int second = regalloc->get_reg_second(def); |
459 | //If peephole had removed the node,do not set live bit for it. |
460 | if (!(def->is_Mach() && def->as_Mach()->get_removed())) { |
461 | if (OptoReg::is_valid(first)) set_live_bit(tmp_live,first); |
462 | if (OptoReg::is_valid(second)) set_live_bit(tmp_live,second); |
463 | } |
464 | // If we use the stack pointer in a cisc-alternative instruction, |
465 | // check for use as a memory operand. Then reconstruct the RegName |
466 | // for this stack location, and set the appropriate bit in the |
467 | // live vector 4987749. |
468 | if (is_cisc_alternate && def == fp) { |
469 | const TypePtr *adr_type = NULL__null; |
470 | intptr_t offset; |
471 | const Node* base = m->get_base_and_disp(offset, adr_type); |
472 | if (base == NodeSentinel(Node*)-1) { |
473 | // Machnode has multiple memory inputs. We are unable to reason |
474 | // with these, but are presuming (with trepidation) that not any of |
475 | // them are oops. This can be fixed by making get_base_and_disp() |
476 | // look at a specific input instead of all inputs. |
477 | assert(!def->bottom_type()->isa_oop_ptr(), "expecting non-oop mem input")do { if (!(!def->bottom_type()->isa_oop_ptr())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 477, "assert(" "!def->bottom_type()->isa_oop_ptr()" ") failed" , "expecting non-oop mem input"); ::breakpoint(); } } while ( 0); |
478 | } else if (base != fp || offset == Type::OffsetBot) { |
479 | // Do nothing: the fp operand is either not from a memory use |
480 | // (base == NULL) OR the fp is used in a non-memory context |
481 | // (base is some other register) OR the offset is not constant, |
482 | // so it is not a stack slot. |
483 | } else { |
484 | assert(offset >= 0, "unexpected negative offset")do { if (!(offset >= 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 484, "assert(" "offset >= 0" ") failed", "unexpected negative offset" ); ::breakpoint(); } } while (0); |
485 | offset -= (offset % jintSize); // count the whole word |
486 | int stack_reg = regalloc->offset2reg(offset); |
487 | if (OptoReg::is_stack(stack_reg)) { |
488 | set_live_bit(tmp_live, stack_reg); |
489 | } else { |
490 | assert(false, "stack_reg not on stack?")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 490, "assert(" "false" ") failed", "stack_reg not on stack?" ); ::breakpoint(); } } while (0); |
491 | } |
492 | } |
493 | } |
494 | } |
495 | |
496 | if( n->jvms() ) { // Record liveness at safepoint |
497 | |
498 | // This placement of this stanza means inputs to calls are |
499 | // considered live at the callsite's OopMap. Argument oops are |
500 | // hence live, but NOT included in the oopmap. See cutout in |
501 | // build_oop_map. Debug oops are live (and in OopMap). |
502 | int *n_live = NEW_ARENA_ARRAY(A, int, max_reg_ints)(int*) (A)->Amalloc((max_reg_ints) * sizeof(int)); |
503 | for( int l=0; l<max_reg_ints; l++ ) |
504 | n_live[l] = tmp_live[l]; |
505 | safehash->Insert(n,n_live); |
506 | } |
507 | |
508 | } |
509 | |
510 | // Now at block top, see if we have any changes. If so, propagate |
511 | // to prior blocks. |
512 | int *old_live = &live[b->_pre_order*max_reg_ints]; |
513 | int l; |
514 | for( l=0; l<max_reg_ints; l++ ) |
515 | if( tmp_live[l] != old_live[l] ) |
516 | break; |
517 | if( l<max_reg_ints ) { // Change! |
518 | // Copy in new value |
519 | for( l=0; l<max_reg_ints; l++ ) |
520 | old_live[l] = tmp_live[l]; |
521 | // Push preds onto worklist |
522 | for (l = 1; l < (int)b->num_preds(); l++) { |
523 | Block* block = cfg->get_block_for_node(b->pred(l)); |
524 | worklist->push(block); |
525 | } |
526 | } |
527 | } |
528 | |
529 | // Scan for any missing safepoints. Happens to infinite loops |
530 | // ala ZKM.jar |
531 | uint i; |
532 | for (i = 1; i < cfg->number_of_blocks(); i++) { |
533 | Block* block = cfg->get_block(i); |
534 | uint j; |
535 | for (j = 1; j < block->number_of_nodes(); j++) { |
536 | if (block->get_node(j)->jvms() && (*safehash)[block->get_node(j)] == NULL__null) { |
537 | break; |
538 | } |
539 | } |
540 | if (j < block->number_of_nodes()) { |
541 | break; |
542 | } |
543 | } |
544 | if (i == cfg->number_of_blocks()) { |
545 | break; // Got 'em all |
546 | } |
547 | |
548 | if (PrintOpto && Verbose) { |
549 | tty->print_cr("retripping live calc"); |
550 | } |
551 | |
552 | // Force the issue (expensively): recheck everybody |
553 | for (i = 1; i < cfg->number_of_blocks(); i++) { |
554 | worklist->push(cfg->get_block(i)); |
555 | } |
556 | } |
557 | } |
558 | |
559 | // Collect GC mask info - where are all the OOPs? |
560 | void PhaseOutput::BuildOopMaps() { |
561 | Compile::TracePhase tp("bldOopMaps", &timers[_t_buildOopMaps]); |
562 | // Can't resource-mark because I need to leave all those OopMaps around, |
563 | // or else I need to resource-mark some arena other than the default. |
564 | // ResourceMark rm; // Reclaim all OopFlows when done |
565 | int max_reg = C->regalloc()->_max_reg; // Current array extent |
566 | |
567 | Arena *A = Thread::current()->resource_area(); |
568 | Block_List worklist; // Worklist of pending blocks |
569 | |
570 | int max_reg_ints = align_up(max_reg, BitsPerInt)>>LogBitsPerInt; |
571 | Dict *safehash = NULL__null; // Used for assert only |
572 | // Compute a backwards liveness per register. Needs a bitarray of |
573 | // #blocks x (#registers, rounded up to ints) |
574 | safehash = new Dict(cmpkey,hashkey,A); |
575 | do_liveness( C->regalloc(), C->cfg(), &worklist, max_reg_ints, A, safehash ); |
576 | OopFlow *free_list = NULL__null; // Free, unused |
577 | |
578 | // Array mapping blocks to completed oopflows |
579 | OopFlow **flows = NEW_ARENA_ARRAY(A, OopFlow*, C->cfg()->number_of_blocks())(OopFlow**) (A)->Amalloc((C->cfg()->number_of_blocks ()) * sizeof(OopFlow*)); |
580 | memset( flows, 0, C->cfg()->number_of_blocks() * sizeof(OopFlow*) ); |
581 | |
582 | |
583 | // Do the first block 'by hand' to prime the worklist |
584 | Block *entry = C->cfg()->get_block(1); |
585 | OopFlow *rootflow = OopFlow::make(A,max_reg,C); |
586 | // Initialize to 'bottom' (not 'top') |
587 | memset( rootflow->_callees, OptoReg::Bad, max_reg*sizeof(short) ); |
588 | memset( rootflow->_defs , 0, max_reg*sizeof(Node*) ); |
589 | flows[entry->_pre_order] = rootflow; |
590 | |
591 | // Do the first block 'by hand' to prime the worklist |
592 | rootflow->_b = entry; |
593 | rootflow->compute_reach( C->regalloc(), max_reg, safehash ); |
594 | for( uint i=0; i<entry->_num_succs; i++ ) |
595 | worklist.push(entry->_succs[i]); |
596 | |
597 | // Now worklist contains blocks which have some, but perhaps not all, |
598 | // predecessors visited. |
599 | while( worklist.size() ) { |
600 | // Scan for a block with all predecessors visited, or any randoms slob |
601 | // otherwise. All-preds-visited order allows me to recycle OopFlow |
602 | // structures rapidly and cut down on the memory footprint. |
603 | // Note: not all predecessors might be visited yet (must happen for |
604 | // irreducible loops). This is OK, since every live value must have the |
605 | // SAME reaching def for the block, so any reaching def is OK. |
606 | uint i; |
607 | |
608 | Block *b = worklist.pop(); |
609 | // Ignore root block |
610 | if (b == C->cfg()->get_root_block()) { |
611 | continue; |
612 | } |
613 | // Block is already done? Happens if block has several predecessors, |
614 | // he can get on the worklist more than once. |
615 | if( flows[b->_pre_order] ) continue; |
616 | |
617 | // If this block has a visited predecessor AND that predecessor has this |
618 | // last block as his only undone child, we can move the OopFlow from the |
619 | // pred to this block. Otherwise we have to grab a new OopFlow. |
620 | OopFlow *flow = NULL__null; // Flag for finding optimized flow |
621 | Block *pred = (Block*)((intptr_t)0xdeadbeef); |
622 | // Scan this block's preds to find a done predecessor |
623 | for (uint j = 1; j < b->num_preds(); j++) { |
624 | Block* p = C->cfg()->get_block_for_node(b->pred(j)); |
625 | OopFlow *p_flow = flows[p->_pre_order]; |
626 | if( p_flow ) { // Predecessor is done |
627 | assert( p_flow->_b == p, "cross check" )do { if (!(p_flow->_b == p)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 627, "assert(" "p_flow->_b == p" ") failed", "cross check" ); ::breakpoint(); } } while (0); |
628 | pred = p; // Record some predecessor |
629 | // If all successors of p are done except for 'b', then we can carry |
630 | // p_flow forward to 'b' without copying, otherwise we have to draw |
631 | // from the free_list and clone data. |
632 | uint k; |
633 | for( k=0; k<p->_num_succs; k++ ) |
634 | if( !flows[p->_succs[k]->_pre_order] && |
635 | p->_succs[k] != b ) |
636 | break; |
637 | |
638 | // Either carry-forward the now-unused OopFlow for b's use |
639 | // or draw a new one from the free list |
640 | if( k==p->_num_succs ) { |
641 | flow = p_flow; |
642 | break; // Found an ideal pred, use him |
643 | } |
644 | } |
645 | } |
646 | |
647 | if( flow ) { |
648 | // We have an OopFlow that's the last-use of a predecessor. |
649 | // Carry it forward. |
650 | } else { // Draw a new OopFlow from the freelist |
651 | if( !free_list ) |
652 | free_list = OopFlow::make(A,max_reg,C); |
653 | flow = free_list; |
654 | assert( flow->_b == NULL, "oopFlow is not free" )do { if (!(flow->_b == __null)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 654, "assert(" "flow->_b == __null" ") failed", "oopFlow is not free" ); ::breakpoint(); } } while (0); |
655 | free_list = flow->_next; |
656 | flow->_next = NULL__null; |
657 | |
658 | // Copy/clone over the data |
659 | flow->clone(flows[pred->_pre_order], max_reg); |
660 | } |
661 | |
662 | // Mark flow for block. Blocks can only be flowed over once, |
663 | // because after the first time they are guarded from entering |
664 | // this code again. |
665 | assert( flow->_b == pred, "have some prior flow" )do { if (!(flow->_b == pred)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/buildOopMap.cpp" , 665, "assert(" "flow->_b == pred" ") failed", "have some prior flow" ); ::breakpoint(); } } while (0); |
666 | flow->_b = NULL__null; |
667 | |
668 | // Now push flow forward |
669 | flows[b->_pre_order] = flow;// Mark flow for this block |
670 | flow->_b = b; |
671 | flow->compute_reach( C->regalloc(), max_reg, safehash ); |
672 | |
673 | // Now push children onto worklist |
674 | for( i=0; i<b->_num_succs; i++ ) |
675 | worklist.push(b->_succs[i]); |
676 | |
677 | } |
678 | } |