File: | jdk/src/hotspot/share/opto/escape.cpp |
Warning: | line 123, column 13 Value stored to 'igvn' during its initialization is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * Copyright (c) 2005, 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 "ci/bcEscapeAnalyzer.hpp" |
27 | #include "compiler/compileLog.hpp" |
28 | #include "gc/shared/barrierSet.hpp" |
29 | #include "gc/shared/c2/barrierSetC2.hpp" |
30 | #include "libadt/vectset.hpp" |
31 | #include "memory/allocation.hpp" |
32 | #include "memory/resourceArea.hpp" |
33 | #include "opto/c2compiler.hpp" |
34 | #include "opto/arraycopynode.hpp" |
35 | #include "opto/callnode.hpp" |
36 | #include "opto/cfgnode.hpp" |
37 | #include "opto/compile.hpp" |
38 | #include "opto/escape.hpp" |
39 | #include "opto/phaseX.hpp" |
40 | #include "opto/movenode.hpp" |
41 | #include "opto/rootnode.hpp" |
42 | #include "utilities/macros.hpp" |
43 | |
44 | ConnectionGraph::ConnectionGraph(Compile * C, PhaseIterGVN *igvn, int invocation) : |
45 | _nodes(C->comp_arena(), C->unique(), C->unique(), NULL__null), |
46 | _in_worklist(C->comp_arena()), |
47 | _next_pidx(0), |
48 | _collecting(true), |
49 | _verify(false), |
50 | _compile(C), |
51 | _igvn(igvn), |
52 | _invocation(invocation), |
53 | _build_iterations(0), |
54 | _build_time(0.), |
55 | _node_map(C->comp_arena()) { |
56 | // Add unknown java object. |
57 | add_java_object(C->top(), PointsToNode::GlobalEscape); |
58 | phantom_obj = ptnode_adr(C->top()->_idx)->as_JavaObject(); |
59 | // Add ConP(#NULL) and ConN(#NULL) nodes. |
60 | Node* oop_null = igvn->zerocon(T_OBJECT); |
61 | assert(oop_null->_idx < nodes_size(), "should be created already")do { if (!(oop_null->_idx < nodes_size())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 61, "assert(" "oop_null->_idx < nodes_size()" ") failed" , "should be created already"); ::breakpoint(); } } while (0); |
62 | add_java_object(oop_null, PointsToNode::NoEscape); |
63 | null_obj = ptnode_adr(oop_null->_idx)->as_JavaObject(); |
64 | if (UseCompressedOops) { |
65 | Node* noop_null = igvn->zerocon(T_NARROWOOP); |
66 | assert(noop_null->_idx < nodes_size(), "should be created already")do { if (!(noop_null->_idx < nodes_size())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 66, "assert(" "noop_null->_idx < nodes_size()" ") failed" , "should be created already"); ::breakpoint(); } } while (0); |
67 | map_ideal_node(noop_null, null_obj); |
68 | } |
69 | } |
70 | |
71 | bool ConnectionGraph::has_candidates(Compile *C) { |
72 | // EA brings benefits only when the code has allocations and/or locks which |
73 | // are represented by ideal Macro nodes. |
74 | int cnt = C->macro_count(); |
75 | for (int i = 0; i < cnt; i++) { |
76 | Node *n = C->macro_node(i); |
77 | if (n->is_Allocate()) { |
78 | return true; |
79 | } |
80 | if (n->is_Lock()) { |
81 | Node* obj = n->as_Lock()->obj_node()->uncast(); |
82 | if (!(obj->is_Parm() || obj->is_Con())) { |
83 | return true; |
84 | } |
85 | } |
86 | if (n->is_CallStaticJava() && |
87 | n->as_CallStaticJava()->is_boxing_method()) { |
88 | return true; |
89 | } |
90 | } |
91 | return false; |
92 | } |
93 | |
94 | void ConnectionGraph::do_analysis(Compile *C, PhaseIterGVN *igvn) { |
95 | Compile::TracePhase tp("escapeAnalysis", &Phase::timers[Phase::_t_escapeAnalysis]); |
96 | ResourceMark rm; |
97 | |
98 | // Add ConP#NULL and ConN#NULL nodes before ConnectionGraph construction |
99 | // to create space for them in ConnectionGraph::_nodes[]. |
100 | Node* oop_null = igvn->zerocon(T_OBJECT); |
101 | Node* noop_null = igvn->zerocon(T_NARROWOOP); |
102 | int invocation = 0; |
103 | if (C->congraph() != NULL__null) { |
104 | invocation = C->congraph()->_invocation + 1; |
105 | } |
106 | ConnectionGraph* congraph = new(C->comp_arena()) ConnectionGraph(C, igvn, invocation); |
107 | // Perform escape analysis |
108 | if (congraph->compute_escape()) { |
109 | // There are non escaping objects. |
110 | C->set_congraph(congraph); |
111 | } |
112 | // Cleanup. |
113 | if (oop_null->outcnt() == 0) { |
114 | igvn->hash_delete(oop_null); |
115 | } |
116 | if (noop_null->outcnt() == 0) { |
117 | igvn->hash_delete(noop_null); |
118 | } |
119 | } |
120 | |
121 | bool ConnectionGraph::compute_escape() { |
122 | Compile* C = _compile; |
123 | PhaseGVN* igvn = _igvn; |
Value stored to 'igvn' during its initialization is never read | |
124 | |
125 | // Worklists used by EA. |
126 | Unique_Node_List delayed_worklist; |
127 | GrowableArray<Node*> alloc_worklist; |
128 | GrowableArray<Node*> ptr_cmp_worklist; |
129 | GrowableArray<MemBarStoreStoreNode*> storestore_worklist; |
130 | GrowableArray<ArrayCopyNode*> arraycopy_worklist; |
131 | GrowableArray<PointsToNode*> ptnodes_worklist; |
132 | GrowableArray<JavaObjectNode*> java_objects_worklist; |
133 | GrowableArray<JavaObjectNode*> non_escaped_allocs_worklist; |
134 | GrowableArray<FieldNode*> oop_fields_worklist; |
135 | GrowableArray<SafePointNode*> sfn_worklist; |
136 | GrowableArray<MergeMemNode*> mergemem_worklist; |
137 | DEBUG_ONLY( GrowableArray<Node*> addp_worklist; )GrowableArray<Node*> addp_worklist; |
138 | |
139 | { Compile::TracePhase tp("connectionGraph", &Phase::timers[Phase::_t_connectionGraph]); |
140 | |
141 | // 1. Populate Connection Graph (CG) with PointsTo nodes. |
142 | ideal_nodes.map(C->live_nodes(), NULL__null); // preallocate space |
143 | // Initialize worklist |
144 | if (C->root() != NULL__null) { |
145 | ideal_nodes.push(C->root()); |
146 | } |
147 | // Processed ideal nodes are unique on ideal_nodes list |
148 | // but several ideal nodes are mapped to the phantom_obj. |
149 | // To avoid duplicated entries on the following worklists |
150 | // add the phantom_obj only once to them. |
151 | ptnodes_worklist.append(phantom_obj); |
152 | java_objects_worklist.append(phantom_obj); |
153 | for( uint next = 0; next < ideal_nodes.size(); ++next ) { |
154 | Node* n = ideal_nodes.at(next); |
155 | // Create PointsTo nodes and add them to Connection Graph. Called |
156 | // only once per ideal node since ideal_nodes is Unique_Node list. |
157 | add_node_to_connection_graph(n, &delayed_worklist); |
158 | PointsToNode* ptn = ptnode_adr(n->_idx); |
159 | if (ptn != NULL__null && ptn != phantom_obj) { |
160 | ptnodes_worklist.append(ptn); |
161 | if (ptn->is_JavaObject()) { |
162 | java_objects_worklist.append(ptn->as_JavaObject()); |
163 | if ((n->is_Allocate() || n->is_CallStaticJava()) && |
164 | (ptn->escape_state() < PointsToNode::GlobalEscape)) { |
165 | // Only allocations and java static calls results are interesting. |
166 | non_escaped_allocs_worklist.append(ptn->as_JavaObject()); |
167 | } |
168 | } else if (ptn->is_Field() && ptn->as_Field()->is_oop()) { |
169 | oop_fields_worklist.append(ptn->as_Field()); |
170 | } |
171 | } |
172 | // Collect some interesting nodes for futher use. |
173 | switch (n->Opcode()) { |
174 | case Op_MergeMem: |
175 | // Collect all MergeMem nodes to add memory slices for |
176 | // scalar replaceable objects in split_unique_types(). |
177 | mergemem_worklist.append(n->as_MergeMem()); |
178 | break; |
179 | case Op_CmpP: |
180 | case Op_CmpN: |
181 | // Collect compare pointers nodes. |
182 | if (OptimizePtrCompare) { |
183 | ptr_cmp_worklist.append(n); |
184 | } |
185 | break; |
186 | case Op_MemBarStoreStore: |
187 | // Collect all MemBarStoreStore nodes so that depending on the |
188 | // escape status of the associated Allocate node some of them |
189 | // may be eliminated. |
190 | storestore_worklist.append(n->as_MemBarStoreStore()); |
191 | break; |
192 | case Op_MemBarRelease: |
193 | if (n->req() > MemBarNode::Precedent) { |
194 | record_for_optimizer(n); |
195 | } |
196 | break; |
197 | #ifdef ASSERT1 |
198 | case Op_AddP: |
199 | // Collect address nodes for graph verification. |
200 | addp_worklist.append(n); |
201 | break; |
202 | #endif |
203 | case Op_ArrayCopy: |
204 | // Keep a list of ArrayCopy nodes so if one of its input is non |
205 | // escaping, we can record a unique type |
206 | arraycopy_worklist.append(n->as_ArrayCopy()); |
207 | break; |
208 | default: |
209 | // not interested now, ignore... |
210 | break; |
211 | } |
212 | for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
213 | Node* m = n->fast_out(i); // Get user |
214 | ideal_nodes.push(m); |
215 | } |
216 | if (n->is_SafePoint()) { |
217 | sfn_worklist.append(n->as_SafePoint()); |
218 | } |
219 | } |
220 | if (non_escaped_allocs_worklist.length() == 0) { |
221 | _collecting = false; |
222 | return false; // Nothing to do. |
223 | } |
224 | // Add final simple edges to graph. |
225 | while(delayed_worklist.size() > 0) { |
226 | Node* n = delayed_worklist.pop(); |
227 | add_final_edges(n); |
228 | } |
229 | |
230 | #ifdef ASSERT1 |
231 | if (VerifyConnectionGraph) { |
232 | // Verify that no new simple edges could be created and all |
233 | // local vars has edges. |
234 | _verify = true; |
235 | int ptnodes_length = ptnodes_worklist.length(); |
236 | for (int next = 0; next < ptnodes_length; ++next) { |
237 | PointsToNode* ptn = ptnodes_worklist.at(next); |
238 | add_final_edges(ptn->ideal_node()); |
239 | if (ptn->is_LocalVar() && ptn->edge_count() == 0) { |
240 | ptn->dump(); |
241 | assert(ptn->as_LocalVar()->edge_count() > 0, "sanity")do { if (!(ptn->as_LocalVar()->edge_count() > 0)) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 241, "assert(" "ptn->as_LocalVar()->edge_count() > 0" ") failed", "sanity"); ::breakpoint(); } } while (0); |
242 | } |
243 | } |
244 | _verify = false; |
245 | } |
246 | #endif |
247 | // Bytecode analyzer BCEscapeAnalyzer, used for Call nodes |
248 | // processing, calls to CI to resolve symbols (types, fields, methods) |
249 | // referenced in bytecode. During symbol resolution VM may throw |
250 | // an exception which CI cleans and converts to compilation failure. |
251 | if (C->failing()) return false; |
252 | |
253 | // 2. Finish Graph construction by propagating references to all |
254 | // java objects through graph. |
255 | if (!complete_connection_graph(ptnodes_worklist, non_escaped_allocs_worklist, |
256 | java_objects_worklist, oop_fields_worklist)) { |
257 | // All objects escaped or hit time or iterations limits. |
258 | _collecting = false; |
259 | return false; |
260 | } |
261 | |
262 | // 3. Adjust scalar_replaceable state of nonescaping objects and push |
263 | // scalar replaceable allocations on alloc_worklist for processing |
264 | // in split_unique_types(). |
265 | int non_escaped_length = non_escaped_allocs_worklist.length(); |
266 | for (int next = 0; next < non_escaped_length; next++) { |
267 | JavaObjectNode* ptn = non_escaped_allocs_worklist.at(next); |
268 | bool noescape = (ptn->escape_state() == PointsToNode::NoEscape); |
269 | Node* n = ptn->ideal_node(); |
270 | if (n->is_Allocate()) { |
271 | n->as_Allocate()->_is_non_escaping = noescape; |
272 | } |
273 | if (noescape && ptn->scalar_replaceable()) { |
274 | adjust_scalar_replaceable_state(ptn); |
275 | if (ptn->scalar_replaceable()) { |
276 | alloc_worklist.append(ptn->ideal_node()); |
277 | } |
278 | } |
279 | } |
280 | |
281 | #ifdef ASSERT1 |
282 | if (VerifyConnectionGraph) { |
283 | // Verify that graph is complete - no new edges could be added or needed. |
284 | verify_connection_graph(ptnodes_worklist, non_escaped_allocs_worklist, |
285 | java_objects_worklist, addp_worklist); |
286 | } |
287 | assert(C->unique() == nodes_size(), "no new ideal nodes should be added during ConnectionGraph build")do { if (!(C->unique() == nodes_size())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 287, "assert(" "C->unique() == nodes_size()" ") failed", "no new ideal nodes should be added during ConnectionGraph build" ); ::breakpoint(); } } while (0); |
288 | assert(null_obj->escape_state() == PointsToNode::NoEscape &&do { if (!(null_obj->escape_state() == PointsToNode::NoEscape && null_obj->edge_count() == 0 && !null_obj ->arraycopy_src() && !null_obj->arraycopy_dst() )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 291, "assert(" "null_obj->escape_state() == PointsToNode::NoEscape && null_obj->edge_count() == 0 && !null_obj->arraycopy_src() && !null_obj->arraycopy_dst()" ") failed", "sanity"); ::breakpoint(); } } while (0) |
289 | null_obj->edge_count() == 0 &&do { if (!(null_obj->escape_state() == PointsToNode::NoEscape && null_obj->edge_count() == 0 && !null_obj ->arraycopy_src() && !null_obj->arraycopy_dst() )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 291, "assert(" "null_obj->escape_state() == PointsToNode::NoEscape && null_obj->edge_count() == 0 && !null_obj->arraycopy_src() && !null_obj->arraycopy_dst()" ") failed", "sanity"); ::breakpoint(); } } while (0) |
290 | !null_obj->arraycopy_src() &&do { if (!(null_obj->escape_state() == PointsToNode::NoEscape && null_obj->edge_count() == 0 && !null_obj ->arraycopy_src() && !null_obj->arraycopy_dst() )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 291, "assert(" "null_obj->escape_state() == PointsToNode::NoEscape && null_obj->edge_count() == 0 && !null_obj->arraycopy_src() && !null_obj->arraycopy_dst()" ") failed", "sanity"); ::breakpoint(); } } while (0) |
291 | !null_obj->arraycopy_dst(), "sanity")do { if (!(null_obj->escape_state() == PointsToNode::NoEscape && null_obj->edge_count() == 0 && !null_obj ->arraycopy_src() && !null_obj->arraycopy_dst() )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 291, "assert(" "null_obj->escape_state() == PointsToNode::NoEscape && null_obj->edge_count() == 0 && !null_obj->arraycopy_src() && !null_obj->arraycopy_dst()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
292 | #endif |
293 | |
294 | _collecting = false; |
295 | |
296 | } // TracePhase t3("connectionGraph") |
297 | |
298 | // 4. Optimize ideal graph based on EA information. |
299 | bool has_non_escaping_obj = (non_escaped_allocs_worklist.length() > 0); |
300 | if (has_non_escaping_obj) { |
301 | optimize_ideal_graph(ptr_cmp_worklist, storestore_worklist); |
302 | } |
303 | |
304 | #ifndef PRODUCT |
305 | if (PrintEscapeAnalysis) { |
306 | dump(ptnodes_worklist); // Dump ConnectionGraph |
307 | } |
308 | #endif |
309 | |
310 | #ifdef ASSERT1 |
311 | if (VerifyConnectionGraph) { |
312 | int alloc_length = alloc_worklist.length(); |
313 | for (int next = 0; next < alloc_length; ++next) { |
314 | Node* n = alloc_worklist.at(next); |
315 | PointsToNode* ptn = ptnode_adr(n->_idx); |
316 | assert(ptn->escape_state() == PointsToNode::NoEscape && ptn->scalar_replaceable(), "sanity")do { if (!(ptn->escape_state() == PointsToNode::NoEscape && ptn->scalar_replaceable())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 316, "assert(" "ptn->escape_state() == PointsToNode::NoEscape && ptn->scalar_replaceable()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
317 | } |
318 | } |
319 | #endif |
320 | |
321 | // 5. Separate memory graph for scalar replaceable allcations. |
322 | bool has_scalar_replaceable_candidates = (alloc_worklist.length() > 0); |
323 | if (has_scalar_replaceable_candidates && |
324 | C->AliasLevel() >= 3 && EliminateAllocations) { |
325 | // Now use the escape information to create unique types for |
326 | // scalar replaceable objects. |
327 | split_unique_types(alloc_worklist, arraycopy_worklist, mergemem_worklist); |
328 | if (C->failing()) return false; |
329 | C->print_method(PHASE_AFTER_EA, 2); |
330 | |
331 | #ifdef ASSERT1 |
332 | } else if (Verbose && (PrintEscapeAnalysis || PrintEliminateAllocations)) { |
333 | tty->print("=== No allocations eliminated for "); |
334 | C->method()->print_short_name(); |
335 | if (!EliminateAllocations) { |
336 | tty->print(" since EliminateAllocations is off ==="); |
337 | } else if(!has_scalar_replaceable_candidates) { |
338 | tty->print(" since there are no scalar replaceable candidates ==="); |
339 | } else if(C->AliasLevel() < 3) { |
340 | tty->print(" since AliasLevel < 3 ==="); |
341 | } |
342 | tty->cr(); |
343 | #endif |
344 | } |
345 | |
346 | // Annotate at safepoints if they have <= ArgEscape objects in their scope and at |
347 | // java calls if they pass ArgEscape objects as parameters. |
348 | if (has_non_escaping_obj && |
349 | (C->env()->should_retain_local_variables() || |
350 | C->env()->jvmti_can_get_owned_monitor_info() || |
351 | C->env()->jvmti_can_walk_any_space() || |
352 | DeoptimizeObjectsALot)) { |
353 | int sfn_length = sfn_worklist.length(); |
354 | for (int next = 0; next < sfn_length; next++) { |
355 | SafePointNode* sfn = sfn_worklist.at(next); |
356 | sfn->set_has_ea_local_in_scope(has_ea_local_in_scope(sfn)); |
357 | if (sfn->is_CallJava()) { |
358 | CallJavaNode* call = sfn->as_CallJava(); |
359 | call->set_arg_escape(has_arg_escape(call)); |
360 | } |
361 | } |
362 | } |
363 | |
364 | return has_non_escaping_obj; |
365 | } |
366 | |
367 | // Returns true if there is an object in the scope of sfn that does not escape globally. |
368 | bool ConnectionGraph::has_ea_local_in_scope(SafePointNode* sfn) { |
369 | Compile* C = _compile; |
370 | for (JVMState* jvms = sfn->jvms(); jvms != NULL__null; jvms = jvms->caller()) { |
371 | if (C->env()->should_retain_local_variables() || C->env()->jvmti_can_walk_any_space() || |
372 | DeoptimizeObjectsALot) { |
373 | // Jvmti agents can access locals. Must provide info about local objects at runtime. |
374 | int num_locs = jvms->loc_size(); |
375 | for (int idx = 0; idx < num_locs; idx++) { |
376 | Node* l = sfn->local(jvms, idx); |
377 | if (not_global_escape(l)) { |
378 | return true; |
379 | } |
380 | } |
381 | } |
382 | if (C->env()->jvmti_can_get_owned_monitor_info() || |
383 | C->env()->jvmti_can_walk_any_space() || DeoptimizeObjectsALot) { |
384 | // Jvmti agents can read monitors. Must provide info about locked objects at runtime. |
385 | int num_mon = jvms->nof_monitors(); |
386 | for (int idx = 0; idx < num_mon; idx++) { |
387 | Node* m = sfn->monitor_obj(jvms, idx); |
388 | if (m != NULL__null && not_global_escape(m)) { |
389 | return true; |
390 | } |
391 | } |
392 | } |
393 | } |
394 | return false; |
395 | } |
396 | |
397 | // Returns true if at least one of the arguments to the call is an object |
398 | // that does not escape globally. |
399 | bool ConnectionGraph::has_arg_escape(CallJavaNode* call) { |
400 | if (call->method() != NULL__null) { |
401 | uint max_idx = TypeFunc::Parms + call->method()->arg_size(); |
402 | for (uint idx = TypeFunc::Parms; idx < max_idx; idx++) { |
403 | Node* p = call->in(idx); |
404 | if (not_global_escape(p)) { |
405 | return true; |
406 | } |
407 | } |
408 | } else { |
409 | const char* name = call->as_CallStaticJava()->_name; |
410 | assert(name != NULL, "no name")do { if (!(name != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 410, "assert(" "name != __null" ") failed", "no name"); ::breakpoint (); } } while (0); |
411 | // no arg escapes through uncommon traps |
412 | if (strcmp(name, "uncommon_trap") != 0) { |
413 | // process_call_arguments() assumes that all arguments escape globally |
414 | const TypeTuple* d = call->tf()->domain(); |
415 | for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { |
416 | const Type* at = d->field_at(i); |
417 | if (at->isa_oopptr() != NULL__null) { |
418 | return true; |
419 | } |
420 | } |
421 | } |
422 | } |
423 | return false; |
424 | } |
425 | |
426 | |
427 | |
428 | // Utility function for nodes that load an object |
429 | void ConnectionGraph::add_objload_to_connection_graph(Node *n, Unique_Node_List *delayed_worklist) { |
430 | // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because |
431 | // ThreadLocal has RawPtr type. |
432 | const Type* t = _igvn->type(n); |
433 | if (t->make_ptr() != NULL__null) { |
434 | Node* adr = n->in(MemNode::Address); |
435 | #ifdef ASSERT1 |
436 | if (!adr->is_AddP()) { |
437 | assert(_igvn->type(adr)->isa_rawptr(), "sanity")do { if (!(_igvn->type(adr)->isa_rawptr())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 437, "assert(" "_igvn->type(adr)->isa_rawptr()" ") failed" , "sanity"); ::breakpoint(); } } while (0); |
438 | } else { |
439 | assert((ptnode_adr(adr->_idx) == NULL ||do { if (!((ptnode_adr(adr->_idx) == __null || ptnode_adr( adr->_idx)->as_Field()->is_oop()))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 440, "assert(" "(ptnode_adr(adr->_idx) == __null || ptnode_adr(adr->_idx)->as_Field()->is_oop())" ") failed", "sanity"); ::breakpoint(); } } while (0) |
440 | ptnode_adr(adr->_idx)->as_Field()->is_oop()), "sanity")do { if (!((ptnode_adr(adr->_idx) == __null || ptnode_adr( adr->_idx)->as_Field()->is_oop()))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 440, "assert(" "(ptnode_adr(adr->_idx) == __null || ptnode_adr(adr->_idx)->as_Field()->is_oop())" ") failed", "sanity"); ::breakpoint(); } } while (0); |
441 | } |
442 | #endif |
443 | add_local_var_and_edge(n, PointsToNode::NoEscape, |
444 | adr, delayed_worklist); |
445 | } |
446 | } |
447 | |
448 | // Populate Connection Graph with PointsTo nodes and create simple |
449 | // connection graph edges. |
450 | void ConnectionGraph::add_node_to_connection_graph(Node *n, Unique_Node_List *delayed_worklist) { |
451 | assert(!_verify, "this method should not be called for verification")do { if (!(!_verify)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 451, "assert(" "!_verify" ") failed", "this method should not be called for verification" ); ::breakpoint(); } } while (0); |
452 | PhaseGVN* igvn = _igvn; |
453 | uint n_idx = n->_idx; |
454 | PointsToNode* n_ptn = ptnode_adr(n_idx); |
455 | if (n_ptn != NULL__null) { |
456 | return; // No need to redefine PointsTo node during first iteration. |
457 | } |
458 | int opcode = n->Opcode(); |
459 | bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->escape_add_to_con_graph(this, igvn, delayed_worklist, n, opcode); |
460 | if (gc_handled) { |
461 | return; // Ignore node if already handled by GC. |
462 | } |
463 | |
464 | if (n->is_Call()) { |
465 | // Arguments to allocation and locking don't escape. |
466 | if (n->is_AbstractLock()) { |
467 | // Put Lock and Unlock nodes on IGVN worklist to process them during |
468 | // first IGVN optimization when escape information is still available. |
469 | record_for_optimizer(n); |
470 | } else if (n->is_Allocate()) { |
471 | add_call_node(n->as_Call()); |
472 | record_for_optimizer(n); |
473 | } else { |
474 | if (n->is_CallStaticJava()) { |
475 | const char* name = n->as_CallStaticJava()->_name; |
476 | if (name != NULL__null && strcmp(name, "uncommon_trap") == 0) { |
477 | return; // Skip uncommon traps |
478 | } |
479 | } |
480 | // Don't mark as processed since call's arguments have to be processed. |
481 | delayed_worklist->push(n); |
482 | // Check if a call returns an object. |
483 | if ((n->as_Call()->returns_pointer() && |
484 | n->as_Call()->proj_out_or_null(TypeFunc::Parms) != NULL__null) || |
485 | (n->is_CallStaticJava() && |
486 | n->as_CallStaticJava()->is_boxing_method())) { |
487 | add_call_node(n->as_Call()); |
488 | } |
489 | } |
490 | return; |
491 | } |
492 | // Put this check here to process call arguments since some call nodes |
493 | // point to phantom_obj. |
494 | if (n_ptn == phantom_obj || n_ptn == null_obj) { |
495 | return; // Skip predefined nodes. |
496 | } |
497 | switch (opcode) { |
498 | case Op_AddP: { |
499 | Node* base = get_addp_base(n); |
500 | PointsToNode* ptn_base = ptnode_adr(base->_idx); |
501 | // Field nodes are created for all field types. They are used in |
502 | // adjust_scalar_replaceable_state() and split_unique_types(). |
503 | // Note, non-oop fields will have only base edges in Connection |
504 | // Graph because such fields are not used for oop loads and stores. |
505 | int offset = address_offset(n, igvn); |
506 | add_field(n, PointsToNode::NoEscape, offset); |
507 | if (ptn_base == NULL__null) { |
508 | delayed_worklist->push(n); // Process it later. |
509 | } else { |
510 | n_ptn = ptnode_adr(n_idx); |
511 | add_base(n_ptn->as_Field(), ptn_base); |
512 | } |
513 | break; |
514 | } |
515 | case Op_CastX2P: { |
516 | map_ideal_node(n, phantom_obj); |
517 | break; |
518 | } |
519 | case Op_CastPP: |
520 | case Op_CheckCastPP: |
521 | case Op_EncodeP: |
522 | case Op_DecodeN: |
523 | case Op_EncodePKlass: |
524 | case Op_DecodeNKlass: { |
525 | add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), delayed_worklist); |
526 | break; |
527 | } |
528 | case Op_CMoveP: { |
529 | add_local_var(n, PointsToNode::NoEscape); |
530 | // Do not add edges during first iteration because some could be |
531 | // not defined yet. |
532 | delayed_worklist->push(n); |
533 | break; |
534 | } |
535 | case Op_ConP: |
536 | case Op_ConN: |
537 | case Op_ConNKlass: { |
538 | // assume all oop constants globally escape except for null |
539 | PointsToNode::EscapeState es; |
540 | const Type* t = igvn->type(n); |
541 | if (t == TypePtr::NULL_PTR || t == TypeNarrowOop::NULL_PTR) { |
542 | es = PointsToNode::NoEscape; |
543 | } else { |
544 | es = PointsToNode::GlobalEscape; |
545 | } |
546 | add_java_object(n, es); |
547 | break; |
548 | } |
549 | case Op_CreateEx: { |
550 | // assume that all exception objects globally escape |
551 | map_ideal_node(n, phantom_obj); |
552 | break; |
553 | } |
554 | case Op_LoadKlass: |
555 | case Op_LoadNKlass: { |
556 | // Unknown class is loaded |
557 | map_ideal_node(n, phantom_obj); |
558 | break; |
559 | } |
560 | case Op_LoadP: |
561 | case Op_LoadN: |
562 | case Op_LoadPLocked: { |
563 | add_objload_to_connection_graph(n, delayed_worklist); |
564 | break; |
565 | } |
566 | case Op_Parm: { |
567 | map_ideal_node(n, phantom_obj); |
568 | break; |
569 | } |
570 | case Op_PartialSubtypeCheck: { |
571 | // Produces Null or notNull and is used in only in CmpP so |
572 | // phantom_obj could be used. |
573 | map_ideal_node(n, phantom_obj); // Result is unknown |
574 | break; |
575 | } |
576 | case Op_Phi: { |
577 | // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because |
578 | // ThreadLocal has RawPtr type. |
579 | const Type* t = n->as_Phi()->type(); |
580 | if (t->make_ptr() != NULL__null) { |
581 | add_local_var(n, PointsToNode::NoEscape); |
582 | // Do not add edges during first iteration because some could be |
583 | // not defined yet. |
584 | delayed_worklist->push(n); |
585 | } |
586 | break; |
587 | } |
588 | case Op_Proj: { |
589 | // we are only interested in the oop result projection from a call |
590 | if (n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() && |
591 | n->in(0)->as_Call()->returns_pointer()) { |
592 | add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), delayed_worklist); |
593 | } |
594 | break; |
595 | } |
596 | case Op_Rethrow: // Exception object escapes |
597 | case Op_Return: { |
598 | if (n->req() > TypeFunc::Parms && |
599 | igvn->type(n->in(TypeFunc::Parms))->isa_oopptr()) { |
600 | // Treat Return value as LocalVar with GlobalEscape escape state. |
601 | add_local_var_and_edge(n, PointsToNode::GlobalEscape, n->in(TypeFunc::Parms), delayed_worklist); |
602 | } |
603 | break; |
604 | } |
605 | case Op_CompareAndExchangeP: |
606 | case Op_CompareAndExchangeN: |
607 | case Op_GetAndSetP: |
608 | case Op_GetAndSetN: { |
609 | add_objload_to_connection_graph(n, delayed_worklist); |
610 | // fall-through |
611 | } |
612 | case Op_StoreP: |
613 | case Op_StoreN: |
614 | case Op_StoreNKlass: |
615 | case Op_StorePConditional: |
616 | case Op_WeakCompareAndSwapP: |
617 | case Op_WeakCompareAndSwapN: |
618 | case Op_CompareAndSwapP: |
619 | case Op_CompareAndSwapN: { |
620 | add_to_congraph_unsafe_access(n, opcode, delayed_worklist); |
621 | break; |
622 | } |
623 | case Op_AryEq: |
624 | case Op_HasNegatives: |
625 | case Op_StrComp: |
626 | case Op_StrEquals: |
627 | case Op_StrIndexOf: |
628 | case Op_StrIndexOfChar: |
629 | case Op_StrInflatedCopy: |
630 | case Op_StrCompressedCopy: |
631 | case Op_EncodeISOArray: { |
632 | add_local_var(n, PointsToNode::ArgEscape); |
633 | delayed_worklist->push(n); // Process it later. |
634 | break; |
635 | } |
636 | case Op_ThreadLocal: { |
637 | add_java_object(n, PointsToNode::ArgEscape); |
638 | break; |
639 | } |
640 | default: |
641 | ; // Do nothing for nodes not related to EA. |
642 | } |
643 | return; |
644 | } |
645 | |
646 | // Add final simple edges to graph. |
647 | void ConnectionGraph::add_final_edges(Node *n) { |
648 | PointsToNode* n_ptn = ptnode_adr(n->_idx); |
649 | #ifdef ASSERT1 |
650 | if (_verify && n_ptn->is_JavaObject()) |
651 | return; // This method does not change graph for JavaObject. |
652 | #endif |
653 | |
654 | if (n->is_Call()) { |
655 | process_call_arguments(n->as_Call()); |
656 | return; |
657 | } |
658 | assert(n->is_Store() || n->is_LoadStore() ||do { if (!(n->is_Store() || n->is_LoadStore() || (n_ptn != __null) && (n_ptn->ideal_node() != __null))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 660, "assert(" "n->is_Store() || n->is_LoadStore() || (n_ptn != __null) && (n_ptn->ideal_node() != __null)" ") failed", "node should be registered already"); ::breakpoint (); } } while (0) |
659 | (n_ptn != NULL) && (n_ptn->ideal_node() != NULL),do { if (!(n->is_Store() || n->is_LoadStore() || (n_ptn != __null) && (n_ptn->ideal_node() != __null))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 660, "assert(" "n->is_Store() || n->is_LoadStore() || (n_ptn != __null) && (n_ptn->ideal_node() != __null)" ") failed", "node should be registered already"); ::breakpoint (); } } while (0) |
660 | "node should be registered already")do { if (!(n->is_Store() || n->is_LoadStore() || (n_ptn != __null) && (n_ptn->ideal_node() != __null))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 660, "assert(" "n->is_Store() || n->is_LoadStore() || (n_ptn != __null) && (n_ptn->ideal_node() != __null)" ") failed", "node should be registered already"); ::breakpoint (); } } while (0); |
661 | int opcode = n->Opcode(); |
662 | bool gc_handled = BarrierSet::barrier_set()->barrier_set_c2()->escape_add_final_edges(this, _igvn, n, opcode); |
663 | if (gc_handled) { |
664 | return; // Ignore node if already handled by GC. |
665 | } |
666 | switch (opcode) { |
667 | case Op_AddP: { |
668 | Node* base = get_addp_base(n); |
669 | PointsToNode* ptn_base = ptnode_adr(base->_idx); |
670 | assert(ptn_base != NULL, "field's base should be registered")do { if (!(ptn_base != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 670, "assert(" "ptn_base != __null" ") failed", "field's base should be registered" ); ::breakpoint(); } } while (0); |
671 | add_base(n_ptn->as_Field(), ptn_base); |
672 | break; |
673 | } |
674 | case Op_CastPP: |
675 | case Op_CheckCastPP: |
676 | case Op_EncodeP: |
677 | case Op_DecodeN: |
678 | case Op_EncodePKlass: |
679 | case Op_DecodeNKlass: { |
680 | add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(1), NULL__null); |
681 | break; |
682 | } |
683 | case Op_CMoveP: { |
684 | for (uint i = CMoveNode::IfFalse; i < n->req(); i++) { |
685 | Node* in = n->in(i); |
686 | if (in == NULL__null) { |
687 | continue; // ignore NULL |
688 | } |
689 | Node* uncast_in = in->uncast(); |
690 | if (uncast_in->is_top() || uncast_in == n) { |
691 | continue; // ignore top or inputs which go back this node |
692 | } |
693 | PointsToNode* ptn = ptnode_adr(in->_idx); |
694 | assert(ptn != NULL, "node should be registered")do { if (!(ptn != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 694, "assert(" "ptn != __null" ") failed", "node should be registered" ); ::breakpoint(); } } while (0); |
695 | add_edge(n_ptn, ptn); |
696 | } |
697 | break; |
698 | } |
699 | case Op_LoadP: |
700 | case Op_LoadN: |
701 | case Op_LoadPLocked: { |
702 | // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because |
703 | // ThreadLocal has RawPtr type. |
704 | assert(_igvn->type(n)->make_ptr() != NULL, "Unexpected node type")do { if (!(_igvn->type(n)->make_ptr() != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 704, "assert(" "_igvn->type(n)->make_ptr() != __null" ") failed", "Unexpected node type"); ::breakpoint(); } } while (0); |
705 | add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(MemNode::Address), NULL__null); |
706 | break; |
707 | } |
708 | case Op_Phi: { |
709 | // Using isa_ptr() instead of isa_oopptr() for LoadP and Phi because |
710 | // ThreadLocal has RawPtr type. |
711 | assert(n->as_Phi()->type()->make_ptr() != NULL, "Unexpected node type")do { if (!(n->as_Phi()->type()->make_ptr() != __null )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 711, "assert(" "n->as_Phi()->type()->make_ptr() != __null" ") failed", "Unexpected node type"); ::breakpoint(); } } while (0); |
712 | for (uint i = 1; i < n->req(); i++) { |
713 | Node* in = n->in(i); |
714 | if (in == NULL__null) { |
715 | continue; // ignore NULL |
716 | } |
717 | Node* uncast_in = in->uncast(); |
718 | if (uncast_in->is_top() || uncast_in == n) { |
719 | continue; // ignore top or inputs which go back this node |
720 | } |
721 | PointsToNode* ptn = ptnode_adr(in->_idx); |
722 | assert(ptn != NULL, "node should be registered")do { if (!(ptn != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 722, "assert(" "ptn != __null" ") failed", "node should be registered" ); ::breakpoint(); } } while (0); |
723 | add_edge(n_ptn, ptn); |
724 | } |
725 | break; |
726 | } |
727 | case Op_Proj: { |
728 | // we are only interested in the oop result projection from a call |
729 | assert(n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() &&do { if (!(n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() && n->in(0)->as_Call ()->returns_pointer())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 730, "assert(" "n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() && n->in(0)->as_Call()->returns_pointer()" ") failed", "Unexpected node type"); ::breakpoint(); } } while (0) |
730 | n->in(0)->as_Call()->returns_pointer(), "Unexpected node type")do { if (!(n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() && n->in(0)->as_Call ()->returns_pointer())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 730, "assert(" "n->as_Proj()->_con == TypeFunc::Parms && n->in(0)->is_Call() && n->in(0)->as_Call()->returns_pointer()" ") failed", "Unexpected node type"); ::breakpoint(); } } while (0); |
731 | add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(0), NULL__null); |
732 | break; |
733 | } |
734 | case Op_Rethrow: // Exception object escapes |
735 | case Op_Return: { |
736 | assert(n->req() > TypeFunc::Parms && _igvn->type(n->in(TypeFunc::Parms))->isa_oopptr(),do { if (!(n->req() > TypeFunc::Parms && _igvn-> type(n->in(TypeFunc::Parms))->isa_oopptr())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 737, "assert(" "n->req() > TypeFunc::Parms && _igvn->type(n->in(TypeFunc::Parms))->isa_oopptr()" ") failed", "Unexpected node type"); ::breakpoint(); } } while (0) |
737 | "Unexpected node type")do { if (!(n->req() > TypeFunc::Parms && _igvn-> type(n->in(TypeFunc::Parms))->isa_oopptr())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 737, "assert(" "n->req() > TypeFunc::Parms && _igvn->type(n->in(TypeFunc::Parms))->isa_oopptr()" ") failed", "Unexpected node type"); ::breakpoint(); } } while (0); |
738 | // Treat Return value as LocalVar with GlobalEscape escape state. |
739 | add_local_var_and_edge(n, PointsToNode::GlobalEscape, n->in(TypeFunc::Parms), NULL__null); |
740 | break; |
741 | } |
742 | case Op_CompareAndExchangeP: |
743 | case Op_CompareAndExchangeN: |
744 | case Op_GetAndSetP: |
745 | case Op_GetAndSetN:{ |
746 | assert(_igvn->type(n)->make_ptr() != NULL, "Unexpected node type")do { if (!(_igvn->type(n)->make_ptr() != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 746, "assert(" "_igvn->type(n)->make_ptr() != __null" ") failed", "Unexpected node type"); ::breakpoint(); } } while (0); |
747 | add_local_var_and_edge(n, PointsToNode::NoEscape, n->in(MemNode::Address), NULL__null); |
748 | // fall-through |
749 | } |
750 | case Op_CompareAndSwapP: |
751 | case Op_CompareAndSwapN: |
752 | case Op_WeakCompareAndSwapP: |
753 | case Op_WeakCompareAndSwapN: |
754 | case Op_StoreP: |
755 | case Op_StoreN: |
756 | case Op_StoreNKlass: |
757 | case Op_StorePConditional:{ |
758 | add_final_edges_unsafe_access(n, opcode); |
759 | break; |
760 | } |
761 | case Op_AryEq: |
762 | case Op_HasNegatives: |
763 | case Op_StrComp: |
764 | case Op_StrEquals: |
765 | case Op_StrIndexOf: |
766 | case Op_StrIndexOfChar: |
767 | case Op_StrInflatedCopy: |
768 | case Op_StrCompressedCopy: |
769 | case Op_EncodeISOArray: { |
770 | // char[]/byte[] arrays passed to string intrinsic do not escape but |
771 | // they are not scalar replaceable. Adjust escape state for them. |
772 | // Start from in(2) edge since in(1) is memory edge. |
773 | for (uint i = 2; i < n->req(); i++) { |
774 | Node* adr = n->in(i); |
775 | const Type* at = _igvn->type(adr); |
776 | if (!adr->is_top() && at->isa_ptr()) { |
777 | assert(at == Type::TOP || at == TypePtr::NULL_PTR ||do { if (!(at == Type::TOP || at == TypePtr::NULL_PTR || at-> isa_ptr() != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 778, "assert(" "at == Type::TOP || at == TypePtr::NULL_PTR || at->isa_ptr() != __null" ") failed", "expecting a pointer"); ::breakpoint(); } } while (0) |
778 | at->isa_ptr() != NULL, "expecting a pointer")do { if (!(at == Type::TOP || at == TypePtr::NULL_PTR || at-> isa_ptr() != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 778, "assert(" "at == Type::TOP || at == TypePtr::NULL_PTR || at->isa_ptr() != __null" ") failed", "expecting a pointer"); ::breakpoint(); } } while (0); |
779 | if (adr->is_AddP()) { |
780 | adr = get_addp_base(adr); |
781 | } |
782 | PointsToNode* ptn = ptnode_adr(adr->_idx); |
783 | assert(ptn != NULL, "node should be registered")do { if (!(ptn != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 783, "assert(" "ptn != __null" ") failed", "node should be registered" ); ::breakpoint(); } } while (0); |
784 | add_edge(n_ptn, ptn); |
785 | } |
786 | } |
787 | break; |
788 | } |
789 | default: { |
790 | // This method should be called only for EA specific nodes which may |
791 | // miss some edges when they were created. |
792 | #ifdef ASSERT1 |
793 | n->dump(1); |
794 | #endif |
795 | guarantee(false, "unknown node")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 795, "guarantee(" "false" ") failed", "unknown node"); ::breakpoint (); } } while (0); |
796 | } |
797 | } |
798 | return; |
799 | } |
800 | |
801 | void ConnectionGraph::add_to_congraph_unsafe_access(Node* n, uint opcode, Unique_Node_List* delayed_worklist) { |
802 | Node* adr = n->in(MemNode::Address); |
803 | const Type* adr_type = _igvn->type(adr); |
804 | adr_type = adr_type->make_ptr(); |
805 | if (adr_type == NULL__null) { |
806 | return; // skip dead nodes |
807 | } |
808 | if (adr_type->isa_oopptr() |
809 | || ((opcode == Op_StoreP || opcode == Op_StoreN || opcode == Op_StoreNKlass) |
810 | && adr_type == TypeRawPtr::NOTNULL |
811 | && is_captured_store_address(adr))) { |
812 | delayed_worklist->push(n); // Process it later. |
813 | #ifdef ASSERT1 |
814 | assert (adr->is_AddP(), "expecting an AddP")do { if (!(adr->is_AddP())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 814, "assert(" "adr->is_AddP()" ") failed", "expecting an AddP" ); ::breakpoint(); } } while (0); |
815 | if (adr_type == TypeRawPtr::NOTNULL) { |
816 | // Verify a raw address for a store captured by Initialize node. |
817 | int offs = (int) _igvn->find_intptr_t_confind_long_con(adr->in(AddPNode::Offset), Type::OffsetBot); |
818 | assert(offs != Type::OffsetBot, "offset must be a constant")do { if (!(offs != Type::OffsetBot)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 818, "assert(" "offs != Type::OffsetBot" ") failed", "offset must be a constant" ); ::breakpoint(); } } while (0); |
819 | } |
820 | #endif |
821 | } else { |
822 | // Ignore copy the displaced header to the BoxNode (OSR compilation). |
823 | if (adr->is_BoxLock()) { |
824 | return; |
825 | } |
826 | // Stored value escapes in unsafe access. |
827 | if ((opcode == Op_StoreP) && adr_type->isa_rawptr()) { |
828 | delayed_worklist->push(n); // Process unsafe access later. |
829 | return; |
830 | } |
831 | #ifdef ASSERT1 |
832 | n->dump(1); |
833 | assert(false, "not unsafe")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 833, "assert(" "false" ") failed", "not unsafe"); ::breakpoint (); } } while (0); |
834 | #endif |
835 | } |
836 | } |
837 | |
838 | bool ConnectionGraph::add_final_edges_unsafe_access(Node* n, uint opcode) { |
839 | Node* adr = n->in(MemNode::Address); |
840 | const Type *adr_type = _igvn->type(adr); |
841 | adr_type = adr_type->make_ptr(); |
842 | #ifdef ASSERT1 |
843 | if (adr_type == NULL__null) { |
844 | n->dump(1); |
845 | assert(adr_type != NULL, "dead node should not be on list")do { if (!(adr_type != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 845, "assert(" "adr_type != __null" ") failed", "dead node should not be on list" ); ::breakpoint(); } } while (0); |
846 | return true; |
847 | } |
848 | #endif |
849 | |
850 | if (adr_type->isa_oopptr() |
851 | || ((opcode == Op_StoreP || opcode == Op_StoreN || opcode == Op_StoreNKlass) |
852 | && adr_type == TypeRawPtr::NOTNULL |
853 | && is_captured_store_address(adr))) { |
854 | // Point Address to Value |
855 | PointsToNode* adr_ptn = ptnode_adr(adr->_idx); |
856 | assert(adr_ptn != NULL &&do { if (!(adr_ptn != __null && adr_ptn->as_Field( )->is_oop())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 857, "assert(" "adr_ptn != __null && adr_ptn->as_Field()->is_oop()" ") failed", "node should be registered"); ::breakpoint(); } } while (0) |
857 | adr_ptn->as_Field()->is_oop(), "node should be registered")do { if (!(adr_ptn != __null && adr_ptn->as_Field( )->is_oop())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 857, "assert(" "adr_ptn != __null && adr_ptn->as_Field()->is_oop()" ") failed", "node should be registered"); ::breakpoint(); } } while (0); |
858 | Node* val = n->in(MemNode::ValueIn); |
859 | PointsToNode* ptn = ptnode_adr(val->_idx); |
860 | assert(ptn != NULL, "node should be registered")do { if (!(ptn != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 860, "assert(" "ptn != __null" ") failed", "node should be registered" ); ::breakpoint(); } } while (0); |
861 | add_edge(adr_ptn, ptn); |
862 | return true; |
863 | } else if ((opcode == Op_StoreP) && adr_type->isa_rawptr()) { |
864 | // Stored value escapes in unsafe access. |
865 | Node* val = n->in(MemNode::ValueIn); |
866 | PointsToNode* ptn = ptnode_adr(val->_idx); |
867 | assert(ptn != NULL, "node should be registered")do { if (!(ptn != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 867, "assert(" "ptn != __null" ") failed", "node should be registered" ); ::breakpoint(); } } while (0); |
868 | set_escape_state(ptn, PointsToNode::GlobalEscape); |
869 | // Add edge to object for unsafe access with offset. |
870 | PointsToNode* adr_ptn = ptnode_adr(adr->_idx); |
871 | assert(adr_ptn != NULL, "node should be registered")do { if (!(adr_ptn != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 871, "assert(" "adr_ptn != __null" ") failed", "node should be registered" ); ::breakpoint(); } } while (0); |
872 | if (adr_ptn->is_Field()) { |
873 | assert(adr_ptn->as_Field()->is_oop(), "should be oop field")do { if (!(adr_ptn->as_Field()->is_oop())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 873, "assert(" "adr_ptn->as_Field()->is_oop()" ") failed" , "should be oop field"); ::breakpoint(); } } while (0); |
874 | add_edge(adr_ptn, ptn); |
875 | } |
876 | return true; |
877 | } |
878 | #ifdef ASSERT1 |
879 | n->dump(1); |
880 | assert(false, "not unsafe")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 880, "assert(" "false" ") failed", "not unsafe"); ::breakpoint (); } } while (0); |
881 | #endif |
882 | return false; |
883 | } |
884 | |
885 | void ConnectionGraph::add_call_node(CallNode* call) { |
886 | assert(call->returns_pointer(), "only for call which returns pointer")do { if (!(call->returns_pointer())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 886, "assert(" "call->returns_pointer()" ") failed", "only for call which returns pointer" ); ::breakpoint(); } } while (0); |
887 | uint call_idx = call->_idx; |
888 | if (call->is_Allocate()) { |
889 | Node* k = call->in(AllocateNode::KlassNode); |
890 | const TypeKlassPtr* kt = k->bottom_type()->isa_klassptr(); |
891 | assert(kt != NULL, "TypeKlassPtr required.")do { if (!(kt != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 891, "assert(" "kt != __null" ") failed", "TypeKlassPtr required." ); ::breakpoint(); } } while (0); |
892 | ciKlass* cik = kt->klass(); |
893 | PointsToNode::EscapeState es = PointsToNode::NoEscape; |
894 | bool scalar_replaceable = true; |
895 | if (call->is_AllocateArray()) { |
896 | if (!cik->is_array_klass()) { // StressReflectiveCode |
897 | es = PointsToNode::GlobalEscape; |
898 | } else { |
899 | int length = call->in(AllocateNode::ALength)->find_int_con(-1); |
900 | if (length < 0 || length > EliminateAllocationArraySizeLimit) { |
901 | // Not scalar replaceable if the length is not constant or too big. |
902 | scalar_replaceable = false; |
903 | } |
904 | } |
905 | } else { // Allocate instance |
906 | if (cik->is_subclass_of(_compile->env()->Thread_klass()) || |
907 | cik->is_subclass_of(_compile->env()->Reference_klass()) || |
908 | !cik->is_instance_klass() || // StressReflectiveCode |
909 | !cik->as_instance_klass()->can_be_instantiated() || |
910 | cik->as_instance_klass()->has_finalizer()) { |
911 | es = PointsToNode::GlobalEscape; |
912 | } else { |
913 | int nfields = cik->as_instance_klass()->nof_nonstatic_fields(); |
914 | if (nfields > EliminateAllocationFieldsLimit) { |
915 | // Not scalar replaceable if there are too many fields. |
916 | scalar_replaceable = false; |
917 | } |
918 | } |
919 | } |
920 | add_java_object(call, es); |
921 | PointsToNode* ptn = ptnode_adr(call_idx); |
922 | if (!scalar_replaceable && ptn->scalar_replaceable()) { |
923 | ptn->set_scalar_replaceable(false); |
924 | } |
925 | } else if (call->is_CallStaticJava()) { |
926 | // Call nodes could be different types: |
927 | // |
928 | // 1. CallDynamicJavaNode (what happened during call is unknown): |
929 | // |
930 | // - mapped to GlobalEscape JavaObject node if oop is returned; |
931 | // |
932 | // - all oop arguments are escaping globally; |
933 | // |
934 | // 2. CallStaticJavaNode (execute bytecode analysis if possible): |
935 | // |
936 | // - the same as CallDynamicJavaNode if can't do bytecode analysis; |
937 | // |
938 | // - mapped to GlobalEscape JavaObject node if unknown oop is returned; |
939 | // - mapped to NoEscape JavaObject node if non-escaping object allocated |
940 | // during call is returned; |
941 | // - mapped to ArgEscape LocalVar node pointed to object arguments |
942 | // which are returned and does not escape during call; |
943 | // |
944 | // - oop arguments escaping status is defined by bytecode analysis; |
945 | // |
946 | // For a static call, we know exactly what method is being called. |
947 | // Use bytecode estimator to record whether the call's return value escapes. |
948 | ciMethod* meth = call->as_CallJava()->method(); |
949 | if (meth == NULL__null) { |
950 | const char* name = call->as_CallStaticJava()->_name; |
951 | assert(strncmp(name, "_multianewarray", 15) == 0, "TODO: add failed case check")do { if (!(strncmp(name, "_multianewarray", 15) == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 951, "assert(" "strncmp(name, \"_multianewarray\", 15) == 0" ") failed", "TODO: add failed case check"); ::breakpoint(); } } while (0); |
952 | // Returns a newly allocated non-escaped object. |
953 | add_java_object(call, PointsToNode::NoEscape); |
954 | ptnode_adr(call_idx)->set_scalar_replaceable(false); |
955 | } else if (meth->is_boxing_method()) { |
956 | // Returns boxing object |
957 | PointsToNode::EscapeState es; |
958 | vmIntrinsics::ID intr = meth->intrinsic_id(); |
959 | if (intr == vmIntrinsics::_floatValue || intr == vmIntrinsics::_doubleValue) { |
960 | // It does not escape if object is always allocated. |
961 | es = PointsToNode::NoEscape; |
962 | } else { |
963 | // It escapes globally if object could be loaded from cache. |
964 | es = PointsToNode::GlobalEscape; |
965 | } |
966 | add_java_object(call, es); |
967 | } else { |
968 | BCEscapeAnalyzer* call_analyzer = meth->get_bcea(); |
969 | call_analyzer->copy_dependencies(_compile->dependencies()); |
970 | if (call_analyzer->is_return_allocated()) { |
971 | // Returns a newly allocated non-escaped object, simply |
972 | // update dependency information. |
973 | // Mark it as NoEscape so that objects referenced by |
974 | // it's fields will be marked as NoEscape at least. |
975 | add_java_object(call, PointsToNode::NoEscape); |
976 | ptnode_adr(call_idx)->set_scalar_replaceable(false); |
977 | } else { |
978 | // Determine whether any arguments are returned. |
979 | const TypeTuple* d = call->tf()->domain(); |
980 | bool ret_arg = false; |
981 | for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { |
982 | if (d->field_at(i)->isa_ptr() != NULL__null && |
983 | call_analyzer->is_arg_returned(i - TypeFunc::Parms)) { |
984 | ret_arg = true; |
985 | break; |
986 | } |
987 | } |
988 | if (ret_arg) { |
989 | add_local_var(call, PointsToNode::ArgEscape); |
990 | } else { |
991 | // Returns unknown object. |
992 | map_ideal_node(call, phantom_obj); |
993 | } |
994 | } |
995 | } |
996 | } else { |
997 | // An other type of call, assume the worst case: |
998 | // returned value is unknown and globally escapes. |
999 | assert(call->Opcode() == Op_CallDynamicJava, "add failed case check")do { if (!(call->Opcode() == Op_CallDynamicJava)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 999, "assert(" "call->Opcode() == Op_CallDynamicJava" ") failed" , "add failed case check"); ::breakpoint(); } } while (0); |
1000 | map_ideal_node(call, phantom_obj); |
1001 | } |
1002 | } |
1003 | |
1004 | void ConnectionGraph::process_call_arguments(CallNode *call) { |
1005 | bool is_arraycopy = false; |
1006 | switch (call->Opcode()) { |
1007 | #ifdef ASSERT1 |
1008 | case Op_Allocate: |
1009 | case Op_AllocateArray: |
1010 | case Op_Lock: |
1011 | case Op_Unlock: |
1012 | assert(false, "should be done already")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1012, "assert(" "false" ") failed", "should be done already" ); ::breakpoint(); } } while (0); |
1013 | break; |
1014 | #endif |
1015 | case Op_ArrayCopy: |
1016 | case Op_CallLeafNoFP: |
1017 | // Most array copies are ArrayCopy nodes at this point but there |
1018 | // are still a few direct calls to the copy subroutines (See |
1019 | // PhaseStringOpts::copy_string()) |
1020 | is_arraycopy = (call->Opcode() == Op_ArrayCopy) || |
1021 | call->as_CallLeaf()->is_call_to_arraycopystub(); |
1022 | // fall through |
1023 | case Op_CallLeafVector: |
1024 | case Op_CallLeaf: { |
1025 | // Stub calls, objects do not escape but they are not scale replaceable. |
1026 | // Adjust escape state for outgoing arguments. |
1027 | const TypeTuple * d = call->tf()->domain(); |
1028 | bool src_has_oops = false; |
1029 | for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { |
1030 | const Type* at = d->field_at(i); |
1031 | Node *arg = call->in(i); |
1032 | if (arg == NULL__null) { |
1033 | continue; |
1034 | } |
1035 | const Type *aat = _igvn->type(arg); |
1036 | if (arg->is_top() || !at->isa_ptr() || !aat->isa_ptr()) { |
1037 | continue; |
1038 | } |
1039 | if (arg->is_AddP()) { |
1040 | // |
1041 | // The inline_native_clone() case when the arraycopy stub is called |
1042 | // after the allocation before Initialize and CheckCastPP nodes. |
1043 | // Or normal arraycopy for object arrays case. |
1044 | // |
1045 | // Set AddP's base (Allocate) as not scalar replaceable since |
1046 | // pointer to the base (with offset) is passed as argument. |
1047 | // |
1048 | arg = get_addp_base(arg); |
1049 | } |
1050 | PointsToNode* arg_ptn = ptnode_adr(arg->_idx); |
1051 | assert(arg_ptn != NULL, "should be registered")do { if (!(arg_ptn != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1051, "assert(" "arg_ptn != __null" ") failed", "should be registered" ); ::breakpoint(); } } while (0); |
1052 | PointsToNode::EscapeState arg_esc = arg_ptn->escape_state(); |
1053 | if (is_arraycopy || arg_esc < PointsToNode::ArgEscape) { |
1054 | assert(aat == Type::TOP || aat == TypePtr::NULL_PTR ||do { if (!(aat == Type::TOP || aat == TypePtr::NULL_PTR || aat ->isa_ptr() != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1055, "assert(" "aat == Type::TOP || aat == TypePtr::NULL_PTR || aat->isa_ptr() != __null" ") failed", "expecting an Ptr"); ::breakpoint(); } } while ( 0) |
1055 | aat->isa_ptr() != NULL, "expecting an Ptr")do { if (!(aat == Type::TOP || aat == TypePtr::NULL_PTR || aat ->isa_ptr() != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1055, "assert(" "aat == Type::TOP || aat == TypePtr::NULL_PTR || aat->isa_ptr() != __null" ") failed", "expecting an Ptr"); ::breakpoint(); } } while ( 0); |
1056 | bool arg_has_oops = aat->isa_oopptr() && |
1057 | (aat->isa_oopptr()->klass() == NULL__null || aat->isa_instptr() || |
1058 | (aat->isa_aryptr() && aat->isa_aryptr()->klass()->is_obj_array_klass())); |
1059 | if (i == TypeFunc::Parms) { |
1060 | src_has_oops = arg_has_oops; |
1061 | } |
1062 | // |
1063 | // src or dst could be j.l.Object when other is basic type array: |
1064 | // |
1065 | // arraycopy(char[],0,Object*,0,size); |
1066 | // arraycopy(Object*,0,char[],0,size); |
1067 | // |
1068 | // Don't add edges in such cases. |
1069 | // |
1070 | bool arg_is_arraycopy_dest = src_has_oops && is_arraycopy && |
1071 | arg_has_oops && (i > TypeFunc::Parms); |
1072 | #ifdef ASSERT1 |
1073 | if (!(is_arraycopy || |
1074 | BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(call) || |
1075 | (call->as_CallLeaf()->_name != NULL__null && |
1076 | (strcmp(call->as_CallLeaf()->_name, "updateBytesCRC32") == 0 || |
1077 | strcmp(call->as_CallLeaf()->_name, "updateBytesCRC32C") == 0 || |
1078 | strcmp(call->as_CallLeaf()->_name, "updateBytesAdler32") == 0 || |
1079 | strcmp(call->as_CallLeaf()->_name, "aescrypt_encryptBlock") == 0 || |
1080 | strcmp(call->as_CallLeaf()->_name, "aescrypt_decryptBlock") == 0 || |
1081 | strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_encryptAESCrypt") == 0 || |
1082 | strcmp(call->as_CallLeaf()->_name, "cipherBlockChaining_decryptAESCrypt") == 0 || |
1083 | strcmp(call->as_CallLeaf()->_name, "electronicCodeBook_encryptAESCrypt") == 0 || |
1084 | strcmp(call->as_CallLeaf()->_name, "electronicCodeBook_decryptAESCrypt") == 0 || |
1085 | strcmp(call->as_CallLeaf()->_name, "counterMode_AESCrypt") == 0 || |
1086 | strcmp(call->as_CallLeaf()->_name, "galoisCounterMode_AESCrypt") == 0 || |
1087 | strcmp(call->as_CallLeaf()->_name, "ghash_processBlocks") == 0 || |
1088 | strcmp(call->as_CallLeaf()->_name, "encodeBlock") == 0 || |
1089 | strcmp(call->as_CallLeaf()->_name, "decodeBlock") == 0 || |
1090 | strcmp(call->as_CallLeaf()->_name, "md5_implCompress") == 0 || |
1091 | strcmp(call->as_CallLeaf()->_name, "md5_implCompressMB") == 0 || |
1092 | strcmp(call->as_CallLeaf()->_name, "sha1_implCompress") == 0 || |
1093 | strcmp(call->as_CallLeaf()->_name, "sha1_implCompressMB") == 0 || |
1094 | strcmp(call->as_CallLeaf()->_name, "sha256_implCompress") == 0 || |
1095 | strcmp(call->as_CallLeaf()->_name, "sha256_implCompressMB") == 0 || |
1096 | strcmp(call->as_CallLeaf()->_name, "sha512_implCompress") == 0 || |
1097 | strcmp(call->as_CallLeaf()->_name, "sha512_implCompressMB") == 0 || |
1098 | strcmp(call->as_CallLeaf()->_name, "sha3_implCompress") == 0 || |
1099 | strcmp(call->as_CallLeaf()->_name, "sha3_implCompressMB") == 0 || |
1100 | strcmp(call->as_CallLeaf()->_name, "multiplyToLen") == 0 || |
1101 | strcmp(call->as_CallLeaf()->_name, "squareToLen") == 0 || |
1102 | strcmp(call->as_CallLeaf()->_name, "mulAdd") == 0 || |
1103 | strcmp(call->as_CallLeaf()->_name, "montgomery_multiply") == 0 || |
1104 | strcmp(call->as_CallLeaf()->_name, "montgomery_square") == 0 || |
1105 | strcmp(call->as_CallLeaf()->_name, "bigIntegerRightShiftWorker") == 0 || |
1106 | strcmp(call->as_CallLeaf()->_name, "bigIntegerLeftShiftWorker") == 0 || |
1107 | strcmp(call->as_CallLeaf()->_name, "vectorizedMismatch") == 0 || |
1108 | strcmp(call->as_CallLeaf()->_name, "get_class_id_intrinsic") == 0) |
1109 | ))) { |
1110 | call->dump(); |
1111 | fatal("EA unexpected CallLeaf %s", call->as_CallLeaf()->_name)do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1111, "EA unexpected CallLeaf %s", call->as_CallLeaf()-> _name); ::breakpoint(); } while (0); |
1112 | } |
1113 | #endif |
1114 | // Always process arraycopy's destination object since |
1115 | // we need to add all possible edges to references in |
1116 | // source object. |
1117 | if (arg_esc >= PointsToNode::ArgEscape && |
1118 | !arg_is_arraycopy_dest) { |
1119 | continue; |
1120 | } |
1121 | PointsToNode::EscapeState es = PointsToNode::ArgEscape; |
1122 | if (call->is_ArrayCopy()) { |
1123 | ArrayCopyNode* ac = call->as_ArrayCopy(); |
1124 | if (ac->is_clonebasic() || |
1125 | ac->is_arraycopy_validated() || |
1126 | ac->is_copyof_validated() || |
1127 | ac->is_copyofrange_validated()) { |
1128 | es = PointsToNode::NoEscape; |
1129 | } |
1130 | } |
1131 | set_escape_state(arg_ptn, es); |
1132 | if (arg_is_arraycopy_dest) { |
1133 | Node* src = call->in(TypeFunc::Parms); |
1134 | if (src->is_AddP()) { |
1135 | src = get_addp_base(src); |
1136 | } |
1137 | PointsToNode* src_ptn = ptnode_adr(src->_idx); |
1138 | assert(src_ptn != NULL, "should be registered")do { if (!(src_ptn != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1138, "assert(" "src_ptn != __null" ") failed", "should be registered" ); ::breakpoint(); } } while (0); |
1139 | if (arg_ptn != src_ptn) { |
1140 | // Special arraycopy edge: |
1141 | // A destination object's field can't have the source object |
1142 | // as base since objects escape states are not related. |
1143 | // Only escape state of destination object's fields affects |
1144 | // escape state of fields in source object. |
1145 | add_arraycopy(call, es, src_ptn, arg_ptn); |
1146 | } |
1147 | } |
1148 | } |
1149 | } |
1150 | break; |
1151 | } |
1152 | case Op_CallStaticJava: { |
1153 | // For a static call, we know exactly what method is being called. |
1154 | // Use bytecode estimator to record the call's escape affects |
1155 | #ifdef ASSERT1 |
1156 | const char* name = call->as_CallStaticJava()->_name; |
1157 | assert((name == NULL || strcmp(name, "uncommon_trap") != 0), "normal calls only")do { if (!((name == __null || strcmp(name, "uncommon_trap") != 0))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1157, "assert(" "(name == __null || strcmp(name, \"uncommon_trap\") != 0)" ") failed", "normal calls only"); ::breakpoint(); } } while ( 0); |
1158 | #endif |
1159 | ciMethod* meth = call->as_CallJava()->method(); |
1160 | if ((meth != NULL__null) && meth->is_boxing_method()) { |
1161 | break; // Boxing methods do not modify any oops. |
1162 | } |
1163 | BCEscapeAnalyzer* call_analyzer = (meth !=NULL__null) ? meth->get_bcea() : NULL__null; |
1164 | // fall-through if not a Java method or no analyzer information |
1165 | if (call_analyzer != NULL__null) { |
1166 | PointsToNode* call_ptn = ptnode_adr(call->_idx); |
1167 | const TypeTuple* d = call->tf()->domain(); |
1168 | for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { |
1169 | const Type* at = d->field_at(i); |
1170 | int k = i - TypeFunc::Parms; |
1171 | Node* arg = call->in(i); |
1172 | PointsToNode* arg_ptn = ptnode_adr(arg->_idx); |
1173 | if (at->isa_ptr() != NULL__null && |
1174 | call_analyzer->is_arg_returned(k)) { |
1175 | // The call returns arguments. |
1176 | if (call_ptn != NULL__null) { // Is call's result used? |
1177 | assert(call_ptn->is_LocalVar(), "node should be registered")do { if (!(call_ptn->is_LocalVar())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1177, "assert(" "call_ptn->is_LocalVar()" ") failed", "node should be registered" ); ::breakpoint(); } } while (0); |
1178 | assert(arg_ptn != NULL, "node should be registered")do { if (!(arg_ptn != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1178, "assert(" "arg_ptn != __null" ") failed", "node should be registered" ); ::breakpoint(); } } while (0); |
1179 | add_edge(call_ptn, arg_ptn); |
1180 | } |
1181 | } |
1182 | if (at->isa_oopptr() != NULL__null && |
1183 | arg_ptn->escape_state() < PointsToNode::GlobalEscape) { |
1184 | if (!call_analyzer->is_arg_stack(k)) { |
1185 | // The argument global escapes |
1186 | set_escape_state(arg_ptn, PointsToNode::GlobalEscape); |
1187 | } else { |
1188 | set_escape_state(arg_ptn, PointsToNode::ArgEscape); |
1189 | if (!call_analyzer->is_arg_local(k)) { |
1190 | // The argument itself doesn't escape, but any fields might |
1191 | set_fields_escape_state(arg_ptn, PointsToNode::GlobalEscape); |
1192 | } |
1193 | } |
1194 | } |
1195 | } |
1196 | if (call_ptn != NULL__null && call_ptn->is_LocalVar()) { |
1197 | // The call returns arguments. |
1198 | assert(call_ptn->edge_count() > 0, "sanity")do { if (!(call_ptn->edge_count() > 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1198, "assert(" "call_ptn->edge_count() > 0" ") failed" , "sanity"); ::breakpoint(); } } while (0); |
1199 | if (!call_analyzer->is_return_local()) { |
1200 | // Returns also unknown object. |
1201 | add_edge(call_ptn, phantom_obj); |
1202 | } |
1203 | } |
1204 | break; |
1205 | } |
1206 | } |
1207 | default: { |
1208 | // Fall-through here if not a Java method or no analyzer information |
1209 | // or some other type of call, assume the worst case: all arguments |
1210 | // globally escape. |
1211 | const TypeTuple* d = call->tf()->domain(); |
1212 | for (uint i = TypeFunc::Parms; i < d->cnt(); i++) { |
1213 | const Type* at = d->field_at(i); |
1214 | if (at->isa_oopptr() != NULL__null) { |
1215 | Node* arg = call->in(i); |
1216 | if (arg->is_AddP()) { |
1217 | arg = get_addp_base(arg); |
1218 | } |
1219 | assert(ptnode_adr(arg->_idx) != NULL, "should be defined already")do { if (!(ptnode_adr(arg->_idx) != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1219, "assert(" "ptnode_adr(arg->_idx) != __null" ") failed" , "should be defined already"); ::breakpoint(); } } while (0); |
1220 | set_escape_state(ptnode_adr(arg->_idx), PointsToNode::GlobalEscape); |
1221 | } |
1222 | } |
1223 | } |
1224 | } |
1225 | } |
1226 | |
1227 | |
1228 | // Finish Graph construction. |
1229 | bool ConnectionGraph::complete_connection_graph( |
1230 | GrowableArray<PointsToNode*>& ptnodes_worklist, |
1231 | GrowableArray<JavaObjectNode*>& non_escaped_allocs_worklist, |
1232 | GrowableArray<JavaObjectNode*>& java_objects_worklist, |
1233 | GrowableArray<FieldNode*>& oop_fields_worklist) { |
1234 | // Normally only 1-3 passes needed to build Connection Graph depending |
1235 | // on graph complexity. Observed 8 passes in jvm2008 compiler.compiler. |
1236 | // Set limit to 20 to catch situation when something did go wrong and |
1237 | // bailout Escape Analysis. |
1238 | // Also limit build time to 20 sec (60 in debug VM), EscapeAnalysisTimeout flag. |
1239 | #define GRAPH_BUILD_ITER_LIMIT 20 |
1240 | |
1241 | // Propagate GlobalEscape and ArgEscape escape states and check that |
1242 | // we still have non-escaping objects. The method pushs on _worklist |
1243 | // Field nodes which reference phantom_object. |
1244 | if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_allocs_worklist)) { |
1245 | return false; // Nothing to do. |
1246 | } |
1247 | // Now propagate references to all JavaObject nodes. |
1248 | int java_objects_length = java_objects_worklist.length(); |
1249 | elapsedTimer build_time; |
1250 | build_time.start(); |
1251 | elapsedTimer time; |
1252 | bool timeout = false; |
1253 | int new_edges = 1; |
1254 | int iterations = 0; |
1255 | do { |
1256 | while ((new_edges > 0) && |
1257 | (iterations++ < GRAPH_BUILD_ITER_LIMIT)) { |
1258 | double start_time = time.seconds(); |
1259 | time.start(); |
1260 | new_edges = 0; |
1261 | // Propagate references to phantom_object for nodes pushed on _worklist |
1262 | // by find_non_escaped_objects() and find_field_value(). |
1263 | new_edges += add_java_object_edges(phantom_obj, false); |
1264 | for (int next = 0; next < java_objects_length; ++next) { |
1265 | JavaObjectNode* ptn = java_objects_worklist.at(next); |
1266 | new_edges += add_java_object_edges(ptn, true); |
1267 | |
1268 | #define SAMPLE_SIZE 4 |
1269 | if ((next % SAMPLE_SIZE) == 0) { |
1270 | // Each 4 iterations calculate how much time it will take |
1271 | // to complete graph construction. |
1272 | time.stop(); |
1273 | // Poll for requests from shutdown mechanism to quiesce compiler |
1274 | // because Connection graph construction may take long time. |
1275 | CompileBroker::maybe_block(); |
1276 | double stop_time = time.seconds(); |
1277 | double time_per_iter = (stop_time - start_time) / (double)SAMPLE_SIZE; |
1278 | double time_until_end = time_per_iter * (double)(java_objects_length - next); |
1279 | if ((start_time + time_until_end) >= EscapeAnalysisTimeout) { |
1280 | timeout = true; |
1281 | break; // Timeout |
1282 | } |
1283 | start_time = stop_time; |
1284 | time.start(); |
1285 | } |
1286 | #undef SAMPLE_SIZE |
1287 | |
1288 | } |
1289 | if (timeout) break; |
1290 | if (new_edges > 0) { |
1291 | // Update escape states on each iteration if graph was updated. |
1292 | if (!find_non_escaped_objects(ptnodes_worklist, non_escaped_allocs_worklist)) { |
1293 | return false; // Nothing to do. |
1294 | } |
1295 | } |
1296 | time.stop(); |
1297 | if (time.seconds() >= EscapeAnalysisTimeout) { |
1298 | timeout = true; |
1299 | break; |
1300 | } |
1301 | } |
1302 | if ((iterations < GRAPH_BUILD_ITER_LIMIT) && !timeout) { |
1303 | time.start(); |
1304 | // Find fields which have unknown value. |
1305 | int fields_length = oop_fields_worklist.length(); |
1306 | for (int next = 0; next < fields_length; next++) { |
1307 | FieldNode* field = oop_fields_worklist.at(next); |
1308 | if (field->edge_count() == 0) { |
1309 | new_edges += find_field_value(field); |
1310 | // This code may added new edges to phantom_object. |
1311 | // Need an other cycle to propagate references to phantom_object. |
1312 | } |
1313 | } |
1314 | time.stop(); |
1315 | if (time.seconds() >= EscapeAnalysisTimeout) { |
1316 | timeout = true; |
1317 | break; |
1318 | } |
1319 | } else { |
1320 | new_edges = 0; // Bailout |
1321 | } |
1322 | } while (new_edges > 0); |
1323 | |
1324 | build_time.stop(); |
1325 | _build_time = build_time.seconds(); |
1326 | _build_iterations = iterations; |
1327 | |
1328 | // Bailout if passed limits. |
1329 | if ((iterations >= GRAPH_BUILD_ITER_LIMIT) || timeout) { |
1330 | Compile* C = _compile; |
1331 | if (C->log() != NULL__null) { |
1332 | C->log()->begin_elem("connectionGraph_bailout reason='reached "); |
1333 | C->log()->text("%s", timeout ? "time" : "iterations"); |
1334 | C->log()->end_elem(" limit'"); |
1335 | } |
1336 | assert(ExitEscapeAnalysisOnTimeout, "infinite EA connection graph build during invocation %d (%f sec, %d iterations) with %d nodes and worklist size %d",do { if (!(ExitEscapeAnalysisOnTimeout)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1337, "assert(" "ExitEscapeAnalysisOnTimeout" ") failed", "infinite EA connection graph build during invocation %d (%f sec, %d iterations) with %d nodes and worklist size %d" , _invocation, _build_time, _build_iterations, nodes_size(), ptnodes_worklist .length()); ::breakpoint(); } } while (0) |
1337 | _invocation, _build_time, _build_iterations, nodes_size(), ptnodes_worklist.length())do { if (!(ExitEscapeAnalysisOnTimeout)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1337, "assert(" "ExitEscapeAnalysisOnTimeout" ") failed", "infinite EA connection graph build during invocation %d (%f sec, %d iterations) with %d nodes and worklist size %d" , _invocation, _build_time, _build_iterations, nodes_size(), ptnodes_worklist .length()); ::breakpoint(); } } while (0); |
1338 | // Possible infinite build_connection_graph loop, |
1339 | // bailout (no changes to ideal graph were made). |
1340 | return false; |
1341 | } |
1342 | |
1343 | #undef GRAPH_BUILD_ITER_LIMIT |
1344 | |
1345 | // Find fields initialized by NULL for non-escaping Allocations. |
1346 | int non_escaped_length = non_escaped_allocs_worklist.length(); |
1347 | for (int next = 0; next < non_escaped_length; next++) { |
1348 | JavaObjectNode* ptn = non_escaped_allocs_worklist.at(next); |
1349 | PointsToNode::EscapeState es = ptn->escape_state(); |
1350 | assert(es <= PointsToNode::ArgEscape, "sanity")do { if (!(es <= PointsToNode::ArgEscape)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1350, "assert(" "es <= PointsToNode::ArgEscape" ") failed" , "sanity"); ::breakpoint(); } } while (0); |
1351 | if (es == PointsToNode::NoEscape) { |
1352 | if (find_init_values_null(ptn, _igvn) > 0) { |
1353 | // Adding references to NULL object does not change escape states |
1354 | // since it does not escape. Also no fields are added to NULL object. |
1355 | add_java_object_edges(null_obj, false); |
1356 | } |
1357 | } |
1358 | Node* n = ptn->ideal_node(); |
1359 | if (n->is_Allocate()) { |
1360 | // The object allocated by this Allocate node will never be |
1361 | // seen by an other thread. Mark it so that when it is |
1362 | // expanded no MemBarStoreStore is added. |
1363 | InitializeNode* ini = n->as_Allocate()->initialization(); |
1364 | if (ini != NULL__null) |
1365 | ini->set_does_not_escape(); |
1366 | } |
1367 | } |
1368 | return true; // Finished graph construction. |
1369 | } |
1370 | |
1371 | // Propagate GlobalEscape and ArgEscape escape states to all nodes |
1372 | // and check that we still have non-escaping java objects. |
1373 | bool ConnectionGraph::find_non_escaped_objects(GrowableArray<PointsToNode*>& ptnodes_worklist, |
1374 | GrowableArray<JavaObjectNode*>& non_escaped_allocs_worklist) { |
1375 | GrowableArray<PointsToNode*> escape_worklist; |
1376 | // First, put all nodes with GlobalEscape and ArgEscape states on worklist. |
1377 | int ptnodes_length = ptnodes_worklist.length(); |
1378 | for (int next = 0; next < ptnodes_length; ++next) { |
1379 | PointsToNode* ptn = ptnodes_worklist.at(next); |
1380 | if (ptn->escape_state() >= PointsToNode::ArgEscape || |
1381 | ptn->fields_escape_state() >= PointsToNode::ArgEscape) { |
1382 | escape_worklist.push(ptn); |
1383 | } |
1384 | } |
1385 | // Set escape states to referenced nodes (edges list). |
1386 | while (escape_worklist.length() > 0) { |
1387 | PointsToNode* ptn = escape_worklist.pop(); |
1388 | PointsToNode::EscapeState es = ptn->escape_state(); |
1389 | PointsToNode::EscapeState field_es = ptn->fields_escape_state(); |
1390 | if (ptn->is_Field() && ptn->as_Field()->is_oop() && |
1391 | es >= PointsToNode::ArgEscape) { |
1392 | // GlobalEscape or ArgEscape state of field means it has unknown value. |
1393 | if (add_edge(ptn, phantom_obj)) { |
1394 | // New edge was added |
1395 | add_field_uses_to_worklist(ptn->as_Field()); |
1396 | } |
1397 | } |
1398 | for (EdgeIterator i(ptn); i.has_next(); i.next()) { |
1399 | PointsToNode* e = i.get(); |
1400 | if (e->is_Arraycopy()) { |
1401 | assert(ptn->arraycopy_dst(), "sanity")do { if (!(ptn->arraycopy_dst())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1401, "assert(" "ptn->arraycopy_dst()" ") failed", "sanity" ); ::breakpoint(); } } while (0); |
1402 | // Propagate only fields escape state through arraycopy edge. |
1403 | if (e->fields_escape_state() < field_es) { |
1404 | set_fields_escape_state(e, field_es); |
1405 | escape_worklist.push(e); |
1406 | } |
1407 | } else if (es >= field_es) { |
1408 | // fields_escape_state is also set to 'es' if it is less than 'es'. |
1409 | if (e->escape_state() < es) { |
1410 | set_escape_state(e, es); |
1411 | escape_worklist.push(e); |
1412 | } |
1413 | } else { |
1414 | // Propagate field escape state. |
1415 | bool es_changed = false; |
1416 | if (e->fields_escape_state() < field_es) { |
1417 | set_fields_escape_state(e, field_es); |
1418 | es_changed = true; |
1419 | } |
1420 | if ((e->escape_state() < field_es) && |
1421 | e->is_Field() && ptn->is_JavaObject() && |
1422 | e->as_Field()->is_oop()) { |
1423 | // Change escape state of referenced fields. |
1424 | set_escape_state(e, field_es); |
1425 | es_changed = true; |
1426 | } else if (e->escape_state() < es) { |
1427 | set_escape_state(e, es); |
1428 | es_changed = true; |
1429 | } |
1430 | if (es_changed) { |
1431 | escape_worklist.push(e); |
1432 | } |
1433 | } |
1434 | } |
1435 | } |
1436 | // Remove escaped objects from non_escaped list. |
1437 | for (int next = non_escaped_allocs_worklist.length()-1; next >= 0 ; --next) { |
1438 | JavaObjectNode* ptn = non_escaped_allocs_worklist.at(next); |
1439 | if (ptn->escape_state() >= PointsToNode::GlobalEscape) { |
1440 | non_escaped_allocs_worklist.delete_at(next); |
1441 | } |
1442 | if (ptn->escape_state() == PointsToNode::NoEscape) { |
1443 | // Find fields in non-escaped allocations which have unknown value. |
1444 | find_init_values_phantom(ptn); |
1445 | } |
1446 | } |
1447 | return (non_escaped_allocs_worklist.length() > 0); |
1448 | } |
1449 | |
1450 | // Add all references to JavaObject node by walking over all uses. |
1451 | int ConnectionGraph::add_java_object_edges(JavaObjectNode* jobj, bool populate_worklist) { |
1452 | int new_edges = 0; |
1453 | if (populate_worklist) { |
1454 | // Populate _worklist by uses of jobj's uses. |
1455 | for (UseIterator i(jobj); i.has_next(); i.next()) { |
1456 | PointsToNode* use = i.get(); |
1457 | if (use->is_Arraycopy()) { |
1458 | continue; |
1459 | } |
1460 | add_uses_to_worklist(use); |
1461 | if (use->is_Field() && use->as_Field()->is_oop()) { |
1462 | // Put on worklist all field's uses (loads) and |
1463 | // related field nodes (same base and offset). |
1464 | add_field_uses_to_worklist(use->as_Field()); |
1465 | } |
1466 | } |
1467 | } |
1468 | for (int l = 0; l < _worklist.length(); l++) { |
1469 | PointsToNode* use = _worklist.at(l); |
1470 | if (PointsToNode::is_base_use(use)) { |
1471 | // Add reference from jobj to field and from field to jobj (field's base). |
1472 | use = PointsToNode::get_use_node(use)->as_Field(); |
1473 | if (add_base(use->as_Field(), jobj)) { |
1474 | new_edges++; |
1475 | } |
1476 | continue; |
1477 | } |
1478 | assert(!use->is_JavaObject(), "sanity")do { if (!(!use->is_JavaObject())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1478, "assert(" "!use->is_JavaObject()" ") failed", "sanity" ); ::breakpoint(); } } while (0); |
1479 | if (use->is_Arraycopy()) { |
1480 | if (jobj == null_obj) { // NULL object does not have field edges |
1481 | continue; |
1482 | } |
1483 | // Added edge from Arraycopy node to arraycopy's source java object |
1484 | if (add_edge(use, jobj)) { |
1485 | jobj->set_arraycopy_src(); |
1486 | new_edges++; |
1487 | } |
1488 | // and stop here. |
1489 | continue; |
1490 | } |
1491 | if (!add_edge(use, jobj)) { |
1492 | continue; // No new edge added, there was such edge already. |
1493 | } |
1494 | new_edges++; |
1495 | if (use->is_LocalVar()) { |
1496 | add_uses_to_worklist(use); |
1497 | if (use->arraycopy_dst()) { |
1498 | for (EdgeIterator i(use); i.has_next(); i.next()) { |
1499 | PointsToNode* e = i.get(); |
1500 | if (e->is_Arraycopy()) { |
1501 | if (jobj == null_obj) { // NULL object does not have field edges |
1502 | continue; |
1503 | } |
1504 | // Add edge from arraycopy's destination java object to Arraycopy node. |
1505 | if (add_edge(jobj, e)) { |
1506 | new_edges++; |
1507 | jobj->set_arraycopy_dst(); |
1508 | } |
1509 | } |
1510 | } |
1511 | } |
1512 | } else { |
1513 | // Added new edge to stored in field values. |
1514 | // Put on worklist all field's uses (loads) and |
1515 | // related field nodes (same base and offset). |
1516 | add_field_uses_to_worklist(use->as_Field()); |
1517 | } |
1518 | } |
1519 | _worklist.clear(); |
1520 | _in_worklist.reset(); |
1521 | return new_edges; |
1522 | } |
1523 | |
1524 | // Put on worklist all related field nodes. |
1525 | void ConnectionGraph::add_field_uses_to_worklist(FieldNode* field) { |
1526 | assert(field->is_oop(), "sanity")do { if (!(field->is_oop())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1526, "assert(" "field->is_oop()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1527 | int offset = field->offset(); |
1528 | add_uses_to_worklist(field); |
1529 | // Loop over all bases of this field and push on worklist Field nodes |
1530 | // with the same offset and base (since they may reference the same field). |
1531 | for (BaseIterator i(field); i.has_next(); i.next()) { |
1532 | PointsToNode* base = i.get(); |
1533 | add_fields_to_worklist(field, base); |
1534 | // Check if the base was source object of arraycopy and go over arraycopy's |
1535 | // destination objects since values stored to a field of source object are |
1536 | // accessable by uses (loads) of fields of destination objects. |
1537 | if (base->arraycopy_src()) { |
1538 | for (UseIterator j(base); j.has_next(); j.next()) { |
1539 | PointsToNode* arycp = j.get(); |
1540 | if (arycp->is_Arraycopy()) { |
1541 | for (UseIterator k(arycp); k.has_next(); k.next()) { |
1542 | PointsToNode* abase = k.get(); |
1543 | if (abase->arraycopy_dst() && abase != base) { |
1544 | // Look for the same arraycopy reference. |
1545 | add_fields_to_worklist(field, abase); |
1546 | } |
1547 | } |
1548 | } |
1549 | } |
1550 | } |
1551 | } |
1552 | } |
1553 | |
1554 | // Put on worklist all related field nodes. |
1555 | void ConnectionGraph::add_fields_to_worklist(FieldNode* field, PointsToNode* base) { |
1556 | int offset = field->offset(); |
1557 | if (base->is_LocalVar()) { |
1558 | for (UseIterator j(base); j.has_next(); j.next()) { |
1559 | PointsToNode* f = j.get(); |
1560 | if (PointsToNode::is_base_use(f)) { // Field |
1561 | f = PointsToNode::get_use_node(f); |
1562 | if (f == field || !f->as_Field()->is_oop()) { |
1563 | continue; |
1564 | } |
1565 | int offs = f->as_Field()->offset(); |
1566 | if (offs == offset || offset == Type::OffsetBot || offs == Type::OffsetBot) { |
1567 | add_to_worklist(f); |
1568 | } |
1569 | } |
1570 | } |
1571 | } else { |
1572 | assert(base->is_JavaObject(), "sanity")do { if (!(base->is_JavaObject())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1572, "assert(" "base->is_JavaObject()" ") failed", "sanity" ); ::breakpoint(); } } while (0); |
1573 | if (// Skip phantom_object since it is only used to indicate that |
1574 | // this field's content globally escapes. |
1575 | (base != phantom_obj) && |
1576 | // NULL object node does not have fields. |
1577 | (base != null_obj)) { |
1578 | for (EdgeIterator i(base); i.has_next(); i.next()) { |
1579 | PointsToNode* f = i.get(); |
1580 | // Skip arraycopy edge since store to destination object field |
1581 | // does not update value in source object field. |
1582 | if (f->is_Arraycopy()) { |
1583 | assert(base->arraycopy_dst(), "sanity")do { if (!(base->arraycopy_dst())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1583, "assert(" "base->arraycopy_dst()" ") failed", "sanity" ); ::breakpoint(); } } while (0); |
1584 | continue; |
1585 | } |
1586 | if (f == field || !f->as_Field()->is_oop()) { |
1587 | continue; |
1588 | } |
1589 | int offs = f->as_Field()->offset(); |
1590 | if (offs == offset || offset == Type::OffsetBot || offs == Type::OffsetBot) { |
1591 | add_to_worklist(f); |
1592 | } |
1593 | } |
1594 | } |
1595 | } |
1596 | } |
1597 | |
1598 | // Find fields which have unknown value. |
1599 | int ConnectionGraph::find_field_value(FieldNode* field) { |
1600 | // Escaped fields should have init value already. |
1601 | assert(field->escape_state() == PointsToNode::NoEscape, "sanity")do { if (!(field->escape_state() == PointsToNode::NoEscape )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1601, "assert(" "field->escape_state() == PointsToNode::NoEscape" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1602 | int new_edges = 0; |
1603 | for (BaseIterator i(field); i.has_next(); i.next()) { |
1604 | PointsToNode* base = i.get(); |
1605 | if (base->is_JavaObject()) { |
1606 | // Skip Allocate's fields which will be processed later. |
1607 | if (base->ideal_node()->is_Allocate()) { |
1608 | return 0; |
1609 | } |
1610 | assert(base == null_obj, "only NULL ptr base expected here")do { if (!(base == null_obj)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1610, "assert(" "base == null_obj" ") failed", "only NULL ptr base expected here" ); ::breakpoint(); } } while (0); |
1611 | } |
1612 | } |
1613 | if (add_edge(field, phantom_obj)) { |
1614 | // New edge was added |
1615 | new_edges++; |
1616 | add_field_uses_to_worklist(field); |
1617 | } |
1618 | return new_edges; |
1619 | } |
1620 | |
1621 | // Find fields initializing values for allocations. |
1622 | int ConnectionGraph::find_init_values_phantom(JavaObjectNode* pta) { |
1623 | assert(pta->escape_state() == PointsToNode::NoEscape, "Not escaped Allocate nodes only")do { if (!(pta->escape_state() == PointsToNode::NoEscape)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1623, "assert(" "pta->escape_state() == PointsToNode::NoEscape" ") failed", "Not escaped Allocate nodes only"); ::breakpoint (); } } while (0); |
1624 | Node* alloc = pta->ideal_node(); |
1625 | |
1626 | // Do nothing for Allocate nodes since its fields values are |
1627 | // "known" unless they are initialized by arraycopy/clone. |
1628 | if (alloc->is_Allocate() && !pta->arraycopy_dst()) { |
1629 | return 0; |
1630 | } |
1631 | assert(pta->arraycopy_dst() || alloc->as_CallStaticJava(), "sanity")do { if (!(pta->arraycopy_dst() || alloc->as_CallStaticJava ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1631, "assert(" "pta->arraycopy_dst() || alloc->as_CallStaticJava()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1632 | #ifdef ASSERT1 |
1633 | if (!pta->arraycopy_dst() && alloc->as_CallStaticJava()->method() == NULL__null) { |
1634 | const char* name = alloc->as_CallStaticJava()->_name; |
1635 | assert(strncmp(name, "_multianewarray", 15) == 0, "sanity")do { if (!(strncmp(name, "_multianewarray", 15) == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1635, "assert(" "strncmp(name, \"_multianewarray\", 15) == 0" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1636 | } |
1637 | #endif |
1638 | // Non-escaped allocation returned from Java or runtime call have unknown values in fields. |
1639 | int new_edges = 0; |
1640 | for (EdgeIterator i(pta); i.has_next(); i.next()) { |
1641 | PointsToNode* field = i.get(); |
1642 | if (field->is_Field() && field->as_Field()->is_oop()) { |
1643 | if (add_edge(field, phantom_obj)) { |
1644 | // New edge was added |
1645 | new_edges++; |
1646 | add_field_uses_to_worklist(field->as_Field()); |
1647 | } |
1648 | } |
1649 | } |
1650 | return new_edges; |
1651 | } |
1652 | |
1653 | // Find fields initializing values for allocations. |
1654 | int ConnectionGraph::find_init_values_null(JavaObjectNode* pta, PhaseTransform* phase) { |
1655 | assert(pta->escape_state() == PointsToNode::NoEscape, "Not escaped Allocate nodes only")do { if (!(pta->escape_state() == PointsToNode::NoEscape)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1655, "assert(" "pta->escape_state() == PointsToNode::NoEscape" ") failed", "Not escaped Allocate nodes only"); ::breakpoint (); } } while (0); |
1656 | Node* alloc = pta->ideal_node(); |
1657 | // Do nothing for Call nodes since its fields values are unknown. |
1658 | if (!alloc->is_Allocate()) { |
1659 | return 0; |
1660 | } |
1661 | InitializeNode* ini = alloc->as_Allocate()->initialization(); |
1662 | bool visited_bottom_offset = false; |
1663 | GrowableArray<int> offsets_worklist; |
1664 | int new_edges = 0; |
1665 | |
1666 | // Check if an oop field's initializing value is recorded and add |
1667 | // a corresponding NULL if field's value if it is not recorded. |
1668 | // Connection Graph does not record a default initialization by NULL |
1669 | // captured by Initialize node. |
1670 | // |
1671 | for (EdgeIterator i(pta); i.has_next(); i.next()) { |
1672 | PointsToNode* field = i.get(); // Field (AddP) |
1673 | if (!field->is_Field() || !field->as_Field()->is_oop()) { |
1674 | continue; // Not oop field |
1675 | } |
1676 | int offset = field->as_Field()->offset(); |
1677 | if (offset == Type::OffsetBot) { |
1678 | if (!visited_bottom_offset) { |
1679 | // OffsetBot is used to reference array's element, |
1680 | // always add reference to NULL to all Field nodes since we don't |
1681 | // known which element is referenced. |
1682 | if (add_edge(field, null_obj)) { |
1683 | // New edge was added |
1684 | new_edges++; |
1685 | add_field_uses_to_worklist(field->as_Field()); |
1686 | visited_bottom_offset = true; |
1687 | } |
1688 | } |
1689 | } else { |
1690 | // Check only oop fields. |
1691 | const Type* adr_type = field->ideal_node()->as_AddP()->bottom_type(); |
1692 | if (adr_type->isa_rawptr()) { |
1693 | #ifdef ASSERT1 |
1694 | // Raw pointers are used for initializing stores so skip it |
1695 | // since it should be recorded already |
1696 | Node* base = get_addp_base(field->ideal_node()); |
1697 | assert(adr_type->isa_rawptr() && is_captured_store_address(field->ideal_node()), "unexpected pointer type")do { if (!(adr_type->isa_rawptr() && is_captured_store_address (field->ideal_node()))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1697, "assert(" "adr_type->isa_rawptr() && is_captured_store_address(field->ideal_node())" ") failed", "unexpected pointer type"); ::breakpoint(); } } while (0); |
1698 | #endif |
1699 | continue; |
1700 | } |
1701 | if (!offsets_worklist.contains(offset)) { |
1702 | offsets_worklist.append(offset); |
1703 | Node* value = NULL__null; |
1704 | if (ini != NULL__null) { |
1705 | // StoreP::memory_type() == T_ADDRESS |
1706 | BasicType ft = UseCompressedOops ? T_NARROWOOP : T_ADDRESS; |
1707 | Node* store = ini->find_captured_store(offset, type2aelembytes(ft, true), phase); |
1708 | // Make sure initializing store has the same type as this AddP. |
1709 | // This AddP may reference non existing field because it is on a |
1710 | // dead branch of bimorphic call which is not eliminated yet. |
1711 | if (store != NULL__null && store->is_Store() && |
1712 | store->as_Store()->memory_type() == ft) { |
1713 | value = store->in(MemNode::ValueIn); |
1714 | #ifdef ASSERT1 |
1715 | if (VerifyConnectionGraph) { |
1716 | // Verify that AddP already points to all objects the value points to. |
1717 | PointsToNode* val = ptnode_adr(value->_idx); |
1718 | assert((val != NULL), "should be processed already")do { if (!((val != __null))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1718, "assert(" "(val != __null)" ") failed", "should be processed already" ); ::breakpoint(); } } while (0); |
1719 | PointsToNode* missed_obj = NULL__null; |
1720 | if (val->is_JavaObject()) { |
1721 | if (!field->points_to(val->as_JavaObject())) { |
1722 | missed_obj = val; |
1723 | } |
1724 | } else { |
1725 | if (!val->is_LocalVar() || (val->edge_count() == 0)) { |
1726 | tty->print_cr("----------init store has invalid value -----"); |
1727 | store->dump(); |
1728 | val->dump(); |
1729 | assert(val->is_LocalVar() && (val->edge_count() > 0), "should be processed already")do { if (!(val->is_LocalVar() && (val->edge_count () > 0))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1729, "assert(" "val->is_LocalVar() && (val->edge_count() > 0)" ") failed", "should be processed already"); ::breakpoint(); } } while (0); |
1730 | } |
1731 | for (EdgeIterator j(val); j.has_next(); j.next()) { |
1732 | PointsToNode* obj = j.get(); |
1733 | if (obj->is_JavaObject()) { |
1734 | if (!field->points_to(obj->as_JavaObject())) { |
1735 | missed_obj = obj; |
1736 | break; |
1737 | } |
1738 | } |
1739 | } |
1740 | } |
1741 | if (missed_obj != NULL__null) { |
1742 | tty->print_cr("----------field---------------------------------"); |
1743 | field->dump(); |
1744 | tty->print_cr("----------missed referernce to object-----------"); |
1745 | missed_obj->dump(); |
1746 | tty->print_cr("----------object referernced by init store -----"); |
1747 | store->dump(); |
1748 | val->dump(); |
1749 | assert(!field->points_to(missed_obj->as_JavaObject()), "missed JavaObject reference")do { if (!(!field->points_to(missed_obj->as_JavaObject( )))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1749, "assert(" "!field->points_to(missed_obj->as_JavaObject())" ") failed", "missed JavaObject reference"); ::breakpoint(); } } while (0); |
1750 | } |
1751 | } |
1752 | #endif |
1753 | } else { |
1754 | // There could be initializing stores which follow allocation. |
1755 | // For example, a volatile field store is not collected |
1756 | // by Initialize node. |
1757 | // |
1758 | // Need to check for dependent loads to separate such stores from |
1759 | // stores which follow loads. For now, add initial value NULL so |
1760 | // that compare pointers optimization works correctly. |
1761 | } |
1762 | } |
1763 | if (value == NULL__null) { |
1764 | // A field's initializing value was not recorded. Add NULL. |
1765 | if (add_edge(field, null_obj)) { |
1766 | // New edge was added |
1767 | new_edges++; |
1768 | add_field_uses_to_worklist(field->as_Field()); |
1769 | } |
1770 | } |
1771 | } |
1772 | } |
1773 | } |
1774 | return new_edges; |
1775 | } |
1776 | |
1777 | // Adjust scalar_replaceable state after Connection Graph is built. |
1778 | void ConnectionGraph::adjust_scalar_replaceable_state(JavaObjectNode* jobj) { |
1779 | // Search for non-escaping objects which are not scalar replaceable |
1780 | // and mark them to propagate the state to referenced objects. |
1781 | |
1782 | for (UseIterator i(jobj); i.has_next(); i.next()) { |
1783 | PointsToNode* use = i.get(); |
1784 | if (use->is_Arraycopy()) { |
1785 | continue; |
1786 | } |
1787 | if (use->is_Field()) { |
1788 | FieldNode* field = use->as_Field(); |
1789 | assert(field->is_oop() && field->scalar_replaceable(), "sanity")do { if (!(field->is_oop() && field->scalar_replaceable ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1789, "assert(" "field->is_oop() && field->scalar_replaceable()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1790 | // 1. An object is not scalar replaceable if the field into which it is |
1791 | // stored has unknown offset (stored into unknown element of an array). |
1792 | if (field->offset() == Type::OffsetBot) { |
1793 | jobj->set_scalar_replaceable(false); |
1794 | return; |
1795 | } |
1796 | // 2. An object is not scalar replaceable if the field into which it is |
1797 | // stored has multiple bases one of which is null. |
1798 | if (field->base_count() > 1) { |
1799 | for (BaseIterator i(field); i.has_next(); i.next()) { |
1800 | PointsToNode* base = i.get(); |
1801 | if (base == null_obj) { |
1802 | jobj->set_scalar_replaceable(false); |
1803 | return; |
1804 | } |
1805 | } |
1806 | } |
1807 | } |
1808 | assert(use->is_Field() || use->is_LocalVar(), "sanity")do { if (!(use->is_Field() || use->is_LocalVar())) { (* g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1808, "assert(" "use->is_Field() || use->is_LocalVar()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1809 | // 3. An object is not scalar replaceable if it is merged with other objects. |
1810 | for (EdgeIterator j(use); j.has_next(); j.next()) { |
1811 | PointsToNode* ptn = j.get(); |
1812 | if (ptn->is_JavaObject() && ptn != jobj) { |
1813 | // Mark all objects. |
1814 | jobj->set_scalar_replaceable(false); |
1815 | ptn->set_scalar_replaceable(false); |
1816 | } |
1817 | } |
1818 | if (!jobj->scalar_replaceable()) { |
1819 | return; |
1820 | } |
1821 | } |
1822 | |
1823 | for (EdgeIterator j(jobj); j.has_next(); j.next()) { |
1824 | if (j.get()->is_Arraycopy()) { |
1825 | continue; |
1826 | } |
1827 | |
1828 | // Non-escaping object node should point only to field nodes. |
1829 | FieldNode* field = j.get()->as_Field(); |
1830 | int offset = field->as_Field()->offset(); |
1831 | |
1832 | // 4. An object is not scalar replaceable if it has a field with unknown |
1833 | // offset (array's element is accessed in loop). |
1834 | if (offset == Type::OffsetBot) { |
1835 | jobj->set_scalar_replaceable(false); |
1836 | return; |
1837 | } |
1838 | // 5. Currently an object is not scalar replaceable if a LoadStore node |
1839 | // access its field since the field value is unknown after it. |
1840 | // |
1841 | Node* n = field->ideal_node(); |
1842 | |
1843 | // Test for an unsafe access that was parsed as maybe off heap |
1844 | // (with a CheckCastPP to raw memory). |
1845 | assert(n->is_AddP(), "expect an address computation")do { if (!(n->is_AddP())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1845, "assert(" "n->is_AddP()" ") failed", "expect an address computation" ); ::breakpoint(); } } while (0); |
1846 | if (n->in(AddPNode::Base)->is_top() && |
1847 | n->in(AddPNode::Address)->Opcode() == Op_CheckCastPP) { |
1848 | assert(n->in(AddPNode::Address)->bottom_type()->isa_rawptr(), "raw address so raw cast expected")do { if (!(n->in(AddPNode::Address)->bottom_type()-> isa_rawptr())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1848, "assert(" "n->in(AddPNode::Address)->bottom_type()->isa_rawptr()" ") failed", "raw address so raw cast expected"); ::breakpoint (); } } while (0); |
1849 | assert(_igvn->type(n->in(AddPNode::Address)->in(1))->isa_oopptr(), "cast pattern at unsafe access expected")do { if (!(_igvn->type(n->in(AddPNode::Address)->in( 1))->isa_oopptr())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1849, "assert(" "_igvn->type(n->in(AddPNode::Address)->in(1))->isa_oopptr()" ") failed", "cast pattern at unsafe access expected"); ::breakpoint (); } } while (0); |
1850 | jobj->set_scalar_replaceable(false); |
1851 | return; |
1852 | } |
1853 | |
1854 | for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
1855 | Node* u = n->fast_out(i); |
1856 | if (u->is_LoadStore() || (u->is_Mem() && u->as_Mem()->is_mismatched_access())) { |
1857 | jobj->set_scalar_replaceable(false); |
1858 | return; |
1859 | } |
1860 | } |
1861 | |
1862 | // 6. Or the address may point to more then one object. This may produce |
1863 | // the false positive result (set not scalar replaceable) |
1864 | // since the flow-insensitive escape analysis can't separate |
1865 | // the case when stores overwrite the field's value from the case |
1866 | // when stores happened on different control branches. |
1867 | // |
1868 | // Note: it will disable scalar replacement in some cases: |
1869 | // |
1870 | // Point p[] = new Point[1]; |
1871 | // p[0] = new Point(); // Will be not scalar replaced |
1872 | // |
1873 | // but it will save us from incorrect optimizations in next cases: |
1874 | // |
1875 | // Point p[] = new Point[1]; |
1876 | // if ( x ) p[0] = new Point(); // Will be not scalar replaced |
1877 | // |
1878 | if (field->base_count() > 1) { |
1879 | for (BaseIterator i(field); i.has_next(); i.next()) { |
1880 | PointsToNode* base = i.get(); |
1881 | // Don't take into account LocalVar nodes which |
1882 | // may point to only one object which should be also |
1883 | // this field's base by now. |
1884 | if (base->is_JavaObject() && base != jobj) { |
1885 | // Mark all bases. |
1886 | jobj->set_scalar_replaceable(false); |
1887 | base->set_scalar_replaceable(false); |
1888 | } |
1889 | } |
1890 | } |
1891 | } |
1892 | } |
1893 | |
1894 | #ifdef ASSERT1 |
1895 | void ConnectionGraph::verify_connection_graph( |
1896 | GrowableArray<PointsToNode*>& ptnodes_worklist, |
1897 | GrowableArray<JavaObjectNode*>& non_escaped_allocs_worklist, |
1898 | GrowableArray<JavaObjectNode*>& java_objects_worklist, |
1899 | GrowableArray<Node*>& addp_worklist) { |
1900 | // Verify that graph is complete - no new edges could be added. |
1901 | int java_objects_length = java_objects_worklist.length(); |
1902 | int non_escaped_length = non_escaped_allocs_worklist.length(); |
1903 | int new_edges = 0; |
1904 | for (int next = 0; next < java_objects_length; ++next) { |
1905 | JavaObjectNode* ptn = java_objects_worklist.at(next); |
1906 | new_edges += add_java_object_edges(ptn, true); |
1907 | } |
1908 | assert(new_edges == 0, "graph was not complete")do { if (!(new_edges == 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1908, "assert(" "new_edges == 0" ") failed", "graph was not complete" ); ::breakpoint(); } } while (0); |
1909 | // Verify that escape state is final. |
1910 | int length = non_escaped_allocs_worklist.length(); |
1911 | find_non_escaped_objects(ptnodes_worklist, non_escaped_allocs_worklist); |
1912 | assert((non_escaped_length == non_escaped_allocs_worklist.length()) &&do { if (!((non_escaped_length == non_escaped_allocs_worklist .length()) && (non_escaped_length == length) && (_worklist.length() == 0))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1914, "assert(" "(non_escaped_length == non_escaped_allocs_worklist.length()) && (non_escaped_length == length) && (_worklist.length() == 0)" ") failed", "escape state was not final"); ::breakpoint(); } } while (0) |
1913 | (non_escaped_length == length) &&do { if (!((non_escaped_length == non_escaped_allocs_worklist .length()) && (non_escaped_length == length) && (_worklist.length() == 0))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1914, "assert(" "(non_escaped_length == non_escaped_allocs_worklist.length()) && (non_escaped_length == length) && (_worklist.length() == 0)" ") failed", "escape state was not final"); ::breakpoint(); } } while (0) |
1914 | (_worklist.length() == 0), "escape state was not final")do { if (!((non_escaped_length == non_escaped_allocs_worklist .length()) && (non_escaped_length == length) && (_worklist.length() == 0))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1914, "assert(" "(non_escaped_length == non_escaped_allocs_worklist.length()) && (non_escaped_length == length) && (_worklist.length() == 0)" ") failed", "escape state was not final"); ::breakpoint(); } } while (0); |
1915 | |
1916 | // Verify fields information. |
1917 | int addp_length = addp_worklist.length(); |
1918 | for (int next = 0; next < addp_length; ++next ) { |
1919 | Node* n = addp_worklist.at(next); |
1920 | FieldNode* field = ptnode_adr(n->_idx)->as_Field(); |
1921 | if (field->is_oop()) { |
1922 | // Verify that field has all bases |
1923 | Node* base = get_addp_base(n); |
1924 | PointsToNode* ptn = ptnode_adr(base->_idx); |
1925 | if (ptn->is_JavaObject()) { |
1926 | assert(field->has_base(ptn->as_JavaObject()), "sanity")do { if (!(field->has_base(ptn->as_JavaObject()))) { (* g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1926, "assert(" "field->has_base(ptn->as_JavaObject())" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1927 | } else { |
1928 | assert(ptn->is_LocalVar(), "sanity")do { if (!(ptn->is_LocalVar())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1928, "assert(" "ptn->is_LocalVar()" ") failed", "sanity" ); ::breakpoint(); } } while (0); |
1929 | for (EdgeIterator i(ptn); i.has_next(); i.next()) { |
1930 | PointsToNode* e = i.get(); |
1931 | if (e->is_JavaObject()) { |
1932 | assert(field->has_base(e->as_JavaObject()), "sanity")do { if (!(field->has_base(e->as_JavaObject()))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1932, "assert(" "field->has_base(e->as_JavaObject())" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1933 | } |
1934 | } |
1935 | } |
1936 | // Verify that all fields have initializing values. |
1937 | if (field->edge_count() == 0) { |
1938 | tty->print_cr("----------field does not have references----------"); |
1939 | field->dump(); |
1940 | for (BaseIterator i(field); i.has_next(); i.next()) { |
1941 | PointsToNode* base = i.get(); |
1942 | tty->print_cr("----------field has next base---------------------"); |
1943 | base->dump(); |
1944 | if (base->is_JavaObject() && (base != phantom_obj) && (base != null_obj)) { |
1945 | tty->print_cr("----------base has fields-------------------------"); |
1946 | for (EdgeIterator j(base); j.has_next(); j.next()) { |
1947 | j.get()->dump(); |
1948 | } |
1949 | tty->print_cr("----------base has references---------------------"); |
1950 | for (UseIterator j(base); j.has_next(); j.next()) { |
1951 | j.get()->dump(); |
1952 | } |
1953 | } |
1954 | } |
1955 | for (UseIterator i(field); i.has_next(); i.next()) { |
1956 | i.get()->dump(); |
1957 | } |
1958 | assert(field->edge_count() > 0, "sanity")do { if (!(field->edge_count() > 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1958, "assert(" "field->edge_count() > 0" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1959 | } |
1960 | } |
1961 | } |
1962 | } |
1963 | #endif |
1964 | |
1965 | // Optimize ideal graph. |
1966 | void ConnectionGraph::optimize_ideal_graph(GrowableArray<Node*>& ptr_cmp_worklist, |
1967 | GrowableArray<MemBarStoreStoreNode*>& storestore_worklist) { |
1968 | Compile* C = _compile; |
1969 | PhaseIterGVN* igvn = _igvn; |
1970 | if (EliminateLocks) { |
1971 | // Mark locks before changing ideal graph. |
1972 | int cnt = C->macro_count(); |
1973 | for (int i = 0; i < cnt; i++) { |
1974 | Node *n = C->macro_node(i); |
1975 | if (n->is_AbstractLock()) { // Lock and Unlock nodes |
1976 | AbstractLockNode* alock = n->as_AbstractLock(); |
1977 | if (!alock->is_non_esc_obj()) { |
1978 | if (not_global_escape(alock->obj_node())) { |
1979 | assert(!alock->is_eliminated() || alock->is_coarsened(), "sanity")do { if (!(!alock->is_eliminated() || alock->is_coarsened ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 1979, "assert(" "!alock->is_eliminated() || alock->is_coarsened()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
1980 | // The lock could be marked eliminated by lock coarsening |
1981 | // code during first IGVN before EA. Replace coarsened flag |
1982 | // to eliminate all associated locks/unlocks. |
1983 | #ifdef ASSERT1 |
1984 | alock->log_lock_optimization(C, "eliminate_lock_set_non_esc3"); |
1985 | #endif |
1986 | alock->set_non_esc_obj(); |
1987 | } |
1988 | } |
1989 | } |
1990 | } |
1991 | } |
1992 | |
1993 | if (OptimizePtrCompare) { |
1994 | for (int i = 0; i < ptr_cmp_worklist.length(); i++) { |
1995 | Node *n = ptr_cmp_worklist.at(i); |
1996 | const TypeInt* tcmp = optimize_ptr_compare(n); |
1997 | if (tcmp->singleton()) { |
1998 | Node* cmp = igvn->makecon(tcmp); |
1999 | #ifndef PRODUCT |
2000 | if (PrintOptimizePtrCompare) { |
2001 | tty->print_cr("++++ Replaced: %d %s(%d,%d) --> %s", n->_idx, (n->Opcode() == Op_CmpP ? "CmpP" : "CmpN"), n->in(1)->_idx, n->in(2)->_idx, (tcmp == TypeInt::CC_EQ ? "EQ" : "NotEQ")); |
2002 | if (Verbose) { |
2003 | n->dump(1); |
2004 | } |
2005 | } |
2006 | #endif |
2007 | igvn->replace_node(n, cmp); |
2008 | } |
2009 | } |
2010 | } |
2011 | |
2012 | // For MemBarStoreStore nodes added in library_call.cpp, check |
2013 | // escape status of associated AllocateNode and optimize out |
2014 | // MemBarStoreStore node if the allocated object never escapes. |
2015 | for (int i = 0; i < storestore_worklist.length(); i++) { |
2016 | Node* storestore = storestore_worklist.at(i); |
2017 | Node* alloc = storestore->in(MemBarNode::Precedent)->in(0); |
2018 | if (alloc->is_Allocate() && not_global_escape(alloc)) { |
2019 | MemBarNode* mb = MemBarNode::make(C, Op_MemBarCPUOrder, Compile::AliasIdxBot); |
2020 | mb->init_req(TypeFunc::Memory, storestore->in(TypeFunc::Memory)); |
2021 | mb->init_req(TypeFunc::Control, storestore->in(TypeFunc::Control)); |
2022 | igvn->register_new_node_with_optimizer(mb); |
2023 | igvn->replace_node(storestore, mb); |
2024 | } |
2025 | } |
2026 | } |
2027 | |
2028 | // Optimize objects compare. |
2029 | const TypeInt* ConnectionGraph::optimize_ptr_compare(Node* n) { |
2030 | assert(OptimizePtrCompare, "sanity")do { if (!(OptimizePtrCompare)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2030, "assert(" "OptimizePtrCompare" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2031 | assert(n->Opcode() == Op_CmpN || n->Opcode() == Op_CmpP, "must be")do { if (!(n->Opcode() == Op_CmpN || n->Opcode() == Op_CmpP )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2031, "assert(" "n->Opcode() == Op_CmpN || n->Opcode() == Op_CmpP" ") failed", "must be"); ::breakpoint(); } } while (0); |
2032 | const TypeInt* EQ = TypeInt::CC_EQ; // [0] == ZERO |
2033 | const TypeInt* NE = TypeInt::CC_GT; // [1] == ONE |
2034 | const TypeInt* UNKNOWN = TypeInt::CC; // [-1, 0,1] |
2035 | |
2036 | PointsToNode* ptn1 = ptnode_adr(n->in(1)->_idx); |
2037 | PointsToNode* ptn2 = ptnode_adr(n->in(2)->_idx); |
2038 | JavaObjectNode* jobj1 = unique_java_object(n->in(1)); |
2039 | JavaObjectNode* jobj2 = unique_java_object(n->in(2)); |
2040 | assert(ptn1->is_JavaObject() || ptn1->is_LocalVar(), "sanity")do { if (!(ptn1->is_JavaObject() || ptn1->is_LocalVar() )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2040, "assert(" "ptn1->is_JavaObject() || ptn1->is_LocalVar()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2041 | assert(ptn2->is_JavaObject() || ptn2->is_LocalVar(), "sanity")do { if (!(ptn2->is_JavaObject() || ptn2->is_LocalVar() )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2041, "assert(" "ptn2->is_JavaObject() || ptn2->is_LocalVar()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2042 | |
2043 | // Check simple cases first. |
2044 | if (jobj1 != NULL__null) { |
2045 | if (jobj1->escape_state() == PointsToNode::NoEscape) { |
2046 | if (jobj1 == jobj2) { |
2047 | // Comparing the same not escaping object. |
2048 | return EQ; |
2049 | } |
2050 | Node* obj = jobj1->ideal_node(); |
2051 | // Comparing not escaping allocation. |
2052 | if ((obj->is_Allocate() || obj->is_CallStaticJava()) && |
2053 | !ptn2->points_to(jobj1)) { |
2054 | return NE; // This includes nullness check. |
2055 | } |
2056 | } |
2057 | } |
2058 | if (jobj2 != NULL__null) { |
2059 | if (jobj2->escape_state() == PointsToNode::NoEscape) { |
2060 | Node* obj = jobj2->ideal_node(); |
2061 | // Comparing not escaping allocation. |
2062 | if ((obj->is_Allocate() || obj->is_CallStaticJava()) && |
2063 | !ptn1->points_to(jobj2)) { |
2064 | return NE; // This includes nullness check. |
2065 | } |
2066 | } |
2067 | } |
2068 | if (jobj1 != NULL__null && jobj1 != phantom_obj && |
2069 | jobj2 != NULL__null && jobj2 != phantom_obj && |
2070 | jobj1->ideal_node()->is_Con() && |
2071 | jobj2->ideal_node()->is_Con()) { |
2072 | // Klass or String constants compare. Need to be careful with |
2073 | // compressed pointers - compare types of ConN and ConP instead of nodes. |
2074 | const Type* t1 = jobj1->ideal_node()->get_ptr_type(); |
2075 | const Type* t2 = jobj2->ideal_node()->get_ptr_type(); |
2076 | if (t1->make_ptr() == t2->make_ptr()) { |
2077 | return EQ; |
2078 | } else { |
2079 | return NE; |
2080 | } |
2081 | } |
2082 | if (ptn1->meet(ptn2)) { |
2083 | return UNKNOWN; // Sets are not disjoint |
2084 | } |
2085 | |
2086 | // Sets are disjoint. |
2087 | bool set1_has_unknown_ptr = ptn1->points_to(phantom_obj); |
2088 | bool set2_has_unknown_ptr = ptn2->points_to(phantom_obj); |
2089 | bool set1_has_null_ptr = ptn1->points_to(null_obj); |
2090 | bool set2_has_null_ptr = ptn2->points_to(null_obj); |
2091 | if ((set1_has_unknown_ptr && set2_has_null_ptr) || |
2092 | (set2_has_unknown_ptr && set1_has_null_ptr)) { |
2093 | // Check nullness of unknown object. |
2094 | return UNKNOWN; |
2095 | } |
2096 | |
2097 | // Disjointness by itself is not sufficient since |
2098 | // alias analysis is not complete for escaped objects. |
2099 | // Disjoint sets are definitely unrelated only when |
2100 | // at least one set has only not escaping allocations. |
2101 | if (!set1_has_unknown_ptr && !set1_has_null_ptr) { |
2102 | if (ptn1->non_escaping_allocation()) { |
2103 | return NE; |
2104 | } |
2105 | } |
2106 | if (!set2_has_unknown_ptr && !set2_has_null_ptr) { |
2107 | if (ptn2->non_escaping_allocation()) { |
2108 | return NE; |
2109 | } |
2110 | } |
2111 | return UNKNOWN; |
2112 | } |
2113 | |
2114 | // Connection Graph construction functions. |
2115 | |
2116 | void ConnectionGraph::add_local_var(Node *n, PointsToNode::EscapeState es) { |
2117 | PointsToNode* ptadr = _nodes.at(n->_idx); |
2118 | if (ptadr != NULL__null) { |
2119 | assert(ptadr->is_LocalVar() && ptadr->ideal_node() == n, "sanity")do { if (!(ptadr->is_LocalVar() && ptadr->ideal_node () == n)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2119, "assert(" "ptadr->is_LocalVar() && ptadr->ideal_node() == n" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2120 | return; |
2121 | } |
2122 | Compile* C = _compile; |
2123 | ptadr = new (C->comp_arena()) LocalVarNode(this, n, es); |
2124 | map_ideal_node(n, ptadr); |
2125 | } |
2126 | |
2127 | void ConnectionGraph::add_java_object(Node *n, PointsToNode::EscapeState es) { |
2128 | PointsToNode* ptadr = _nodes.at(n->_idx); |
2129 | if (ptadr != NULL__null) { |
2130 | assert(ptadr->is_JavaObject() && ptadr->ideal_node() == n, "sanity")do { if (!(ptadr->is_JavaObject() && ptadr->ideal_node () == n)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2130, "assert(" "ptadr->is_JavaObject() && ptadr->ideal_node() == n" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2131 | return; |
2132 | } |
2133 | Compile* C = _compile; |
2134 | ptadr = new (C->comp_arena()) JavaObjectNode(this, n, es); |
2135 | map_ideal_node(n, ptadr); |
2136 | } |
2137 | |
2138 | void ConnectionGraph::add_field(Node *n, PointsToNode::EscapeState es, int offset) { |
2139 | PointsToNode* ptadr = _nodes.at(n->_idx); |
2140 | if (ptadr != NULL__null) { |
2141 | assert(ptadr->is_Field() && ptadr->ideal_node() == n, "sanity")do { if (!(ptadr->is_Field() && ptadr->ideal_node () == n)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2141, "assert(" "ptadr->is_Field() && ptadr->ideal_node() == n" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2142 | return; |
2143 | } |
2144 | bool unsafe = false; |
2145 | bool is_oop = is_oop_field(n, offset, &unsafe); |
2146 | if (unsafe) { |
2147 | es = PointsToNode::GlobalEscape; |
2148 | } |
2149 | Compile* C = _compile; |
2150 | FieldNode* field = new (C->comp_arena()) FieldNode(this, n, es, offset, is_oop); |
2151 | map_ideal_node(n, field); |
2152 | } |
2153 | |
2154 | void ConnectionGraph::add_arraycopy(Node *n, PointsToNode::EscapeState es, |
2155 | PointsToNode* src, PointsToNode* dst) { |
2156 | assert(!src->is_Field() && !dst->is_Field(), "only for JavaObject and LocalVar")do { if (!(!src->is_Field() && !dst->is_Field() )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2156, "assert(" "!src->is_Field() && !dst->is_Field()" ") failed", "only for JavaObject and LocalVar"); ::breakpoint (); } } while (0); |
2157 | assert((src != null_obj) && (dst != null_obj), "not for ConP NULL")do { if (!((src != null_obj) && (dst != null_obj))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2157, "assert(" "(src != null_obj) && (dst != null_obj)" ") failed", "not for ConP NULL"); ::breakpoint(); } } while ( 0); |
2158 | PointsToNode* ptadr = _nodes.at(n->_idx); |
2159 | if (ptadr != NULL__null) { |
2160 | assert(ptadr->is_Arraycopy() && ptadr->ideal_node() == n, "sanity")do { if (!(ptadr->is_Arraycopy() && ptadr->ideal_node () == n)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2160, "assert(" "ptadr->is_Arraycopy() && ptadr->ideal_node() == n" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2161 | return; |
2162 | } |
2163 | Compile* C = _compile; |
2164 | ptadr = new (C->comp_arena()) ArraycopyNode(this, n, es); |
2165 | map_ideal_node(n, ptadr); |
2166 | // Add edge from arraycopy node to source object. |
2167 | (void)add_edge(ptadr, src); |
2168 | src->set_arraycopy_src(); |
2169 | // Add edge from destination object to arraycopy node. |
2170 | (void)add_edge(dst, ptadr); |
2171 | dst->set_arraycopy_dst(); |
2172 | } |
2173 | |
2174 | bool ConnectionGraph::is_oop_field(Node* n, int offset, bool* unsafe) { |
2175 | const Type* adr_type = n->as_AddP()->bottom_type(); |
2176 | BasicType bt = T_INT; |
2177 | if (offset == Type::OffsetBot) { |
2178 | // Check only oop fields. |
2179 | if (!adr_type->isa_aryptr() || |
2180 | (adr_type->isa_aryptr()->klass() == NULL__null) || |
2181 | adr_type->isa_aryptr()->klass()->is_obj_array_klass()) { |
2182 | // OffsetBot is used to reference array's element. Ignore first AddP. |
2183 | if (find_second_addp(n, n->in(AddPNode::Base)) == NULL__null) { |
2184 | bt = T_OBJECT; |
2185 | } |
2186 | } |
2187 | } else if (offset != oopDesc::klass_offset_in_bytes()) { |
2188 | if (adr_type->isa_instptr()) { |
2189 | ciField* field = _compile->alias_type(adr_type->isa_instptr())->field(); |
2190 | if (field != NULL__null) { |
2191 | bt = field->layout_type(); |
2192 | } else { |
2193 | // Check for unsafe oop field access |
2194 | if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN) || |
2195 | n->has_out_with(Op_GetAndSetP, Op_GetAndSetN, Op_CompareAndExchangeP, Op_CompareAndExchangeN) || |
2196 | n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN) || |
2197 | BarrierSet::barrier_set()->barrier_set_c2()->escape_has_out_with_unsafe_object(n)) { |
2198 | bt = T_OBJECT; |
2199 | (*unsafe) = true; |
2200 | } |
2201 | } |
2202 | } else if (adr_type->isa_aryptr()) { |
2203 | if (offset == arrayOopDesc::length_offset_in_bytes()) { |
2204 | // Ignore array length load. |
2205 | } else if (find_second_addp(n, n->in(AddPNode::Base)) != NULL__null) { |
2206 | // Ignore first AddP. |
2207 | } else { |
2208 | const Type* elemtype = adr_type->isa_aryptr()->elem(); |
2209 | bt = elemtype->array_element_basic_type(); |
2210 | } |
2211 | } else if (adr_type->isa_rawptr() || adr_type->isa_klassptr()) { |
2212 | // Allocation initialization, ThreadLocal field access, unsafe access |
2213 | if (n->has_out_with(Op_StoreP, Op_LoadP, Op_StoreN, Op_LoadN) || |
2214 | n->has_out_with(Op_GetAndSetP, Op_GetAndSetN, Op_CompareAndExchangeP, Op_CompareAndExchangeN) || |
2215 | n->has_out_with(Op_CompareAndSwapP, Op_CompareAndSwapN, Op_WeakCompareAndSwapP, Op_WeakCompareAndSwapN) || |
2216 | BarrierSet::barrier_set()->barrier_set_c2()->escape_has_out_with_unsafe_object(n)) { |
2217 | bt = T_OBJECT; |
2218 | } |
2219 | } |
2220 | } |
2221 | // Note: T_NARROWOOP is not classed as a real reference type |
2222 | return (is_reference_type(bt) || bt == T_NARROWOOP); |
2223 | } |
2224 | |
2225 | // Returns unique pointed java object or NULL. |
2226 | JavaObjectNode* ConnectionGraph::unique_java_object(Node *n) { |
2227 | assert(!_collecting, "should not call when constructed graph")do { if (!(!_collecting)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2227, "assert(" "!_collecting" ") failed", "should not call when constructed graph" ); ::breakpoint(); } } while (0); |
2228 | // If the node was created after the escape computation we can't answer. |
2229 | uint idx = n->_idx; |
2230 | if (idx >= nodes_size()) { |
2231 | return NULL__null; |
2232 | } |
2233 | PointsToNode* ptn = ptnode_adr(idx); |
2234 | if (ptn == NULL__null) { |
2235 | return NULL__null; |
2236 | } |
2237 | if (ptn->is_JavaObject()) { |
2238 | return ptn->as_JavaObject(); |
2239 | } |
2240 | assert(ptn->is_LocalVar(), "sanity")do { if (!(ptn->is_LocalVar())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2240, "assert(" "ptn->is_LocalVar()" ") failed", "sanity" ); ::breakpoint(); } } while (0); |
2241 | // Check all java objects it points to. |
2242 | JavaObjectNode* jobj = NULL__null; |
2243 | for (EdgeIterator i(ptn); i.has_next(); i.next()) { |
2244 | PointsToNode* e = i.get(); |
2245 | if (e->is_JavaObject()) { |
2246 | if (jobj == NULL__null) { |
2247 | jobj = e->as_JavaObject(); |
2248 | } else if (jobj != e) { |
2249 | return NULL__null; |
2250 | } |
2251 | } |
2252 | } |
2253 | return jobj; |
2254 | } |
2255 | |
2256 | // Return true if this node points only to non-escaping allocations. |
2257 | bool PointsToNode::non_escaping_allocation() { |
2258 | if (is_JavaObject()) { |
2259 | Node* n = ideal_node(); |
2260 | if (n->is_Allocate() || n->is_CallStaticJava()) { |
2261 | return (escape_state() == PointsToNode::NoEscape); |
2262 | } else { |
2263 | return false; |
2264 | } |
2265 | } |
2266 | assert(is_LocalVar(), "sanity")do { if (!(is_LocalVar())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2266, "assert(" "is_LocalVar()" ") failed", "sanity"); ::breakpoint (); } } while (0); |
2267 | // Check all java objects it points to. |
2268 | for (EdgeIterator i(this); i.has_next(); i.next()) { |
2269 | PointsToNode* e = i.get(); |
2270 | if (e->is_JavaObject()) { |
2271 | Node* n = e->ideal_node(); |
2272 | if ((e->escape_state() != PointsToNode::NoEscape) || |
2273 | !(n->is_Allocate() || n->is_CallStaticJava())) { |
2274 | return false; |
2275 | } |
2276 | } |
2277 | } |
2278 | return true; |
2279 | } |
2280 | |
2281 | // Return true if we know the node does not escape globally. |
2282 | bool ConnectionGraph::not_global_escape(Node *n) { |
2283 | assert(!_collecting, "should not call during graph construction")do { if (!(!_collecting)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2283, "assert(" "!_collecting" ") failed", "should not call during graph construction" ); ::breakpoint(); } } while (0); |
2284 | // If the node was created after the escape computation we can't answer. |
2285 | uint idx = n->_idx; |
2286 | if (idx >= nodes_size()) { |
2287 | return false; |
2288 | } |
2289 | PointsToNode* ptn = ptnode_adr(idx); |
2290 | if (ptn == NULL__null) { |
2291 | return false; // not in congraph (e.g. ConI) |
2292 | } |
2293 | PointsToNode::EscapeState es = ptn->escape_state(); |
2294 | // If we have already computed a value, return it. |
2295 | if (es >= PointsToNode::GlobalEscape) { |
2296 | return false; |
2297 | } |
2298 | if (ptn->is_JavaObject()) { |
2299 | return true; // (es < PointsToNode::GlobalEscape); |
2300 | } |
2301 | assert(ptn->is_LocalVar(), "sanity")do { if (!(ptn->is_LocalVar())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2301, "assert(" "ptn->is_LocalVar()" ") failed", "sanity" ); ::breakpoint(); } } while (0); |
2302 | // Check all java objects it points to. |
2303 | for (EdgeIterator i(ptn); i.has_next(); i.next()) { |
2304 | if (i.get()->escape_state() >= PointsToNode::GlobalEscape) { |
2305 | return false; |
2306 | } |
2307 | } |
2308 | return true; |
2309 | } |
2310 | |
2311 | |
2312 | // Helper functions |
2313 | |
2314 | // Return true if this node points to specified node or nodes it points to. |
2315 | bool PointsToNode::points_to(JavaObjectNode* ptn) const { |
2316 | if (is_JavaObject()) { |
2317 | return (this == ptn); |
2318 | } |
2319 | assert(is_LocalVar() || is_Field(), "sanity")do { if (!(is_LocalVar() || is_Field())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2319, "assert(" "is_LocalVar() || is_Field()" ") failed", "sanity" ); ::breakpoint(); } } while (0); |
2320 | for (EdgeIterator i(this); i.has_next(); i.next()) { |
2321 | if (i.get() == ptn) { |
2322 | return true; |
2323 | } |
2324 | } |
2325 | return false; |
2326 | } |
2327 | |
2328 | // Return true if one node points to an other. |
2329 | bool PointsToNode::meet(PointsToNode* ptn) { |
2330 | if (this == ptn) { |
2331 | return true; |
2332 | } else if (ptn->is_JavaObject()) { |
2333 | return this->points_to(ptn->as_JavaObject()); |
2334 | } else if (this->is_JavaObject()) { |
2335 | return ptn->points_to(this->as_JavaObject()); |
2336 | } |
2337 | assert(this->is_LocalVar() && ptn->is_LocalVar(), "sanity")do { if (!(this->is_LocalVar() && ptn->is_LocalVar ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2337, "assert(" "this->is_LocalVar() && ptn->is_LocalVar()" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2338 | int ptn_count = ptn->edge_count(); |
2339 | for (EdgeIterator i(this); i.has_next(); i.next()) { |
2340 | PointsToNode* this_e = i.get(); |
2341 | for (int j = 0; j < ptn_count; j++) { |
2342 | if (this_e == ptn->edge(j)) { |
2343 | return true; |
2344 | } |
2345 | } |
2346 | } |
2347 | return false; |
2348 | } |
2349 | |
2350 | #ifdef ASSERT1 |
2351 | // Return true if bases point to this java object. |
2352 | bool FieldNode::has_base(JavaObjectNode* jobj) const { |
2353 | for (BaseIterator i(this); i.has_next(); i.next()) { |
2354 | if (i.get() == jobj) { |
2355 | return true; |
2356 | } |
2357 | } |
2358 | return false; |
2359 | } |
2360 | #endif |
2361 | |
2362 | bool ConnectionGraph::is_captured_store_address(Node* addp) { |
2363 | // Handle simple case first. |
2364 | assert(_igvn->type(addp)->isa_oopptr() == NULL, "should be raw access")do { if (!(_igvn->type(addp)->isa_oopptr() == __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2364, "assert(" "_igvn->type(addp)->isa_oopptr() == __null" ") failed", "should be raw access"); ::breakpoint(); } } while (0); |
2365 | if (addp->in(AddPNode::Address)->is_Proj() && addp->in(AddPNode::Address)->in(0)->is_Allocate()) { |
2366 | return true; |
2367 | } else if (addp->in(AddPNode::Address)->is_Phi()) { |
2368 | for (DUIterator_Fast imax, i = addp->fast_outs(imax); i < imax; i++) { |
2369 | Node* addp_use = addp->fast_out(i); |
2370 | if (addp_use->is_Store()) { |
2371 | for (DUIterator_Fast jmax, j = addp_use->fast_outs(jmax); j < jmax; j++) { |
2372 | if (addp_use->fast_out(j)->is_Initialize()) { |
2373 | return true; |
2374 | } |
2375 | } |
2376 | } |
2377 | } |
2378 | } |
2379 | return false; |
2380 | } |
2381 | |
2382 | int ConnectionGraph::address_offset(Node* adr, PhaseTransform *phase) { |
2383 | const Type *adr_type = phase->type(adr); |
2384 | if (adr->is_AddP() && adr_type->isa_oopptr() == NULL__null && is_captured_store_address(adr)) { |
2385 | // We are computing a raw address for a store captured by an Initialize |
2386 | // compute an appropriate address type. AddP cases #3 and #5 (see below). |
2387 | int offs = (int)phase->find_intptr_t_confind_long_con(adr->in(AddPNode::Offset), Type::OffsetBot); |
2388 | assert(offs != Type::OffsetBot ||do { if (!(offs != Type::OffsetBot || adr->in(AddPNode::Address )->in(0)->is_AllocateArray())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2390, "assert(" "offs != Type::OffsetBot || adr->in(AddPNode::Address)->in(0)->is_AllocateArray()" ") failed", "offset must be a constant or it is initialization of array" ); ::breakpoint(); } } while (0) |
2389 | adr->in(AddPNode::Address)->in(0)->is_AllocateArray(),do { if (!(offs != Type::OffsetBot || adr->in(AddPNode::Address )->in(0)->is_AllocateArray())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2390, "assert(" "offs != Type::OffsetBot || adr->in(AddPNode::Address)->in(0)->is_AllocateArray()" ") failed", "offset must be a constant or it is initialization of array" ); ::breakpoint(); } } while (0) |
2390 | "offset must be a constant or it is initialization of array")do { if (!(offs != Type::OffsetBot || adr->in(AddPNode::Address )->in(0)->is_AllocateArray())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2390, "assert(" "offs != Type::OffsetBot || adr->in(AddPNode::Address)->in(0)->is_AllocateArray()" ") failed", "offset must be a constant or it is initialization of array" ); ::breakpoint(); } } while (0); |
2391 | return offs; |
2392 | } |
2393 | const TypePtr *t_ptr = adr_type->isa_ptr(); |
2394 | assert(t_ptr != NULL, "must be a pointer type")do { if (!(t_ptr != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2394, "assert(" "t_ptr != __null" ") failed", "must be a pointer type" ); ::breakpoint(); } } while (0); |
2395 | return t_ptr->offset(); |
2396 | } |
2397 | |
2398 | Node* ConnectionGraph::get_addp_base(Node *addp) { |
2399 | assert(addp->is_AddP(), "must be AddP")do { if (!(addp->is_AddP())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2399, "assert(" "addp->is_AddP()" ") failed", "must be AddP" ); ::breakpoint(); } } while (0); |
2400 | // |
2401 | // AddP cases for Base and Address inputs: |
2402 | // case #1. Direct object's field reference: |
2403 | // Allocate |
2404 | // | |
2405 | // Proj #5 ( oop result ) |
2406 | // | |
2407 | // CheckCastPP (cast to instance type) |
2408 | // | | |
2409 | // AddP ( base == address ) |
2410 | // |
2411 | // case #2. Indirect object's field reference: |
2412 | // Phi |
2413 | // | |
2414 | // CastPP (cast to instance type) |
2415 | // | | |
2416 | // AddP ( base == address ) |
2417 | // |
2418 | // case #3. Raw object's field reference for Initialize node: |
2419 | // Allocate |
2420 | // | |
2421 | // Proj #5 ( oop result ) |
2422 | // top | |
2423 | // \ | |
2424 | // AddP ( base == top ) |
2425 | // |
2426 | // case #4. Array's element reference: |
2427 | // {CheckCastPP | CastPP} |
2428 | // | | | |
2429 | // | AddP ( array's element offset ) |
2430 | // | | |
2431 | // AddP ( array's offset ) |
2432 | // |
2433 | // case #5. Raw object's field reference for arraycopy stub call: |
2434 | // The inline_native_clone() case when the arraycopy stub is called |
2435 | // after the allocation before Initialize and CheckCastPP nodes. |
2436 | // Allocate |
2437 | // | |
2438 | // Proj #5 ( oop result ) |
2439 | // | | |
2440 | // AddP ( base == address ) |
2441 | // |
2442 | // case #6. Constant Pool, ThreadLocal, CastX2P or |
2443 | // Raw object's field reference: |
2444 | // {ConP, ThreadLocal, CastX2P, raw Load} |
2445 | // top | |
2446 | // \ | |
2447 | // AddP ( base == top ) |
2448 | // |
2449 | // case #7. Klass's field reference. |
2450 | // LoadKlass |
2451 | // | | |
2452 | // AddP ( base == address ) |
2453 | // |
2454 | // case #8. narrow Klass's field reference. |
2455 | // LoadNKlass |
2456 | // | |
2457 | // DecodeN |
2458 | // | | |
2459 | // AddP ( base == address ) |
2460 | // |
2461 | // case #9. Mixed unsafe access |
2462 | // {instance} |
2463 | // | |
2464 | // CheckCastPP (raw) |
2465 | // top | |
2466 | // \ | |
2467 | // AddP ( base == top ) |
2468 | // |
2469 | Node *base = addp->in(AddPNode::Base); |
2470 | if (base->uncast()->is_top()) { // The AddP case #3 and #6 and #9. |
2471 | base = addp->in(AddPNode::Address); |
2472 | while (base->is_AddP()) { |
2473 | // Case #6 (unsafe access) may have several chained AddP nodes. |
2474 | assert(base->in(AddPNode::Base)->uncast()->is_top(), "expected unsafe access address only")do { if (!(base->in(AddPNode::Base)->uncast()->is_top ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2474, "assert(" "base->in(AddPNode::Base)->uncast()->is_top()" ") failed", "expected unsafe access address only"); ::breakpoint (); } } while (0); |
2475 | base = base->in(AddPNode::Address); |
2476 | } |
2477 | if (base->Opcode() == Op_CheckCastPP && |
2478 | base->bottom_type()->isa_rawptr() && |
2479 | _igvn->type(base->in(1))->isa_oopptr()) { |
2480 | base = base->in(1); // Case #9 |
2481 | } else { |
2482 | Node* uncast_base = base->uncast(); |
2483 | int opcode = uncast_base->Opcode(); |
2484 | assert(opcode == Op_ConP || opcode == Op_ThreadLocal ||do { if (!(opcode == Op_ConP || opcode == Op_ThreadLocal || opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || (uncast_base ->is_Mem() && (uncast_base->bottom_type()->isa_rawptr () != __null)) || is_captured_store_address(addp))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2487, "assert(" "opcode == Op_ConP || opcode == Op_ThreadLocal || opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || (uncast_base->is_Mem() && (uncast_base->bottom_type()->isa_rawptr() != __null)) || is_captured_store_address(addp)" ") failed", "sanity"); ::breakpoint(); } } while (0) |
2485 | opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() ||do { if (!(opcode == Op_ConP || opcode == Op_ThreadLocal || opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || (uncast_base ->is_Mem() && (uncast_base->bottom_type()->isa_rawptr () != __null)) || is_captured_store_address(addp))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2487, "assert(" "opcode == Op_ConP || opcode == Op_ThreadLocal || opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || (uncast_base->is_Mem() && (uncast_base->bottom_type()->isa_rawptr() != __null)) || is_captured_store_address(addp)" ") failed", "sanity"); ::breakpoint(); } } while (0) |
2486 | (uncast_base->is_Mem() && (uncast_base->bottom_type()->isa_rawptr() != NULL)) ||do { if (!(opcode == Op_ConP || opcode == Op_ThreadLocal || opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || (uncast_base ->is_Mem() && (uncast_base->bottom_type()->isa_rawptr () != __null)) || is_captured_store_address(addp))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2487, "assert(" "opcode == Op_ConP || opcode == Op_ThreadLocal || opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || (uncast_base->is_Mem() && (uncast_base->bottom_type()->isa_rawptr() != __null)) || is_captured_store_address(addp)" ") failed", "sanity"); ::breakpoint(); } } while (0) |
2487 | is_captured_store_address(addp), "sanity")do { if (!(opcode == Op_ConP || opcode == Op_ThreadLocal || opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || (uncast_base ->is_Mem() && (uncast_base->bottom_type()->isa_rawptr () != __null)) || is_captured_store_address(addp))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2487, "assert(" "opcode == Op_ConP || opcode == Op_ThreadLocal || opcode == Op_CastX2P || uncast_base->is_DecodeNarrowPtr() || (uncast_base->is_Mem() && (uncast_base->bottom_type()->isa_rawptr() != __null)) || is_captured_store_address(addp)" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2488 | } |
2489 | } |
2490 | return base; |
2491 | } |
2492 | |
2493 | Node* ConnectionGraph::find_second_addp(Node* addp, Node* n) { |
2494 | assert(addp->is_AddP() && addp->outcnt() > 0, "Don't process dead nodes")do { if (!(addp->is_AddP() && addp->outcnt() > 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2494, "assert(" "addp->is_AddP() && addp->outcnt() > 0" ") failed", "Don't process dead nodes"); ::breakpoint(); } } while (0); |
2495 | Node* addp2 = addp->raw_out(0); |
2496 | if (addp->outcnt() == 1 && addp2->is_AddP() && |
2497 | addp2->in(AddPNode::Base) == n && |
2498 | addp2->in(AddPNode::Address) == addp) { |
2499 | assert(addp->in(AddPNode::Base) == n, "expecting the same base")do { if (!(addp->in(AddPNode::Base) == n)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2499, "assert(" "addp->in(AddPNode::Base) == n" ") failed" , "expecting the same base"); ::breakpoint(); } } while (0); |
2500 | // |
2501 | // Find array's offset to push it on worklist first and |
2502 | // as result process an array's element offset first (pushed second) |
2503 | // to avoid CastPP for the array's offset. |
2504 | // Otherwise the inserted CastPP (LocalVar) will point to what |
2505 | // the AddP (Field) points to. Which would be wrong since |
2506 | // the algorithm expects the CastPP has the same point as |
2507 | // as AddP's base CheckCastPP (LocalVar). |
2508 | // |
2509 | // ArrayAllocation |
2510 | // | |
2511 | // CheckCastPP |
2512 | // | |
2513 | // memProj (from ArrayAllocation CheckCastPP) |
2514 | // | || |
2515 | // | || Int (element index) |
2516 | // | || | ConI (log(element size)) |
2517 | // | || | / |
2518 | // | || LShift |
2519 | // | || / |
2520 | // | AddP (array's element offset) |
2521 | // | | |
2522 | // | | ConI (array's offset: #12(32-bits) or #24(64-bits)) |
2523 | // | / / |
2524 | // AddP (array's offset) |
2525 | // | |
2526 | // Load/Store (memory operation on array's element) |
2527 | // |
2528 | return addp2; |
2529 | } |
2530 | return NULL__null; |
2531 | } |
2532 | |
2533 | // |
2534 | // Adjust the type and inputs of an AddP which computes the |
2535 | // address of a field of an instance |
2536 | // |
2537 | bool ConnectionGraph::split_AddP(Node *addp, Node *base) { |
2538 | PhaseGVN* igvn = _igvn; |
2539 | const TypeOopPtr *base_t = igvn->type(base)->isa_oopptr(); |
2540 | assert(base_t != NULL && base_t->is_known_instance(), "expecting instance oopptr")do { if (!(base_t != __null && base_t->is_known_instance ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2540, "assert(" "base_t != __null && base_t->is_known_instance()" ") failed", "expecting instance oopptr"); ::breakpoint(); } } while (0); |
2541 | const TypeOopPtr *t = igvn->type(addp)->isa_oopptr(); |
2542 | if (t == NULL__null) { |
2543 | // We are computing a raw address for a store captured by an Initialize |
2544 | // compute an appropriate address type (cases #3 and #5). |
2545 | assert(igvn->type(addp) == TypeRawPtr::NOTNULL, "must be raw pointer")do { if (!(igvn->type(addp) == TypeRawPtr::NOTNULL)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2545, "assert(" "igvn->type(addp) == TypeRawPtr::NOTNULL" ") failed", "must be raw pointer"); ::breakpoint(); } } while (0); |
2546 | assert(addp->in(AddPNode::Address)->is_Proj(), "base of raw address must be result projection from allocation")do { if (!(addp->in(AddPNode::Address)->is_Proj())) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2546, "assert(" "addp->in(AddPNode::Address)->is_Proj()" ") failed", "base of raw address must be result projection from allocation" ); ::breakpoint(); } } while (0); |
2547 | intptr_t offs = (int)igvn->find_intptr_t_confind_long_con(addp->in(AddPNode::Offset), Type::OffsetBot); |
2548 | assert(offs != Type::OffsetBot, "offset must be a constant")do { if (!(offs != Type::OffsetBot)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2548, "assert(" "offs != Type::OffsetBot" ") failed", "offset must be a constant" ); ::breakpoint(); } } while (0); |
2549 | t = base_t->add_offset(offs)->is_oopptr(); |
2550 | } |
2551 | int inst_id = base_t->instance_id(); |
2552 | assert(!t->is_known_instance() || t->instance_id() == inst_id,do { if (!(!t->is_known_instance() || t->instance_id() == inst_id)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2553, "assert(" "!t->is_known_instance() || t->instance_id() == inst_id" ") failed", "old type must be non-instance or match new type" ); ::breakpoint(); } } while (0) |
2553 | "old type must be non-instance or match new type")do { if (!(!t->is_known_instance() || t->instance_id() == inst_id)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2553, "assert(" "!t->is_known_instance() || t->instance_id() == inst_id" ") failed", "old type must be non-instance or match new type" ); ::breakpoint(); } } while (0); |
2554 | |
2555 | // The type 't' could be subclass of 'base_t'. |
2556 | // As result t->offset() could be large then base_t's size and it will |
2557 | // cause the failure in add_offset() with narrow oops since TypeOopPtr() |
2558 | // constructor verifies correctness of the offset. |
2559 | // |
2560 | // It could happened on subclass's branch (from the type profiling |
2561 | // inlining) which was not eliminated during parsing since the exactness |
2562 | // of the allocation type was not propagated to the subclass type check. |
2563 | // |
2564 | // Or the type 't' could be not related to 'base_t' at all. |
2565 | // It could happened when CHA type is different from MDO type on a dead path |
2566 | // (for example, from instanceof check) which is not collapsed during parsing. |
2567 | // |
2568 | // Do nothing for such AddP node and don't process its users since |
2569 | // this code branch will go away. |
2570 | // |
2571 | if (!t->is_known_instance() && |
2572 | !base_t->klass()->is_subtype_of(t->klass())) { |
2573 | return false; // bail out |
2574 | } |
2575 | const TypeOopPtr *tinst = base_t->add_offset(t->offset())->is_oopptr(); |
2576 | // Do NOT remove the next line: ensure a new alias index is allocated |
2577 | // for the instance type. Note: C++ will not remove it since the call |
2578 | // has side effect. |
2579 | int alias_idx = _compile->get_alias_index(tinst); |
2580 | igvn->set_type(addp, tinst); |
2581 | // record the allocation in the node map |
2582 | set_map(addp, get_map(base->_idx)); |
2583 | // Set addp's Base and Address to 'base'. |
2584 | Node *abase = addp->in(AddPNode::Base); |
2585 | Node *adr = addp->in(AddPNode::Address); |
2586 | if (adr->is_Proj() && adr->in(0)->is_Allocate() && |
2587 | adr->in(0)->_idx == (uint)inst_id) { |
2588 | // Skip AddP cases #3 and #5. |
2589 | } else { |
2590 | assert(!abase->is_top(), "sanity")do { if (!(!abase->is_top())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2590, "assert(" "!abase->is_top()" ") failed", "sanity") ; ::breakpoint(); } } while (0); // AddP case #3 |
2591 | if (abase != base) { |
2592 | igvn->hash_delete(addp); |
2593 | addp->set_req(AddPNode::Base, base); |
2594 | if (abase == adr) { |
2595 | addp->set_req(AddPNode::Address, base); |
2596 | } else { |
2597 | // AddP case #4 (adr is array's element offset AddP node) |
2598 | #ifdef ASSERT1 |
2599 | const TypeOopPtr *atype = igvn->type(adr)->isa_oopptr(); |
2600 | assert(adr->is_AddP() && atype != NULL &&do { if (!(adr->is_AddP() && atype != __null && atype->instance_id() == inst_id)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2601, "assert(" "adr->is_AddP() && atype != __null && atype->instance_id() == inst_id" ") failed", "array's element offset should be processed first" ); ::breakpoint(); } } while (0) |
2601 | atype->instance_id() == inst_id, "array's element offset should be processed first")do { if (!(adr->is_AddP() && atype != __null && atype->instance_id() == inst_id)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2601, "assert(" "adr->is_AddP() && atype != __null && atype->instance_id() == inst_id" ") failed", "array's element offset should be processed first" ); ::breakpoint(); } } while (0); |
2602 | #endif |
2603 | } |
2604 | igvn->hash_insert(addp); |
2605 | } |
2606 | } |
2607 | // Put on IGVN worklist since at least addp's type was changed above. |
2608 | record_for_optimizer(addp); |
2609 | return true; |
2610 | } |
2611 | |
2612 | // |
2613 | // Create a new version of orig_phi if necessary. Returns either the newly |
2614 | // created phi or an existing phi. Sets create_new to indicate whether a new |
2615 | // phi was created. Cache the last newly created phi in the node map. |
2616 | // |
2617 | PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, bool &new_created) { |
2618 | Compile *C = _compile; |
2619 | PhaseGVN* igvn = _igvn; |
2620 | new_created = false; |
2621 | int phi_alias_idx = C->get_alias_index(orig_phi->adr_type()); |
2622 | // nothing to do if orig_phi is bottom memory or matches alias_idx |
2623 | if (phi_alias_idx == alias_idx) { |
2624 | return orig_phi; |
2625 | } |
2626 | // Have we recently created a Phi for this alias index? |
2627 | PhiNode *result = get_map_phi(orig_phi->_idx); |
2628 | if (result != NULL__null && C->get_alias_index(result->adr_type()) == alias_idx) { |
2629 | return result; |
2630 | } |
2631 | // Previous check may fail when the same wide memory Phi was split into Phis |
2632 | // for different memory slices. Search all Phis for this region. |
2633 | if (result != NULL__null) { |
2634 | Node* region = orig_phi->in(0); |
2635 | for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) { |
2636 | Node* phi = region->fast_out(i); |
2637 | if (phi->is_Phi() && |
2638 | C->get_alias_index(phi->as_Phi()->adr_type()) == alias_idx) { |
2639 | assert(phi->_idx >= nodes_size(), "only new Phi per instance memory slice")do { if (!(phi->_idx >= nodes_size())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2639, "assert(" "phi->_idx >= nodes_size()" ") failed" , "only new Phi per instance memory slice"); ::breakpoint(); } } while (0); |
2640 | return phi->as_Phi(); |
2641 | } |
2642 | } |
2643 | } |
2644 | if (C->live_nodes() + 2*NodeLimitFudgeFactor > C->max_node_limit()) { |
2645 | if (C->do_escape_analysis() == true && !C->failing()) { |
2646 | // Retry compilation without escape analysis. |
2647 | // If this is the first failure, the sentinel string will "stick" |
2648 | // to the Compile object, and the C2Compiler will see it and retry. |
2649 | C->record_failure(_invocation > 0 ? C2Compiler::retry_no_iterative_escape_analysis() : C2Compiler::retry_no_escape_analysis()); |
2650 | } |
2651 | return NULL__null; |
2652 | } |
2653 | orig_phi_worklist.append_if_missing(orig_phi); |
2654 | const TypePtr *atype = C->get_adr_type(alias_idx); |
2655 | result = PhiNode::make(orig_phi->in(0), NULL__null, Type::MEMORY, atype); |
2656 | C->copy_node_notes_to(result, orig_phi); |
2657 | igvn->set_type(result, result->bottom_type()); |
2658 | record_for_optimizer(result); |
2659 | set_map(orig_phi, result); |
2660 | new_created = true; |
2661 | return result; |
2662 | } |
2663 | |
2664 | // |
2665 | // Return a new version of Memory Phi "orig_phi" with the inputs having the |
2666 | // specified alias index. |
2667 | // |
2668 | PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist) { |
2669 | assert(alias_idx != Compile::AliasIdxBot, "can't split out bottom memory")do { if (!(alias_idx != Compile::AliasIdxBot)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2669, "assert(" "alias_idx != Compile::AliasIdxBot" ") failed" , "can't split out bottom memory"); ::breakpoint(); } } while (0); |
2670 | Compile *C = _compile; |
2671 | PhaseGVN* igvn = _igvn; |
2672 | bool new_phi_created; |
2673 | PhiNode *result = create_split_phi(orig_phi, alias_idx, orig_phi_worklist, new_phi_created); |
2674 | if (!new_phi_created) { |
2675 | return result; |
2676 | } |
2677 | GrowableArray<PhiNode *> phi_list; |
2678 | GrowableArray<uint> cur_input; |
2679 | PhiNode *phi = orig_phi; |
2680 | uint idx = 1; |
2681 | bool finished = false; |
2682 | while(!finished) { |
2683 | while (idx < phi->req()) { |
2684 | Node *mem = find_inst_mem(phi->in(idx), alias_idx, orig_phi_worklist); |
2685 | if (mem != NULL__null && mem->is_Phi()) { |
2686 | PhiNode *newphi = create_split_phi(mem->as_Phi(), alias_idx, orig_phi_worklist, new_phi_created); |
2687 | if (new_phi_created) { |
2688 | // found an phi for which we created a new split, push current one on worklist and begin |
2689 | // processing new one |
2690 | phi_list.push(phi); |
2691 | cur_input.push(idx); |
2692 | phi = mem->as_Phi(); |
2693 | result = newphi; |
2694 | idx = 1; |
2695 | continue; |
2696 | } else { |
2697 | mem = newphi; |
2698 | } |
2699 | } |
2700 | if (C->failing()) { |
2701 | return NULL__null; |
2702 | } |
2703 | result->set_req(idx++, mem); |
2704 | } |
2705 | #ifdef ASSERT1 |
2706 | // verify that the new Phi has an input for each input of the original |
2707 | assert( phi->req() == result->req(), "must have same number of inputs.")do { if (!(phi->req() == result->req())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2707, "assert(" "phi->req() == result->req()" ") failed" , "must have same number of inputs."); ::breakpoint(); } } while (0); |
2708 | assert( result->in(0) != NULL && result->in(0) == phi->in(0), "regions must match")do { if (!(result->in(0) != __null && result->in (0) == phi->in(0))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2708, "assert(" "result->in(0) != __null && result->in(0) == phi->in(0)" ") failed", "regions must match"); ::breakpoint(); } } while (0); |
2709 | #endif |
2710 | // Check if all new phi's inputs have specified alias index. |
2711 | // Otherwise use old phi. |
2712 | for (uint i = 1; i < phi->req(); i++) { |
2713 | Node* in = result->in(i); |
2714 | assert((phi->in(i) == NULL) == (in == NULL), "inputs must correspond.")do { if (!((phi->in(i) == __null) == (in == __null))) { (* g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2714, "assert(" "(phi->in(i) == __null) == (in == __null)" ") failed", "inputs must correspond."); ::breakpoint(); } } while (0); |
2715 | } |
2716 | // we have finished processing a Phi, see if there are any more to do |
2717 | finished = (phi_list.length() == 0 ); |
2718 | if (!finished) { |
2719 | phi = phi_list.pop(); |
2720 | idx = cur_input.pop(); |
2721 | PhiNode *prev_result = get_map_phi(phi->_idx); |
2722 | prev_result->set_req(idx++, result); |
2723 | result = prev_result; |
2724 | } |
2725 | } |
2726 | return result; |
2727 | } |
2728 | |
2729 | // |
2730 | // The next methods are derived from methods in MemNode. |
2731 | // |
2732 | Node* ConnectionGraph::step_through_mergemem(MergeMemNode *mmem, int alias_idx, const TypeOopPtr *toop) { |
2733 | Node *mem = mmem; |
2734 | // TypeOopPtr::NOTNULL+any is an OOP with unknown offset - generally |
2735 | // means an array I have not precisely typed yet. Do not do any |
2736 | // alias stuff with it any time soon. |
2737 | if (toop->base() != Type::AnyPtr && |
2738 | !(toop->klass() != NULL__null && |
2739 | toop->klass()->is_java_lang_Object() && |
2740 | toop->offset() == Type::OffsetBot)) { |
2741 | mem = mmem->memory_at(alias_idx); |
2742 | // Update input if it is progress over what we have now |
2743 | } |
2744 | return mem; |
2745 | } |
2746 | |
2747 | // |
2748 | // Move memory users to their memory slices. |
2749 | // |
2750 | void ConnectionGraph::move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis) { |
2751 | Compile* C = _compile; |
2752 | PhaseGVN* igvn = _igvn; |
2753 | const TypePtr* tp = igvn->type(n->in(MemNode::Address))->isa_ptr(); |
2754 | assert(tp != NULL, "ptr type")do { if (!(tp != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2754, "assert(" "tp != __null" ") failed", "ptr type"); ::breakpoint (); } } while (0); |
2755 | int alias_idx = C->get_alias_index(tp); |
2756 | int general_idx = C->get_general_index(alias_idx); |
2757 | |
2758 | // Move users first |
2759 | for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
2760 | Node* use = n->fast_out(i); |
2761 | if (use->is_MergeMem()) { |
2762 | MergeMemNode* mmem = use->as_MergeMem(); |
2763 | assert(n == mmem->memory_at(alias_idx), "should be on instance memory slice")do { if (!(n == mmem->memory_at(alias_idx))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2763, "assert(" "n == mmem->memory_at(alias_idx)" ") failed" , "should be on instance memory slice"); ::breakpoint(); } } while (0); |
2764 | if (n != mmem->memory_at(general_idx) || alias_idx == general_idx) { |
2765 | continue; // Nothing to do |
2766 | } |
2767 | // Replace previous general reference to mem node. |
2768 | uint orig_uniq = C->unique(); |
2769 | Node* m = find_inst_mem(n, general_idx, orig_phis); |
2770 | assert(orig_uniq == C->unique(), "no new nodes")do { if (!(orig_uniq == C->unique())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2770, "assert(" "orig_uniq == C->unique()" ") failed", "no new nodes" ); ::breakpoint(); } } while (0); |
2771 | mmem->set_memory_at(general_idx, m); |
2772 | --imax; |
2773 | --i; |
2774 | } else if (use->is_MemBar()) { |
2775 | assert(!use->is_Initialize(), "initializing stores should not be moved")do { if (!(!use->is_Initialize())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2775, "assert(" "!use->is_Initialize()" ") failed", "initializing stores should not be moved" ); ::breakpoint(); } } while (0); |
2776 | if (use->req() > MemBarNode::Precedent && |
2777 | use->in(MemBarNode::Precedent) == n) { |
2778 | // Don't move related membars. |
2779 | record_for_optimizer(use); |
2780 | continue; |
2781 | } |
2782 | tp = use->as_MemBar()->adr_type()->isa_ptr(); |
2783 | if ((tp != NULL__null && C->get_alias_index(tp) == alias_idx) || |
2784 | alias_idx == general_idx) { |
2785 | continue; // Nothing to do |
2786 | } |
2787 | // Move to general memory slice. |
2788 | uint orig_uniq = C->unique(); |
2789 | Node* m = find_inst_mem(n, general_idx, orig_phis); |
2790 | assert(orig_uniq == C->unique(), "no new nodes")do { if (!(orig_uniq == C->unique())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2790, "assert(" "orig_uniq == C->unique()" ") failed", "no new nodes" ); ::breakpoint(); } } while (0); |
2791 | igvn->hash_delete(use); |
2792 | imax -= use->replace_edge(n, m, igvn); |
2793 | igvn->hash_insert(use); |
2794 | record_for_optimizer(use); |
2795 | --i; |
2796 | #ifdef ASSERT1 |
2797 | } else if (use->is_Mem()) { |
2798 | if (use->Opcode() == Op_StoreCM && use->in(MemNode::OopStore) == n) { |
2799 | // Don't move related cardmark. |
2800 | continue; |
2801 | } |
2802 | // Memory nodes should have new memory input. |
2803 | tp = igvn->type(use->in(MemNode::Address))->isa_ptr(); |
2804 | assert(tp != NULL, "ptr type")do { if (!(tp != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2804, "assert(" "tp != __null" ") failed", "ptr type"); ::breakpoint (); } } while (0); |
2805 | int idx = C->get_alias_index(tp); |
2806 | assert(get_map(use->_idx) != NULL || idx == alias_idx,do { if (!(get_map(use->_idx) != __null || idx == alias_idx )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2807, "assert(" "get_map(use->_idx) != __null || idx == alias_idx" ") failed", "Following memory nodes should have new memory input or be on the same memory slice" ); ::breakpoint(); } } while (0) |
2807 | "Following memory nodes should have new memory input or be on the same memory slice")do { if (!(get_map(use->_idx) != __null || idx == alias_idx )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2807, "assert(" "get_map(use->_idx) != __null || idx == alias_idx" ") failed", "Following memory nodes should have new memory input or be on the same memory slice" ); ::breakpoint(); } } while (0); |
2808 | } else if (use->is_Phi()) { |
2809 | // Phi nodes should be split and moved already. |
2810 | tp = use->as_Phi()->adr_type()->isa_ptr(); |
2811 | assert(tp != NULL, "ptr type")do { if (!(tp != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2811, "assert(" "tp != __null" ") failed", "ptr type"); ::breakpoint (); } } while (0); |
2812 | int idx = C->get_alias_index(tp); |
2813 | assert(idx == alias_idx, "Following Phi nodes should be on the same memory slice")do { if (!(idx == alias_idx)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2813, "assert(" "idx == alias_idx" ") failed", "Following Phi nodes should be on the same memory slice" ); ::breakpoint(); } } while (0); |
2814 | } else { |
2815 | use->dump(); |
2816 | assert(false, "should not be here")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2816, "assert(" "false" ") failed", "should not be here"); :: breakpoint(); } } while (0); |
2817 | #endif |
2818 | } |
2819 | } |
2820 | } |
2821 | |
2822 | // |
2823 | // Search memory chain of "mem" to find a MemNode whose address |
2824 | // is the specified alias index. |
2825 | // |
2826 | Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArray<PhiNode *> &orig_phis) { |
2827 | if (orig_mem == NULL__null) { |
2828 | return orig_mem; |
2829 | } |
2830 | Compile* C = _compile; |
2831 | PhaseGVN* igvn = _igvn; |
2832 | const TypeOopPtr *toop = C->get_adr_type(alias_idx)->isa_oopptr(); |
2833 | bool is_instance = (toop != NULL__null) && toop->is_known_instance(); |
2834 | Node *start_mem = C->start()->proj_out_or_null(TypeFunc::Memory); |
2835 | Node *prev = NULL__null; |
2836 | Node *result = orig_mem; |
2837 | while (prev != result) { |
2838 | prev = result; |
2839 | if (result == start_mem) { |
2840 | break; // hit one of our sentinels |
2841 | } |
2842 | if (result->is_Mem()) { |
2843 | const Type *at = igvn->type(result->in(MemNode::Address)); |
2844 | if (at == Type::TOP) { |
2845 | break; // Dead |
2846 | } |
2847 | assert (at->isa_ptr() != NULL, "pointer type required.")do { if (!(at->isa_ptr() != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2847, "assert(" "at->isa_ptr() != __null" ") failed", "pointer type required." ); ::breakpoint(); } } while (0); |
2848 | int idx = C->get_alias_index(at->is_ptr()); |
2849 | if (idx == alias_idx) { |
2850 | break; // Found |
2851 | } |
2852 | if (!is_instance && (at->isa_oopptr() == NULL__null || |
2853 | !at->is_oopptr()->is_known_instance())) { |
2854 | break; // Do not skip store to general memory slice. |
2855 | } |
2856 | result = result->in(MemNode::Memory); |
2857 | } |
2858 | if (!is_instance) { |
2859 | continue; // don't search further for non-instance types |
2860 | } |
2861 | // skip over a call which does not affect this memory slice |
2862 | if (result->is_Proj() && result->as_Proj()->_con == TypeFunc::Memory) { |
2863 | Node *proj_in = result->in(0); |
2864 | if (proj_in->is_Allocate() && proj_in->_idx == (uint)toop->instance_id()) { |
2865 | break; // hit one of our sentinels |
2866 | } else if (proj_in->is_Call()) { |
2867 | // ArrayCopy node processed here as well |
2868 | CallNode *call = proj_in->as_Call(); |
2869 | if (!call->may_modify(toop, igvn)) { |
2870 | result = call->in(TypeFunc::Memory); |
2871 | } |
2872 | } else if (proj_in->is_Initialize()) { |
2873 | AllocateNode* alloc = proj_in->as_Initialize()->allocation(); |
2874 | // Stop if this is the initialization for the object instance which |
2875 | // which contains this memory slice, otherwise skip over it. |
2876 | if (alloc == NULL__null || alloc->_idx != (uint)toop->instance_id()) { |
2877 | result = proj_in->in(TypeFunc::Memory); |
2878 | } |
2879 | } else if (proj_in->is_MemBar()) { |
2880 | // Check if there is an array copy for a clone |
2881 | // Step over GC barrier when ReduceInitialCardMarks is disabled |
2882 | BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); |
2883 | Node* control_proj_ac = bs->step_over_gc_barrier(proj_in->in(0)); |
2884 | |
2885 | if (control_proj_ac->is_Proj() && control_proj_ac->in(0)->is_ArrayCopy()) { |
2886 | // Stop if it is a clone |
2887 | ArrayCopyNode* ac = control_proj_ac->in(0)->as_ArrayCopy(); |
2888 | if (ac->may_modify(toop, igvn)) { |
2889 | break; |
2890 | } |
2891 | } |
2892 | result = proj_in->in(TypeFunc::Memory); |
2893 | } |
2894 | } else if (result->is_MergeMem()) { |
2895 | MergeMemNode *mmem = result->as_MergeMem(); |
2896 | result = step_through_mergemem(mmem, alias_idx, toop); |
2897 | if (result == mmem->base_memory()) { |
2898 | // Didn't find instance memory, search through general slice recursively. |
2899 | result = mmem->memory_at(C->get_general_index(alias_idx)); |
2900 | result = find_inst_mem(result, alias_idx, orig_phis); |
2901 | if (C->failing()) { |
2902 | return NULL__null; |
2903 | } |
2904 | mmem->set_memory_at(alias_idx, result); |
2905 | } |
2906 | } else if (result->is_Phi() && |
2907 | C->get_alias_index(result->as_Phi()->adr_type()) != alias_idx) { |
2908 | Node *un = result->as_Phi()->unique_input(igvn); |
2909 | if (un != NULL__null) { |
2910 | orig_phis.append_if_missing(result->as_Phi()); |
2911 | result = un; |
2912 | } else { |
2913 | break; |
2914 | } |
2915 | } else if (result->is_ClearArray()) { |
2916 | if (!ClearArrayNode::step_through(&result, (uint)toop->instance_id(), igvn)) { |
2917 | // Can not bypass initialization of the instance |
2918 | // we are looking for. |
2919 | break; |
2920 | } |
2921 | // Otherwise skip it (the call updated 'result' value). |
2922 | } else if (result->Opcode() == Op_SCMemProj) { |
2923 | Node* mem = result->in(0); |
2924 | Node* adr = NULL__null; |
2925 | if (mem->is_LoadStore()) { |
2926 | adr = mem->in(MemNode::Address); |
2927 | } else { |
2928 | assert(mem->Opcode() == Op_EncodeISOArray ||do { if (!(mem->Opcode() == Op_EncodeISOArray || mem->Opcode () == Op_StrCompressedCopy)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2929, "assert(" "mem->Opcode() == Op_EncodeISOArray || mem->Opcode() == Op_StrCompressedCopy" ") failed", "sanity"); ::breakpoint(); } } while (0) |
2929 | mem->Opcode() == Op_StrCompressedCopy, "sanity")do { if (!(mem->Opcode() == Op_EncodeISOArray || mem->Opcode () == Op_StrCompressedCopy)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2929, "assert(" "mem->Opcode() == Op_EncodeISOArray || mem->Opcode() == Op_StrCompressedCopy" ") failed", "sanity"); ::breakpoint(); } } while (0); |
2930 | adr = mem->in(3); // Memory edge corresponds to destination array |
2931 | } |
2932 | const Type *at = igvn->type(adr); |
2933 | if (at != Type::TOP) { |
2934 | assert(at->isa_ptr() != NULL, "pointer type required.")do { if (!(at->isa_ptr() != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2934, "assert(" "at->isa_ptr() != __null" ") failed", "pointer type required." ); ::breakpoint(); } } while (0); |
2935 | int idx = C->get_alias_index(at->is_ptr()); |
2936 | if (idx == alias_idx) { |
2937 | // Assert in debug mode |
2938 | assert(false, "Object is not scalar replaceable if a LoadStore node accesses its field")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2938, "assert(" "false" ") failed", "Object is not scalar replaceable if a LoadStore node accesses its field" ); ::breakpoint(); } } while (0); |
2939 | break; // In product mode return SCMemProj node |
2940 | } |
2941 | } |
2942 | result = mem->in(MemNode::Memory); |
2943 | } else if (result->Opcode() == Op_StrInflatedCopy) { |
2944 | Node* adr = result->in(3); // Memory edge corresponds to destination array |
2945 | const Type *at = igvn->type(adr); |
2946 | if (at != Type::TOP) { |
2947 | assert(at->isa_ptr() != NULL, "pointer type required.")do { if (!(at->isa_ptr() != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2947, "assert(" "at->isa_ptr() != __null" ") failed", "pointer type required." ); ::breakpoint(); } } while (0); |
2948 | int idx = C->get_alias_index(at->is_ptr()); |
2949 | if (idx == alias_idx) { |
2950 | // Assert in debug mode |
2951 | assert(false, "Object is not scalar replaceable if a StrInflatedCopy node accesses its field")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2951, "assert(" "false" ") failed", "Object is not scalar replaceable if a StrInflatedCopy node accesses its field" ); ::breakpoint(); } } while (0); |
2952 | break; // In product mode return SCMemProj node |
2953 | } |
2954 | } |
2955 | result = result->in(MemNode::Memory); |
2956 | } |
2957 | } |
2958 | if (result->is_Phi()) { |
2959 | PhiNode *mphi = result->as_Phi(); |
2960 | assert(mphi->bottom_type() == Type::MEMORY, "memory phi required")do { if (!(mphi->bottom_type() == Type::MEMORY)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 2960, "assert(" "mphi->bottom_type() == Type::MEMORY" ") failed" , "memory phi required"); ::breakpoint(); } } while (0); |
2961 | const TypePtr *t = mphi->adr_type(); |
2962 | if (!is_instance) { |
2963 | // Push all non-instance Phis on the orig_phis worklist to update inputs |
2964 | // during Phase 4 if needed. |
2965 | orig_phis.append_if_missing(mphi); |
2966 | } else if (C->get_alias_index(t) != alias_idx) { |
2967 | // Create a new Phi with the specified alias index type. |
2968 | result = split_memory_phi(mphi, alias_idx, orig_phis); |
2969 | } |
2970 | } |
2971 | // the result is either MemNode, PhiNode, InitializeNode. |
2972 | return result; |
2973 | } |
2974 | |
2975 | // |
2976 | // Convert the types of non-escaped object to instance types where possible, |
2977 | // propagate the new type information through the graph, and update memory |
2978 | // edges and MergeMem inputs to reflect the new type. |
2979 | // |
2980 | // We start with allocations (and calls which may be allocations) on alloc_worklist. |
2981 | // The processing is done in 4 phases: |
2982 | // |
2983 | // Phase 1: Process possible allocations from alloc_worklist. Create instance |
2984 | // types for the CheckCastPP for allocations where possible. |
2985 | // Propagate the new types through users as follows: |
2986 | // casts and Phi: push users on alloc_worklist |
2987 | // AddP: cast Base and Address inputs to the instance type |
2988 | // push any AddP users on alloc_worklist and push any memnode |
2989 | // users onto memnode_worklist. |
2990 | // Phase 2: Process MemNode's from memnode_worklist. compute new address type and |
2991 | // search the Memory chain for a store with the appropriate type |
2992 | // address type. If a Phi is found, create a new version with |
2993 | // the appropriate memory slices from each of the Phi inputs. |
2994 | // For stores, process the users as follows: |
2995 | // MemNode: push on memnode_worklist |
2996 | // MergeMem: push on mergemem_worklist |
2997 | // Phase 3: Process MergeMem nodes from mergemem_worklist. Walk each memory slice |
2998 | // moving the first node encountered of each instance type to the |
2999 | // the input corresponding to its alias index. |
3000 | // appropriate memory slice. |
3001 | // Phase 4: Update the inputs of non-instance memory Phis and the Memory input of memnodes. |
3002 | // |
3003 | // In the following example, the CheckCastPP nodes are the cast of allocation |
3004 | // results and the allocation of node 29 is non-escaped and eligible to be an |
3005 | // instance type. |
3006 | // |
3007 | // We start with: |
3008 | // |
3009 | // 7 Parm #memory |
3010 | // 10 ConI "12" |
3011 | // 19 CheckCastPP "Foo" |
3012 | // 20 AddP _ 19 19 10 Foo+12 alias_index=4 |
3013 | // 29 CheckCastPP "Foo" |
3014 | // 30 AddP _ 29 29 10 Foo+12 alias_index=4 |
3015 | // |
3016 | // 40 StoreP 25 7 20 ... alias_index=4 |
3017 | // 50 StoreP 35 40 30 ... alias_index=4 |
3018 | // 60 StoreP 45 50 20 ... alias_index=4 |
3019 | // 70 LoadP _ 60 30 ... alias_index=4 |
3020 | // 80 Phi 75 50 60 Memory alias_index=4 |
3021 | // 90 LoadP _ 80 30 ... alias_index=4 |
3022 | // 100 LoadP _ 80 20 ... alias_index=4 |
3023 | // |
3024 | // |
3025 | // Phase 1 creates an instance type for node 29 assigning it an instance id of 24 |
3026 | // and creating a new alias index for node 30. This gives: |
3027 | // |
3028 | // 7 Parm #memory |
3029 | // 10 ConI "12" |
3030 | // 19 CheckCastPP "Foo" |
3031 | // 20 AddP _ 19 19 10 Foo+12 alias_index=4 |
3032 | // 29 CheckCastPP "Foo" iid=24 |
3033 | // 30 AddP _ 29 29 10 Foo+12 alias_index=6 iid=24 |
3034 | // |
3035 | // 40 StoreP 25 7 20 ... alias_index=4 |
3036 | // 50 StoreP 35 40 30 ... alias_index=6 |
3037 | // 60 StoreP 45 50 20 ... alias_index=4 |
3038 | // 70 LoadP _ 60 30 ... alias_index=6 |
3039 | // 80 Phi 75 50 60 Memory alias_index=4 |
3040 | // 90 LoadP _ 80 30 ... alias_index=6 |
3041 | // 100 LoadP _ 80 20 ... alias_index=4 |
3042 | // |
3043 | // In phase 2, new memory inputs are computed for the loads and stores, |
3044 | // And a new version of the phi is created. In phase 4, the inputs to |
3045 | // node 80 are updated and then the memory nodes are updated with the |
3046 | // values computed in phase 2. This results in: |
3047 | // |
3048 | // 7 Parm #memory |
3049 | // 10 ConI "12" |
3050 | // 19 CheckCastPP "Foo" |
3051 | // 20 AddP _ 19 19 10 Foo+12 alias_index=4 |
3052 | // 29 CheckCastPP "Foo" iid=24 |
3053 | // 30 AddP _ 29 29 10 Foo+12 alias_index=6 iid=24 |
3054 | // |
3055 | // 40 StoreP 25 7 20 ... alias_index=4 |
3056 | // 50 StoreP 35 7 30 ... alias_index=6 |
3057 | // 60 StoreP 45 40 20 ... alias_index=4 |
3058 | // 70 LoadP _ 50 30 ... alias_index=6 |
3059 | // 80 Phi 75 40 60 Memory alias_index=4 |
3060 | // 120 Phi 75 50 50 Memory alias_index=6 |
3061 | // 90 LoadP _ 120 30 ... alias_index=6 |
3062 | // 100 LoadP _ 80 20 ... alias_index=4 |
3063 | // |
3064 | void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist, |
3065 | GrowableArray<ArrayCopyNode*> &arraycopy_worklist, |
3066 | GrowableArray<MergeMemNode*> &mergemem_worklist) { |
3067 | GrowableArray<Node *> memnode_worklist; |
3068 | GrowableArray<PhiNode *> orig_phis; |
3069 | PhaseIterGVN *igvn = _igvn; |
3070 | uint new_index_start = (uint) _compile->num_alias_types(); |
3071 | VectorSet visited; |
3072 | ideal_nodes.clear(); // Reset for use with set_map/get_map. |
3073 | uint unique_old = _compile->unique(); |
3074 | |
3075 | // Phase 1: Process possible allocations from alloc_worklist. |
3076 | // Create instance types for the CheckCastPP for allocations where possible. |
3077 | // |
3078 | // (Note: don't forget to change the order of the second AddP node on |
3079 | // the alloc_worklist if the order of the worklist processing is changed, |
3080 | // see the comment in find_second_addp().) |
3081 | // |
3082 | while (alloc_worklist.length() != 0) { |
3083 | Node *n = alloc_worklist.pop(); |
3084 | uint ni = n->_idx; |
3085 | if (n->is_Call()) { |
3086 | CallNode *alloc = n->as_Call(); |
3087 | // copy escape information to call node |
3088 | PointsToNode* ptn = ptnode_adr(alloc->_idx); |
3089 | PointsToNode::EscapeState es = ptn->escape_state(); |
3090 | // We have an allocation or call which returns a Java object, |
3091 | // see if it is non-escaped. |
3092 | if (es != PointsToNode::NoEscape || !ptn->scalar_replaceable()) { |
3093 | continue; |
3094 | } |
3095 | // Find CheckCastPP for the allocate or for the return value of a call |
3096 | n = alloc->result_cast(); |
3097 | if (n == NULL__null) { // No uses except Initialize node |
3098 | if (alloc->is_Allocate()) { |
3099 | // Set the scalar_replaceable flag for allocation |
3100 | // so it could be eliminated if it has no uses. |
3101 | alloc->as_Allocate()->_is_scalar_replaceable = true; |
3102 | } |
3103 | continue; |
3104 | } |
3105 | if (!n->is_CheckCastPP()) { // not unique CheckCastPP. |
3106 | // we could reach here for allocate case if one init is associated with many allocs. |
3107 | if (alloc->is_Allocate()) { |
3108 | alloc->as_Allocate()->_is_scalar_replaceable = false; |
3109 | } |
3110 | continue; |
3111 | } |
3112 | |
3113 | // The inline code for Object.clone() casts the allocation result to |
3114 | // java.lang.Object and then to the actual type of the allocated |
3115 | // object. Detect this case and use the second cast. |
3116 | // Also detect j.l.reflect.Array.newInstance(jobject, jint) case when |
3117 | // the allocation result is cast to java.lang.Object and then |
3118 | // to the actual Array type. |
3119 | if (alloc->is_Allocate() && n->as_Type()->type() == TypeInstPtr::NOTNULL |
3120 | && (alloc->is_AllocateArray() || |
3121 | igvn->type(alloc->in(AllocateNode::KlassNode)) != TypeInstKlassPtr::OBJECT)) { |
3122 | Node *cast2 = NULL__null; |
3123 | for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
3124 | Node *use = n->fast_out(i); |
3125 | if (use->is_CheckCastPP()) { |
3126 | cast2 = use; |
3127 | break; |
3128 | } |
3129 | } |
3130 | if (cast2 != NULL__null) { |
3131 | n = cast2; |
3132 | } else { |
3133 | // Non-scalar replaceable if the allocation type is unknown statically |
3134 | // (reflection allocation), the object can't be restored during |
3135 | // deoptimization without precise type. |
3136 | continue; |
3137 | } |
3138 | } |
3139 | |
3140 | const TypeOopPtr *t = igvn->type(n)->isa_oopptr(); |
3141 | if (t == NULL__null) { |
3142 | continue; // not a TypeOopPtr |
3143 | } |
3144 | if (!t->klass_is_exact()) { |
3145 | continue; // not an unique type |
3146 | } |
3147 | if (alloc->is_Allocate()) { |
3148 | // Set the scalar_replaceable flag for allocation |
3149 | // so it could be eliminated. |
3150 | alloc->as_Allocate()->_is_scalar_replaceable = true; |
3151 | } |
3152 | set_escape_state(ptnode_adr(n->_idx), es); // CheckCastPP escape state |
3153 | // in order for an object to be scalar-replaceable, it must be: |
3154 | // - a direct allocation (not a call returning an object) |
3155 | // - non-escaping |
3156 | // - eligible to be a unique type |
3157 | // - not determined to be ineligible by escape analysis |
3158 | set_map(alloc, n); |
3159 | set_map(n, alloc); |
3160 | const TypeOopPtr* tinst = t->cast_to_instance_id(ni); |
3161 | igvn->hash_delete(n); |
3162 | igvn->set_type(n, tinst); |
3163 | n->raise_bottom_type(tinst); |
3164 | igvn->hash_insert(n); |
3165 | record_for_optimizer(n); |
3166 | // Allocate an alias index for the header fields. Accesses to |
3167 | // the header emitted during macro expansion wouldn't have |
3168 | // correct memory state otherwise. |
3169 | _compile->get_alias_index(tinst->add_offset(oopDesc::mark_offset_in_bytes())); |
3170 | _compile->get_alias_index(tinst->add_offset(oopDesc::klass_offset_in_bytes())); |
3171 | if (alloc->is_Allocate() && (t->isa_instptr() || t->isa_aryptr())) { |
3172 | |
3173 | // First, put on the worklist all Field edges from Connection Graph |
3174 | // which is more accurate than putting immediate users from Ideal Graph. |
3175 | for (EdgeIterator e(ptn); e.has_next(); e.next()) { |
3176 | PointsToNode* tgt = e.get(); |
3177 | if (tgt->is_Arraycopy()) { |
3178 | continue; |
3179 | } |
3180 | Node* use = tgt->ideal_node(); |
3181 | assert(tgt->is_Field() && use->is_AddP(),do { if (!(tgt->is_Field() && use->is_AddP())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3182, "assert(" "tgt->is_Field() && use->is_AddP()" ") failed", "only AddP nodes are Field edges in CG"); ::breakpoint (); } } while (0) |
3182 | "only AddP nodes are Field edges in CG")do { if (!(tgt->is_Field() && use->is_AddP())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3182, "assert(" "tgt->is_Field() && use->is_AddP()" ") failed", "only AddP nodes are Field edges in CG"); ::breakpoint (); } } while (0); |
3183 | if (use->outcnt() > 0) { // Don't process dead nodes |
3184 | Node* addp2 = find_second_addp(use, use->in(AddPNode::Base)); |
3185 | if (addp2 != NULL__null) { |
3186 | assert(alloc->is_AllocateArray(),"array allocation was expected")do { if (!(alloc->is_AllocateArray())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3186, "assert(" "alloc->is_AllocateArray()" ") failed", "array allocation was expected" ); ::breakpoint(); } } while (0); |
3187 | alloc_worklist.append_if_missing(addp2); |
3188 | } |
3189 | alloc_worklist.append_if_missing(use); |
3190 | } |
3191 | } |
3192 | |
3193 | // An allocation may have an Initialize which has raw stores. Scan |
3194 | // the users of the raw allocation result and push AddP users |
3195 | // on alloc_worklist. |
3196 | Node *raw_result = alloc->proj_out_or_null(TypeFunc::Parms); |
3197 | assert (raw_result != NULL, "must have an allocation result")do { if (!(raw_result != __null)) { (*g_assert_poison) = 'X'; ; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3197, "assert(" "raw_result != __null" ") failed", "must have an allocation result" ); ::breakpoint(); } } while (0); |
3198 | for (DUIterator_Fast imax, i = raw_result->fast_outs(imax); i < imax; i++) { |
3199 | Node *use = raw_result->fast_out(i); |
3200 | if (use->is_AddP() && use->outcnt() > 0) { // Don't process dead nodes |
3201 | Node* addp2 = find_second_addp(use, raw_result); |
3202 | if (addp2 != NULL__null) { |
3203 | assert(alloc->is_AllocateArray(),"array allocation was expected")do { if (!(alloc->is_AllocateArray())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3203, "assert(" "alloc->is_AllocateArray()" ") failed", "array allocation was expected" ); ::breakpoint(); } } while (0); |
3204 | alloc_worklist.append_if_missing(addp2); |
3205 | } |
3206 | alloc_worklist.append_if_missing(use); |
3207 | } else if (use->is_MemBar()) { |
3208 | memnode_worklist.append_if_missing(use); |
3209 | } |
3210 | } |
3211 | } |
3212 | } else if (n->is_AddP()) { |
3213 | JavaObjectNode* jobj = unique_java_object(get_addp_base(n)); |
3214 | if (jobj == NULL__null || jobj == phantom_obj) { |
3215 | #ifdef ASSERT1 |
3216 | ptnode_adr(get_addp_base(n)->_idx)->dump(); |
3217 | ptnode_adr(n->_idx)->dump(); |
3218 | assert(jobj != NULL && jobj != phantom_obj, "escaped allocation")do { if (!(jobj != __null && jobj != phantom_obj)) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3218, "assert(" "jobj != __null && jobj != phantom_obj" ") failed", "escaped allocation"); ::breakpoint(); } } while (0); |
3219 | #endif |
3220 | _compile->record_failure(_invocation > 0 ? C2Compiler::retry_no_iterative_escape_analysis() : C2Compiler::retry_no_escape_analysis()); |
3221 | return; |
3222 | } |
3223 | Node *base = get_map(jobj->idx()); // CheckCastPP node |
3224 | if (!split_AddP(n, base)) continue; // wrong type from dead path |
3225 | } else if (n->is_Phi() || |
3226 | n->is_CheckCastPP() || |
3227 | n->is_EncodeP() || |
3228 | n->is_DecodeN() || |
3229 | (n->is_ConstraintCast() && n->Opcode() == Op_CastPP)) { |
3230 | if (visited.test_set(n->_idx)) { |
3231 | assert(n->is_Phi(), "loops only through Phi's")do { if (!(n->is_Phi())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3231, "assert(" "n->is_Phi()" ") failed", "loops only through Phi's" ); ::breakpoint(); } } while (0); |
3232 | continue; // already processed |
3233 | } |
3234 | JavaObjectNode* jobj = unique_java_object(n); |
3235 | if (jobj == NULL__null || jobj == phantom_obj) { |
3236 | #ifdef ASSERT1 |
3237 | ptnode_adr(n->_idx)->dump(); |
3238 | assert(jobj != NULL && jobj != phantom_obj, "escaped allocation")do { if (!(jobj != __null && jobj != phantom_obj)) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3238, "assert(" "jobj != __null && jobj != phantom_obj" ") failed", "escaped allocation"); ::breakpoint(); } } while (0); |
3239 | #endif |
3240 | _compile->record_failure(_invocation > 0 ? C2Compiler::retry_no_iterative_escape_analysis() : C2Compiler::retry_no_escape_analysis()); |
3241 | return; |
3242 | } else { |
3243 | Node *val = get_map(jobj->idx()); // CheckCastPP node |
3244 | TypeNode *tn = n->as_Type(); |
3245 | const TypeOopPtr* tinst = igvn->type(val)->isa_oopptr(); |
3246 | assert(tinst != NULL && tinst->is_known_instance() &&do { if (!(tinst != __null && tinst->is_known_instance () && tinst->instance_id() == jobj->idx())) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3247, "assert(" "tinst != __null && tinst->is_known_instance() && tinst->instance_id() == jobj->idx()" ") failed", "instance type expected."); ::breakpoint(); } } while (0) |
3247 | tinst->instance_id() == jobj->idx() , "instance type expected.")do { if (!(tinst != __null && tinst->is_known_instance () && tinst->instance_id() == jobj->idx())) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3247, "assert(" "tinst != __null && tinst->is_known_instance() && tinst->instance_id() == jobj->idx()" ") failed", "instance type expected."); ::breakpoint(); } } while (0); |
3248 | |
3249 | const Type *tn_type = igvn->type(tn); |
3250 | const TypeOopPtr *tn_t; |
3251 | if (tn_type->isa_narrowoop()) { |
3252 | tn_t = tn_type->make_ptr()->isa_oopptr(); |
3253 | } else { |
3254 | tn_t = tn_type->isa_oopptr(); |
3255 | } |
3256 | if (tn_t != NULL__null && tinst->klass()->is_subtype_of(tn_t->klass())) { |
3257 | if (tn_type->isa_narrowoop()) { |
3258 | tn_type = tinst->make_narrowoop(); |
3259 | } else { |
3260 | tn_type = tinst; |
3261 | } |
3262 | igvn->hash_delete(tn); |
3263 | igvn->set_type(tn, tn_type); |
3264 | tn->set_type(tn_type); |
3265 | igvn->hash_insert(tn); |
3266 | record_for_optimizer(n); |
3267 | } else { |
3268 | assert(tn_type == TypePtr::NULL_PTR ||do { if (!(tn_type == TypePtr::NULL_PTR || tn_t != __null && !tinst->klass()->is_subtype_of(tn_t->klass()))) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3270, "assert(" "tn_type == TypePtr::NULL_PTR || tn_t != __null && !tinst->klass()->is_subtype_of(tn_t->klass())" ") failed", "unexpected type"); ::breakpoint(); } } while (0 ) |
3269 | tn_t != NULL && !tinst->klass()->is_subtype_of(tn_t->klass()),do { if (!(tn_type == TypePtr::NULL_PTR || tn_t != __null && !tinst->klass()->is_subtype_of(tn_t->klass()))) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3270, "assert(" "tn_type == TypePtr::NULL_PTR || tn_t != __null && !tinst->klass()->is_subtype_of(tn_t->klass())" ") failed", "unexpected type"); ::breakpoint(); } } while (0 ) |
3270 | "unexpected type")do { if (!(tn_type == TypePtr::NULL_PTR || tn_t != __null && !tinst->klass()->is_subtype_of(tn_t->klass()))) { ( *g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3270, "assert(" "tn_type == TypePtr::NULL_PTR || tn_t != __null && !tinst->klass()->is_subtype_of(tn_t->klass())" ") failed", "unexpected type"); ::breakpoint(); } } while (0 ); |
3271 | continue; // Skip dead path with different type |
3272 | } |
3273 | } |
3274 | } else { |
3275 | debug_only(n->dump();)n->dump(); |
3276 | assert(false, "EA: unexpected node")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3276, "assert(" "false" ") failed", "EA: unexpected node"); ::breakpoint(); } } while (0); |
3277 | continue; |
3278 | } |
3279 | // push allocation's users on appropriate worklist |
3280 | for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
3281 | Node *use = n->fast_out(i); |
3282 | if(use->is_Mem() && use->in(MemNode::Address) == n) { |
3283 | // Load/store to instance's field |
3284 | memnode_worklist.append_if_missing(use); |
3285 | } else if (use->is_MemBar()) { |
3286 | if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge |
3287 | memnode_worklist.append_if_missing(use); |
3288 | } |
3289 | } else if (use->is_AddP() && use->outcnt() > 0) { // No dead nodes |
3290 | Node* addp2 = find_second_addp(use, n); |
3291 | if (addp2 != NULL__null) { |
3292 | alloc_worklist.append_if_missing(addp2); |
3293 | } |
3294 | alloc_worklist.append_if_missing(use); |
3295 | } else if (use->is_Phi() || |
3296 | use->is_CheckCastPP() || |
3297 | use->is_EncodeNarrowPtr() || |
3298 | use->is_DecodeNarrowPtr() || |
3299 | (use->is_ConstraintCast() && use->Opcode() == Op_CastPP)) { |
3300 | alloc_worklist.append_if_missing(use); |
3301 | #ifdef ASSERT1 |
3302 | } else if (use->is_Mem()) { |
3303 | assert(use->in(MemNode::Address) != n, "EA: missing allocation reference path")do { if (!(use->in(MemNode::Address) != n)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3303, "assert(" "use->in(MemNode::Address) != n" ") failed" , "EA: missing allocation reference path"); ::breakpoint(); } } while (0); |
3304 | } else if (use->is_MergeMem()) { |
3305 | assert(mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist")do { if (!(mergemem_worklist.contains(use->as_MergeMem())) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3305, "assert(" "mergemem_worklist.contains(use->as_MergeMem())" ") failed", "EA: missing MergeMem node in the worklist"); :: breakpoint(); } } while (0); |
3306 | } else if (use->is_SafePoint()) { |
3307 | // Look for MergeMem nodes for calls which reference unique allocation |
3308 | // (through CheckCastPP nodes) even for debug info. |
3309 | Node* m = use->in(TypeFunc::Memory); |
3310 | if (m->is_MergeMem()) { |
3311 | assert(mergemem_worklist.contains(m->as_MergeMem()), "EA: missing MergeMem node in the worklist")do { if (!(mergemem_worklist.contains(m->as_MergeMem()))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3311, "assert(" "mergemem_worklist.contains(m->as_MergeMem())" ") failed", "EA: missing MergeMem node in the worklist"); :: breakpoint(); } } while (0); |
3312 | } |
3313 | } else if (use->Opcode() == Op_EncodeISOArray) { |
3314 | if (use->in(MemNode::Memory) == n || use->in(3) == n) { |
3315 | // EncodeISOArray overwrites destination array |
3316 | memnode_worklist.append_if_missing(use); |
3317 | } |
3318 | } else { |
3319 | uint op = use->Opcode(); |
3320 | if ((op == Op_StrCompressedCopy || op == Op_StrInflatedCopy) && |
3321 | (use->in(MemNode::Memory) == n)) { |
3322 | // They overwrite memory edge corresponding to destination array, |
3323 | memnode_worklist.append_if_missing(use); |
3324 | } else if (!(op == Op_CmpP || op == Op_Conv2B || |
3325 | op == Op_CastP2X || op == Op_StoreCM || |
3326 | op == Op_FastLock || op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives || |
3327 | op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || |
3328 | op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar || |
3329 | op == Op_SubTypeCheck || |
3330 | BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use))) { |
3331 | n->dump(); |
3332 | use->dump(); |
3333 | assert(false, "EA: missing allocation reference path")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3333, "assert(" "false" ") failed", "EA: missing allocation reference path" ); ::breakpoint(); } } while (0); |
3334 | } |
3335 | #endif |
3336 | } |
3337 | } |
3338 | |
3339 | } |
3340 | |
3341 | // Go over all ArrayCopy nodes and if one of the inputs has a unique |
3342 | // type, record it in the ArrayCopy node so we know what memory this |
3343 | // node uses/modified. |
3344 | for (int next = 0; next < arraycopy_worklist.length(); next++) { |
3345 | ArrayCopyNode* ac = arraycopy_worklist.at(next); |
3346 | Node* dest = ac->in(ArrayCopyNode::Dest); |
3347 | if (dest->is_AddP()) { |
3348 | dest = get_addp_base(dest); |
3349 | } |
3350 | JavaObjectNode* jobj = unique_java_object(dest); |
3351 | if (jobj != NULL__null) { |
3352 | Node *base = get_map(jobj->idx()); |
3353 | if (base != NULL__null) { |
3354 | const TypeOopPtr *base_t = _igvn->type(base)->isa_oopptr(); |
3355 | ac->_dest_type = base_t; |
3356 | } |
3357 | } |
3358 | Node* src = ac->in(ArrayCopyNode::Src); |
3359 | if (src->is_AddP()) { |
3360 | src = get_addp_base(src); |
3361 | } |
3362 | jobj = unique_java_object(src); |
3363 | if (jobj != NULL__null) { |
3364 | Node* base = get_map(jobj->idx()); |
3365 | if (base != NULL__null) { |
3366 | const TypeOopPtr *base_t = _igvn->type(base)->isa_oopptr(); |
3367 | ac->_src_type = base_t; |
3368 | } |
3369 | } |
3370 | } |
3371 | |
3372 | // New alias types were created in split_AddP(). |
3373 | uint new_index_end = (uint) _compile->num_alias_types(); |
3374 | assert(unique_old == _compile->unique(), "there should be no new ideal nodes after Phase 1")do { if (!(unique_old == _compile->unique())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3374, "assert(" "unique_old == _compile->unique()" ") failed" , "there should be no new ideal nodes after Phase 1"); ::breakpoint (); } } while (0); |
3375 | |
3376 | // Phase 2: Process MemNode's from memnode_worklist. compute new address type and |
3377 | // compute new values for Memory inputs (the Memory inputs are not |
3378 | // actually updated until phase 4.) |
3379 | if (memnode_worklist.length() == 0) |
3380 | return; // nothing to do |
3381 | while (memnode_worklist.length() != 0) { |
3382 | Node *n = memnode_worklist.pop(); |
3383 | if (visited.test_set(n->_idx)) { |
3384 | continue; |
3385 | } |
3386 | if (n->is_Phi() || n->is_ClearArray()) { |
3387 | // we don't need to do anything, but the users must be pushed |
3388 | } else if (n->is_MemBar()) { // Initialize, MemBar nodes |
3389 | // we don't need to do anything, but the users must be pushed |
3390 | n = n->as_MemBar()->proj_out_or_null(TypeFunc::Memory); |
3391 | if (n == NULL__null) { |
3392 | continue; |
3393 | } |
3394 | } else if (n->Opcode() == Op_StrCompressedCopy || |
3395 | n->Opcode() == Op_EncodeISOArray) { |
3396 | // get the memory projection |
3397 | n = n->find_out_with(Op_SCMemProj); |
3398 | assert(n != NULL && n->Opcode() == Op_SCMemProj, "memory projection required")do { if (!(n != __null && n->Opcode() == Op_SCMemProj )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3398, "assert(" "n != __null && n->Opcode() == Op_SCMemProj" ") failed", "memory projection required"); ::breakpoint(); } } while (0); |
3399 | } else { |
3400 | assert(n->is_Mem(), "memory node required.")do { if (!(n->is_Mem())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3400, "assert(" "n->is_Mem()" ") failed", "memory node required." ); ::breakpoint(); } } while (0); |
3401 | Node *addr = n->in(MemNode::Address); |
3402 | const Type *addr_t = igvn->type(addr); |
3403 | if (addr_t == Type::TOP) { |
3404 | continue; |
3405 | } |
3406 | assert (addr_t->isa_ptr() != NULL, "pointer type required.")do { if (!(addr_t->isa_ptr() != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3406, "assert(" "addr_t->isa_ptr() != __null" ") failed" , "pointer type required."); ::breakpoint(); } } while (0); |
3407 | int alias_idx = _compile->get_alias_index(addr_t->is_ptr()); |
3408 | assert ((uint)alias_idx < new_index_end, "wrong alias index")do { if (!((uint)alias_idx < new_index_end)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3408, "assert(" "(uint)alias_idx < new_index_end" ") failed" , "wrong alias index"); ::breakpoint(); } } while (0); |
3409 | Node *mem = find_inst_mem(n->in(MemNode::Memory), alias_idx, orig_phis); |
3410 | if (_compile->failing()) { |
3411 | return; |
3412 | } |
3413 | if (mem != n->in(MemNode::Memory)) { |
3414 | // We delay the memory edge update since we need old one in |
3415 | // MergeMem code below when instances memory slices are separated. |
3416 | set_map(n, mem); |
3417 | } |
3418 | if (n->is_Load()) { |
3419 | continue; // don't push users |
3420 | } else if (n->is_LoadStore()) { |
3421 | // get the memory projection |
3422 | n = n->find_out_with(Op_SCMemProj); |
3423 | assert(n != NULL && n->Opcode() == Op_SCMemProj, "memory projection required")do { if (!(n != __null && n->Opcode() == Op_SCMemProj )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3423, "assert(" "n != __null && n->Opcode() == Op_SCMemProj" ") failed", "memory projection required"); ::breakpoint(); } } while (0); |
3424 | } |
3425 | } |
3426 | // push user on appropriate worklist |
3427 | for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) { |
3428 | Node *use = n->fast_out(i); |
3429 | if (use->is_Phi() || use->is_ClearArray()) { |
3430 | memnode_worklist.append_if_missing(use); |
3431 | } else if (use->is_Mem() && use->in(MemNode::Memory) == n) { |
3432 | if (use->Opcode() == Op_StoreCM) { // Ignore cardmark stores |
3433 | continue; |
3434 | } |
3435 | memnode_worklist.append_if_missing(use); |
3436 | } else if (use->is_MemBar()) { |
3437 | if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge |
3438 | memnode_worklist.append_if_missing(use); |
3439 | } |
3440 | #ifdef ASSERT1 |
3441 | } else if(use->is_Mem()) { |
3442 | assert(use->in(MemNode::Memory) != n, "EA: missing memory path")do { if (!(use->in(MemNode::Memory) != n)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3442, "assert(" "use->in(MemNode::Memory) != n" ") failed" , "EA: missing memory path"); ::breakpoint(); } } while (0); |
3443 | } else if (use->is_MergeMem()) { |
3444 | assert(mergemem_worklist.contains(use->as_MergeMem()), "EA: missing MergeMem node in the worklist")do { if (!(mergemem_worklist.contains(use->as_MergeMem())) ) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3444, "assert(" "mergemem_worklist.contains(use->as_MergeMem())" ") failed", "EA: missing MergeMem node in the worklist"); :: breakpoint(); } } while (0); |
3445 | } else if (use->Opcode() == Op_EncodeISOArray) { |
3446 | if (use->in(MemNode::Memory) == n || use->in(3) == n) { |
3447 | // EncodeISOArray overwrites destination array |
3448 | memnode_worklist.append_if_missing(use); |
3449 | } |
3450 | } else { |
3451 | uint op = use->Opcode(); |
3452 | if ((use->in(MemNode::Memory) == n) && |
3453 | (op == Op_StrCompressedCopy || op == Op_StrInflatedCopy)) { |
3454 | // They overwrite memory edge corresponding to destination array, |
3455 | memnode_worklist.append_if_missing(use); |
3456 | } else if (!(BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use) || |
3457 | op == Op_AryEq || op == Op_StrComp || op == Op_HasNegatives || |
3458 | op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || |
3459 | op == Op_StrEquals || op == Op_StrIndexOf || op == Op_StrIndexOfChar)) { |
3460 | n->dump(); |
3461 | use->dump(); |
3462 | assert(false, "EA: missing memory path")do { if (!(false)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3462, "assert(" "false" ") failed", "EA: missing memory path" ); ::breakpoint(); } } while (0); |
3463 | } |
3464 | #endif |
3465 | } |
3466 | } |
3467 | } |
3468 | |
3469 | // Phase 3: Process MergeMem nodes from mergemem_worklist. |
3470 | // Walk each memory slice moving the first node encountered of each |
3471 | // instance type to the the input corresponding to its alias index. |
3472 | uint length = mergemem_worklist.length(); |
3473 | for( uint next = 0; next < length; ++next ) { |
3474 | MergeMemNode* nmm = mergemem_worklist.at(next); |
3475 | assert(!visited.test_set(nmm->_idx), "should not be visited before")do { if (!(!visited.test_set(nmm->_idx))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3475, "assert(" "!visited.test_set(nmm->_idx)" ") failed" , "should not be visited before"); ::breakpoint(); } } while ( 0); |
3476 | // Note: we don't want to use MergeMemStream here because we only want to |
3477 | // scan inputs which exist at the start, not ones we add during processing. |
3478 | // Note 2: MergeMem may already contains instance memory slices added |
3479 | // during find_inst_mem() call when memory nodes were processed above. |
3480 | igvn->hash_delete(nmm); |
3481 | uint nslices = MIN2(nmm->req(), new_index_start); |
3482 | for (uint i = Compile::AliasIdxRaw+1; i < nslices; i++) { |
3483 | Node* mem = nmm->in(i); |
3484 | Node* cur = NULL__null; |
3485 | if (mem == NULL__null || mem->is_top()) { |
3486 | continue; |
3487 | } |
3488 | // First, update mergemem by moving memory nodes to corresponding slices |
3489 | // if their type became more precise since this mergemem was created. |
3490 | while (mem->is_Mem()) { |
3491 | const Type *at = igvn->type(mem->in(MemNode::Address)); |
3492 | if (at != Type::TOP) { |
3493 | assert (at->isa_ptr() != NULL, "pointer type required.")do { if (!(at->isa_ptr() != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3493, "assert(" "at->isa_ptr() != __null" ") failed", "pointer type required." ); ::breakpoint(); } } while (0); |
3494 | uint idx = (uint)_compile->get_alias_index(at->is_ptr()); |
3495 | if (idx == i) { |
3496 | if (cur == NULL__null) { |
3497 | cur = mem; |
3498 | } |
3499 | } else { |
3500 | if (idx >= nmm->req() || nmm->is_empty_memory(nmm->in(idx))) { |
3501 | nmm->set_memory_at(idx, mem); |
3502 | } |
3503 | } |
3504 | } |
3505 | mem = mem->in(MemNode::Memory); |
3506 | } |
3507 | nmm->set_memory_at(i, (cur != NULL__null) ? cur : mem); |
3508 | // Find any instance of the current type if we haven't encountered |
3509 | // already a memory slice of the instance along the memory chain. |
3510 | for (uint ni = new_index_start; ni < new_index_end; ni++) { |
3511 | if((uint)_compile->get_general_index(ni) == i) { |
3512 | Node *m = (ni >= nmm->req()) ? nmm->empty_memory() : nmm->in(ni); |
3513 | if (nmm->is_empty_memory(m)) { |
3514 | Node* result = find_inst_mem(mem, ni, orig_phis); |
3515 | if (_compile->failing()) { |
3516 | return; |
3517 | } |
3518 | nmm->set_memory_at(ni, result); |
3519 | } |
3520 | } |
3521 | } |
3522 | } |
3523 | // Find the rest of instances values |
3524 | for (uint ni = new_index_start; ni < new_index_end; ni++) { |
3525 | const TypeOopPtr *tinst = _compile->get_adr_type(ni)->isa_oopptr(); |
3526 | Node* result = step_through_mergemem(nmm, ni, tinst); |
3527 | if (result == nmm->base_memory()) { |
3528 | // Didn't find instance memory, search through general slice recursively. |
3529 | result = nmm->memory_at(_compile->get_general_index(ni)); |
3530 | result = find_inst_mem(result, ni, orig_phis); |
3531 | if (_compile->failing()) { |
3532 | return; |
3533 | } |
3534 | nmm->set_memory_at(ni, result); |
3535 | } |
3536 | } |
3537 | igvn->hash_insert(nmm); |
3538 | record_for_optimizer(nmm); |
3539 | } |
3540 | |
3541 | // Phase 4: Update the inputs of non-instance memory Phis and |
3542 | // the Memory input of memnodes |
3543 | // First update the inputs of any non-instance Phi's from |
3544 | // which we split out an instance Phi. Note we don't have |
3545 | // to recursively process Phi's encountered on the input memory |
3546 | // chains as is done in split_memory_phi() since they will |
3547 | // also be processed here. |
3548 | for (int j = 0; j < orig_phis.length(); j++) { |
3549 | PhiNode *phi = orig_phis.at(j); |
3550 | int alias_idx = _compile->get_alias_index(phi->adr_type()); |
3551 | igvn->hash_delete(phi); |
3552 | for (uint i = 1; i < phi->req(); i++) { |
3553 | Node *mem = phi->in(i); |
3554 | Node *new_mem = find_inst_mem(mem, alias_idx, orig_phis); |
3555 | if (_compile->failing()) { |
3556 | return; |
3557 | } |
3558 | if (mem != new_mem) { |
3559 | phi->set_req(i, new_mem); |
3560 | } |
3561 | } |
3562 | igvn->hash_insert(phi); |
3563 | record_for_optimizer(phi); |
3564 | } |
3565 | |
3566 | // Update the memory inputs of MemNodes with the value we computed |
3567 | // in Phase 2 and move stores memory users to corresponding memory slices. |
3568 | // Disable memory split verification code until the fix for 6984348. |
3569 | // Currently it produces false negative results since it does not cover all cases. |
3570 | #if 0 // ifdef ASSERT |
3571 | visited.Reset(); |
3572 | Node_Stack old_mems(arena, _compile->unique() >> 2); |
3573 | #endif |
3574 | for (uint i = 0; i < ideal_nodes.size(); i++) { |
3575 | Node* n = ideal_nodes.at(i); |
3576 | Node* nmem = get_map(n->_idx); |
3577 | assert(nmem != NULL, "sanity")do { if (!(nmem != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3577, "assert(" "nmem != __null" ") failed", "sanity"); ::breakpoint (); } } while (0); |
3578 | if (n->is_Mem()) { |
3579 | #if 0 // ifdef ASSERT |
3580 | Node* old_mem = n->in(MemNode::Memory); |
3581 | if (!visited.test_set(old_mem->_idx)) { |
3582 | old_mems.push(old_mem, old_mem->outcnt()); |
3583 | } |
3584 | #endif |
3585 | assert(n->in(MemNode::Memory) != nmem, "sanity")do { if (!(n->in(MemNode::Memory) != nmem)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3585, "assert(" "n->in(MemNode::Memory) != nmem" ") failed" , "sanity"); ::breakpoint(); } } while (0); |
3586 | if (!n->is_Load()) { |
3587 | // Move memory users of a store first. |
3588 | move_inst_mem(n, orig_phis); |
3589 | } |
3590 | // Now update memory input |
3591 | igvn->hash_delete(n); |
3592 | n->set_req(MemNode::Memory, nmem); |
3593 | igvn->hash_insert(n); |
3594 | record_for_optimizer(n); |
3595 | } else { |
3596 | assert(n->is_Allocate() || n->is_CheckCastPP() ||do { if (!(n->is_Allocate() || n->is_CheckCastPP() || n ->is_AddP() || n->is_Phi())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3597, "assert(" "n->is_Allocate() || n->is_CheckCastPP() || n->is_AddP() || n->is_Phi()" ") failed", "unknown node used for set_map()"); ::breakpoint (); } } while (0) |
3597 | n->is_AddP() || n->is_Phi(), "unknown node used for set_map()")do { if (!(n->is_Allocate() || n->is_CheckCastPP() || n ->is_AddP() || n->is_Phi())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3597, "assert(" "n->is_Allocate() || n->is_CheckCastPP() || n->is_AddP() || n->is_Phi()" ") failed", "unknown node used for set_map()"); ::breakpoint (); } } while (0); |
3598 | } |
3599 | } |
3600 | #if 0 // ifdef ASSERT |
3601 | // Verify that memory was split correctly |
3602 | while (old_mems.is_nonempty()) { |
3603 | Node* old_mem = old_mems.node(); |
3604 | uint old_cnt = old_mems.index(); |
3605 | old_mems.pop(); |
3606 | assert(old_cnt == old_mem->outcnt(), "old mem could be lost")do { if (!(old_cnt == old_mem->outcnt())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/opto/escape.cpp" , 3606, "assert(" "old_cnt == old_mem->outcnt()" ") failed" , "old mem could be lost"); ::breakpoint(); } } while (0); |
3607 | } |
3608 | #endif |
3609 | } |
3610 | |
3611 | #ifndef PRODUCT |
3612 | static const char *node_type_names[] = { |
3613 | "UnknownType", |
3614 | "JavaObject", |
3615 | "LocalVar", |
3616 | "Field", |
3617 | "Arraycopy" |
3618 | }; |
3619 | |
3620 | static const char *esc_names[] = { |
3621 | "UnknownEscape", |
3622 | "NoEscape", |
3623 | "ArgEscape", |
3624 | "GlobalEscape" |
3625 | }; |
3626 | |
3627 | void PointsToNode::dump(bool print_state) const { |
3628 | NodeType nt = node_type(); |
3629 | tty->print("%s ", node_type_names[(int) nt]); |
3630 | if (print_state) { |
3631 | EscapeState es = escape_state(); |
3632 | EscapeState fields_es = fields_escape_state(); |
3633 | tty->print("%s(%s) ", esc_names[(int)es], esc_names[(int)fields_es]); |
3634 | if (nt == PointsToNode::JavaObject && !this->scalar_replaceable()) { |
3635 | tty->print("NSR "); |
3636 | } |
3637 | } |
3638 | if (is_Field()) { |
3639 | FieldNode* f = (FieldNode*)this; |
3640 | if (f->is_oop()) { |
3641 | tty->print("oop "); |
3642 | } |
3643 | if (f->offset() > 0) { |
3644 | tty->print("+%d ", f->offset()); |
3645 | } |
3646 | tty->print("("); |
3647 | for (BaseIterator i(f); i.has_next(); i.next()) { |
3648 | PointsToNode* b = i.get(); |
3649 | tty->print(" %d%s", b->idx(),(b->is_JavaObject() ? "P" : "")); |
3650 | } |
3651 | tty->print(" )"); |
3652 | } |
3653 | tty->print("["); |
3654 | for (EdgeIterator i(this); i.has_next(); i.next()) { |
3655 | PointsToNode* e = i.get(); |
3656 | tty->print(" %d%s%s", e->idx(),(e->is_JavaObject() ? "P" : (e->is_Field() ? "F" : "")), e->is_Arraycopy() ? "cp" : ""); |
3657 | } |
3658 | tty->print(" ["); |
3659 | for (UseIterator i(this); i.has_next(); i.next()) { |
3660 | PointsToNode* u = i.get(); |
3661 | bool is_base = false; |
3662 | if (PointsToNode::is_base_use(u)) { |
3663 | is_base = true; |
3664 | u = PointsToNode::get_use_node(u)->as_Field(); |
3665 | } |
3666 | tty->print(" %d%s%s", u->idx(), is_base ? "b" : "", u->is_Arraycopy() ? "cp" : ""); |
3667 | } |
3668 | tty->print(" ]] "); |
3669 | if (_node == NULL__null) { |
3670 | tty->print_cr("<null>"); |
3671 | } else { |
3672 | _node->dump(); |
3673 | } |
3674 | } |
3675 | |
3676 | void ConnectionGraph::dump(GrowableArray<PointsToNode*>& ptnodes_worklist) { |
3677 | bool first = true; |
3678 | int ptnodes_length = ptnodes_worklist.length(); |
3679 | for (int i = 0; i < ptnodes_length; i++) { |
3680 | PointsToNode *ptn = ptnodes_worklist.at(i); |
3681 | if (ptn == NULL__null || !ptn->is_JavaObject()) { |
3682 | continue; |
3683 | } |
3684 | PointsToNode::EscapeState es = ptn->escape_state(); |
3685 | if ((es != PointsToNode::NoEscape) && !Verbose) { |
3686 | continue; |
3687 | } |
3688 | Node* n = ptn->ideal_node(); |
3689 | if (n->is_Allocate() || (n->is_CallStaticJava() && |
3690 | n->as_CallStaticJava()->is_boxing_method())) { |
3691 | if (first) { |
3692 | tty->cr(); |
3693 | tty->print("======== Connection graph for "); |
3694 | _compile->method()->print_short_name(); |
3695 | tty->cr(); |
3696 | tty->print_cr("invocation #%d: %d iterations and %f sec to build connection graph with %d nodes and worklist size %d", |
3697 | _invocation, _build_iterations, _build_time, nodes_size(), ptnodes_worklist.length()); |
3698 | tty->cr(); |
3699 | first = false; |
3700 | } |
3701 | ptn->dump(); |
3702 | // Print all locals and fields which reference this allocation |
3703 | for (UseIterator j(ptn); j.has_next(); j.next()) { |
3704 | PointsToNode* use = j.get(); |
3705 | if (use->is_LocalVar()) { |
3706 | use->dump(Verbose); |
3707 | } else if (Verbose) { |
3708 | use->dump(); |
3709 | } |
3710 | } |
3711 | tty->cr(); |
3712 | } |
3713 | } |
3714 | } |
3715 | #endif |
3716 | |
3717 | void ConnectionGraph::record_for_optimizer(Node *n) { |
3718 | _igvn->_worklist.push(n); |
3719 | _igvn->add_users_to_worklist(n); |
3720 | } |