File: | jdk/src/hotspot/share/c1/c1_Instruction.hpp |
Warning: | line 1067, column 55 Called C++ object pointer is null |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | ||||
2 | * Copyright (c) 1999, 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 "c1/c1_CFGPrinter.hpp" | ||||
27 | #include "c1/c1_Canonicalizer.hpp" | ||||
28 | #include "c1/c1_Compilation.hpp" | ||||
29 | #include "c1/c1_GraphBuilder.hpp" | ||||
30 | #include "c1/c1_InstructionPrinter.hpp" | ||||
31 | #include "ci/ciCallSite.hpp" | ||||
32 | #include "ci/ciField.hpp" | ||||
33 | #include "ci/ciKlass.hpp" | ||||
34 | #include "ci/ciMemberName.hpp" | ||||
35 | #include "ci/ciSymbols.hpp" | ||||
36 | #include "ci/ciUtilities.inline.hpp" | ||||
37 | #include "compiler/compilationPolicy.hpp" | ||||
38 | #include "compiler/compileBroker.hpp" | ||||
39 | #include "compiler/compilerEvent.hpp" | ||||
40 | #include "interpreter/bytecode.hpp" | ||||
41 | #include "jfr/jfrEvents.hpp" | ||||
42 | #include "memory/resourceArea.hpp" | ||||
43 | #include "oops/oop.inline.hpp" | ||||
44 | #include "runtime/sharedRuntime.hpp" | ||||
45 | #include "runtime/vm_version.hpp" | ||||
46 | #include "utilities/bitMap.inline.hpp" | ||||
47 | #include "utilities/powerOfTwo.hpp" | ||||
48 | |||||
49 | class BlockListBuilder { | ||||
50 | private: | ||||
51 | Compilation* _compilation; | ||||
52 | IRScope* _scope; | ||||
53 | |||||
54 | BlockList _blocks; // internal list of all blocks | ||||
55 | BlockList* _bci2block; // mapping from bci to blocks for GraphBuilder | ||||
56 | GrowableArray<BlockList> _bci2block_successors; // Mapping bcis to their blocks successors while we dont have a blockend | ||||
57 | |||||
58 | // fields used by mark_loops | ||||
59 | ResourceBitMap _active; // for iteration of control flow graph | ||||
60 | ResourceBitMap _visited; // for iteration of control flow graph | ||||
61 | intArray _loop_map; // caches the information if a block is contained in a loop | ||||
62 | int _next_loop_index; // next free loop number | ||||
63 | int _next_block_number; // for reverse postorder numbering of blocks | ||||
64 | |||||
65 | // accessors | ||||
66 | Compilation* compilation() const { return _compilation; } | ||||
67 | IRScope* scope() const { return _scope; } | ||||
68 | ciMethod* method() const { return scope()->method(); } | ||||
69 | XHandlers* xhandlers() const { return scope()->xhandlers(); } | ||||
70 | |||||
71 | // unified bailout support | ||||
72 | void bailout(const char* msg) const { compilation()->bailout(msg); } | ||||
73 | bool bailed_out() const { return compilation()->bailed_out(); } | ||||
74 | |||||
75 | // helper functions | ||||
76 | BlockBegin* make_block_at(int bci, BlockBegin* predecessor); | ||||
77 | void handle_exceptions(BlockBegin* current, int cur_bci); | ||||
78 | void handle_jsr(BlockBegin* current, int sr_bci, int next_bci); | ||||
79 | void store_one(BlockBegin* current, int local); | ||||
80 | void store_two(BlockBegin* current, int local); | ||||
81 | void set_entries(int osr_bci); | ||||
82 | void set_leaders(); | ||||
83 | |||||
84 | void make_loop_header(BlockBegin* block); | ||||
85 | void mark_loops(); | ||||
86 | int mark_loops(BlockBegin* b, bool in_subroutine); | ||||
87 | |||||
88 | // debugging | ||||
89 | #ifndef PRODUCT | ||||
90 | void print(); | ||||
91 | #endif | ||||
92 | |||||
93 | int number_of_successors(BlockBegin* block); | ||||
94 | BlockBegin* successor_at(BlockBegin* block, int i); | ||||
95 | void add_successor(BlockBegin* block, BlockBegin* sux); | ||||
96 | bool is_successor(BlockBegin* block, BlockBegin* sux); | ||||
97 | |||||
98 | public: | ||||
99 | // creation | ||||
100 | BlockListBuilder(Compilation* compilation, IRScope* scope, int osr_bci); | ||||
101 | |||||
102 | // accessors for GraphBuilder | ||||
103 | BlockList* bci2block() const { return _bci2block; } | ||||
104 | }; | ||||
105 | |||||
106 | |||||
107 | // Implementation of BlockListBuilder | ||||
108 | |||||
109 | BlockListBuilder::BlockListBuilder(Compilation* compilation, IRScope* scope, int osr_bci) | ||||
110 | : _compilation(compilation) | ||||
111 | , _scope(scope) | ||||
112 | , _blocks(16) | ||||
113 | , _bci2block(new BlockList(scope->method()->code_size(), NULL__null)) | ||||
114 | , _bci2block_successors(scope->method()->code_size()) | ||||
115 | , _active() // size not known yet | ||||
116 | , _visited() // size not known yet | ||||
117 | , _loop_map() // size not known yet | ||||
118 | , _next_loop_index(0) | ||||
119 | , _next_block_number(0) | ||||
120 | { | ||||
121 | set_entries(osr_bci); | ||||
122 | set_leaders(); | ||||
123 | CHECK_BAILOUT(){ if (bailed_out()) return; }; | ||||
124 | |||||
125 | mark_loops(); | ||||
126 | NOT_PRODUCT(if (PrintInitialBlockList) print())if (PrintInitialBlockList) print(); | ||||
127 | |||||
128 | // _bci2block still contains blocks with _end == null and > 0 sux in _bci2block_successors. | ||||
129 | |||||
130 | #ifndef PRODUCT | ||||
131 | if (PrintCFGToFile) { | ||||
132 | stringStream title; | ||||
133 | title.print("BlockListBuilder "); | ||||
134 | scope->method()->print_name(&title); | ||||
135 | CFGPrinter::print_cfg(_bci2block, title.as_string(), false, false); | ||||
136 | } | ||||
137 | #endif | ||||
138 | } | ||||
139 | |||||
140 | |||||
141 | void BlockListBuilder::set_entries(int osr_bci) { | ||||
142 | // generate start blocks | ||||
143 | BlockBegin* std_entry = make_block_at(0, NULL__null); | ||||
144 | if (scope()->caller() == NULL__null) { | ||||
145 | std_entry->set(BlockBegin::std_entry_flag); | ||||
146 | } | ||||
147 | if (osr_bci != -1) { | ||||
148 | BlockBegin* osr_entry = make_block_at(osr_bci, NULL__null); | ||||
149 | osr_entry->set(BlockBegin::osr_entry_flag); | ||||
150 | } | ||||
151 | |||||
152 | // generate exception entry blocks | ||||
153 | XHandlers* list = xhandlers(); | ||||
154 | const int n = list->length(); | ||||
155 | for (int i = 0; i < n; i++) { | ||||
156 | XHandler* h = list->handler_at(i); | ||||
157 | BlockBegin* entry = make_block_at(h->handler_bci(), NULL__null); | ||||
158 | entry->set(BlockBegin::exception_entry_flag); | ||||
159 | h->set_entry_block(entry); | ||||
160 | } | ||||
161 | } | ||||
162 | |||||
163 | |||||
164 | BlockBegin* BlockListBuilder::make_block_at(int cur_bci, BlockBegin* predecessor) { | ||||
165 | assert(method()->bci_block_start().at(cur_bci), "wrong block starts of MethodLivenessAnalyzer")do { if (!(method()->bci_block_start().at(cur_bci))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 165, "assert(" "method()->bci_block_start().at(cur_bci)" ") failed", "wrong block starts of MethodLivenessAnalyzer"); ::breakpoint(); } } while (0); | ||||
166 | |||||
167 | BlockBegin* block = _bci2block->at(cur_bci); | ||||
168 | if (block == NULL__null) { | ||||
169 | block = new BlockBegin(cur_bci); | ||||
170 | block->init_stores_to_locals(method()->max_locals()); | ||||
171 | _bci2block->at_put(cur_bci, block); | ||||
172 | _bci2block_successors.at_put_grow(cur_bci, BlockList()); | ||||
173 | _blocks.append(block); | ||||
174 | |||||
175 | assert(predecessor == NULL || predecessor->bci() < cur_bci, "targets for backward branches must already exist")do { if (!(predecessor == __null || predecessor->bci() < cur_bci)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 175, "assert(" "predecessor == __null || predecessor->bci() < cur_bci" ") failed", "targets for backward branches must already exist" ); ::breakpoint(); } } while (0); | ||||
176 | } | ||||
177 | |||||
178 | if (predecessor != NULL__null) { | ||||
179 | if (block->is_set(BlockBegin::exception_entry_flag)) { | ||||
180 | BAILOUT_("Exception handler can be reached by both normal and exceptional control flow", block){ bailout("Exception handler can be reached by both normal and exceptional control flow" ); return block; }; | ||||
181 | } | ||||
182 | |||||
183 | add_successor(predecessor, block); | ||||
184 | block->increment_total_preds(); | ||||
185 | } | ||||
186 | |||||
187 | return block; | ||||
188 | } | ||||
189 | |||||
190 | |||||
191 | inline void BlockListBuilder::store_one(BlockBegin* current, int local) { | ||||
192 | current->stores_to_locals().set_bit(local); | ||||
193 | } | ||||
194 | inline void BlockListBuilder::store_two(BlockBegin* current, int local) { | ||||
195 | store_one(current, local); | ||||
196 | store_one(current, local + 1); | ||||
197 | } | ||||
198 | |||||
199 | |||||
200 | void BlockListBuilder::handle_exceptions(BlockBegin* current, int cur_bci) { | ||||
201 | // Draws edges from a block to its exception handlers | ||||
202 | XHandlers* list = xhandlers(); | ||||
203 | const int n = list->length(); | ||||
204 | |||||
205 | for (int i = 0; i < n; i++) { | ||||
206 | XHandler* h = list->handler_at(i); | ||||
207 | |||||
208 | if (h->covers(cur_bci)) { | ||||
209 | BlockBegin* entry = h->entry_block(); | ||||
210 | assert(entry != NULL && entry == _bci2block->at(h->handler_bci()), "entry must be set")do { if (!(entry != __null && entry == _bci2block-> at(h->handler_bci()))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 210, "assert(" "entry != __null && entry == _bci2block->at(h->handler_bci())" ") failed", "entry must be set"); ::breakpoint(); } } while ( 0); | ||||
211 | assert(entry->is_set(BlockBegin::exception_entry_flag), "flag must be set")do { if (!(entry->is_set(BlockBegin::exception_entry_flag) )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 211, "assert(" "entry->is_set(BlockBegin::exception_entry_flag)" ") failed", "flag must be set"); ::breakpoint(); } } while ( 0); | ||||
212 | |||||
213 | // add each exception handler only once | ||||
214 | if(!is_successor(current, entry)) { | ||||
215 | add_successor(current, entry); | ||||
216 | entry->increment_total_preds(); | ||||
217 | } | ||||
218 | |||||
219 | // stop when reaching catchall | ||||
220 | if (h->catch_type() == 0) break; | ||||
221 | } | ||||
222 | } | ||||
223 | } | ||||
224 | |||||
225 | void BlockListBuilder::handle_jsr(BlockBegin* current, int sr_bci, int next_bci) { | ||||
226 | // start a new block after jsr-bytecode and link this block into cfg | ||||
227 | make_block_at(next_bci, current); | ||||
228 | |||||
229 | // start a new block at the subroutine entry at mark it with special flag | ||||
230 | BlockBegin* sr_block = make_block_at(sr_bci, current); | ||||
231 | if (!sr_block->is_set(BlockBegin::subroutine_entry_flag)) { | ||||
232 | sr_block->set(BlockBegin::subroutine_entry_flag); | ||||
233 | } | ||||
234 | } | ||||
235 | |||||
236 | |||||
237 | void BlockListBuilder::set_leaders() { | ||||
238 | bool has_xhandlers = xhandlers()->has_handlers(); | ||||
239 | BlockBegin* current = NULL__null; | ||||
240 | |||||
241 | // The information which bci starts a new block simplifies the analysis | ||||
242 | // Without it, backward branches could jump to a bci where no block was created | ||||
243 | // during bytecode iteration. This would require the creation of a new block at the | ||||
244 | // branch target and a modification of the successor lists. | ||||
245 | const BitMap& bci_block_start = method()->bci_block_start(); | ||||
246 | |||||
247 | ciBytecodeStream s(method()); | ||||
248 | while (s.next() != ciBytecodeStream::EOBC()) { | ||||
249 | int cur_bci = s.cur_bci(); | ||||
250 | |||||
251 | if (bci_block_start.at(cur_bci)) { | ||||
252 | current = make_block_at(cur_bci, current); | ||||
253 | } | ||||
254 | assert(current != NULL, "must have current block")do { if (!(current != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 254, "assert(" "current != __null" ") failed", "must have current block" ); ::breakpoint(); } } while (0); | ||||
255 | |||||
256 | if (has_xhandlers && GraphBuilder::can_trap(method(), s.cur_bc())) { | ||||
257 | handle_exceptions(current, cur_bci); | ||||
258 | } | ||||
259 | |||||
260 | switch (s.cur_bc()) { | ||||
261 | // track stores to local variables for selective creation of phi functions | ||||
262 | case Bytecodes::_iinc: store_one(current, s.get_index()); break; | ||||
263 | case Bytecodes::_istore: store_one(current, s.get_index()); break; | ||||
264 | case Bytecodes::_lstore: store_two(current, s.get_index()); break; | ||||
265 | case Bytecodes::_fstore: store_one(current, s.get_index()); break; | ||||
266 | case Bytecodes::_dstore: store_two(current, s.get_index()); break; | ||||
267 | case Bytecodes::_astore: store_one(current, s.get_index()); break; | ||||
268 | case Bytecodes::_istore_0: store_one(current, 0); break; | ||||
269 | case Bytecodes::_istore_1: store_one(current, 1); break; | ||||
270 | case Bytecodes::_istore_2: store_one(current, 2); break; | ||||
271 | case Bytecodes::_istore_3: store_one(current, 3); break; | ||||
272 | case Bytecodes::_lstore_0: store_two(current, 0); break; | ||||
273 | case Bytecodes::_lstore_1: store_two(current, 1); break; | ||||
274 | case Bytecodes::_lstore_2: store_two(current, 2); break; | ||||
275 | case Bytecodes::_lstore_3: store_two(current, 3); break; | ||||
276 | case Bytecodes::_fstore_0: store_one(current, 0); break; | ||||
277 | case Bytecodes::_fstore_1: store_one(current, 1); break; | ||||
278 | case Bytecodes::_fstore_2: store_one(current, 2); break; | ||||
279 | case Bytecodes::_fstore_3: store_one(current, 3); break; | ||||
280 | case Bytecodes::_dstore_0: store_two(current, 0); break; | ||||
281 | case Bytecodes::_dstore_1: store_two(current, 1); break; | ||||
282 | case Bytecodes::_dstore_2: store_two(current, 2); break; | ||||
283 | case Bytecodes::_dstore_3: store_two(current, 3); break; | ||||
284 | case Bytecodes::_astore_0: store_one(current, 0); break; | ||||
285 | case Bytecodes::_astore_1: store_one(current, 1); break; | ||||
286 | case Bytecodes::_astore_2: store_one(current, 2); break; | ||||
287 | case Bytecodes::_astore_3: store_one(current, 3); break; | ||||
288 | |||||
289 | // track bytecodes that affect the control flow | ||||
290 | case Bytecodes::_athrow: // fall through | ||||
291 | case Bytecodes::_ret: // fall through | ||||
292 | case Bytecodes::_ireturn: // fall through | ||||
293 | case Bytecodes::_lreturn: // fall through | ||||
294 | case Bytecodes::_freturn: // fall through | ||||
295 | case Bytecodes::_dreturn: // fall through | ||||
296 | case Bytecodes::_areturn: // fall through | ||||
297 | case Bytecodes::_return: | ||||
298 | current = NULL__null; | ||||
299 | break; | ||||
300 | |||||
301 | case Bytecodes::_ifeq: // fall through | ||||
302 | case Bytecodes::_ifne: // fall through | ||||
303 | case Bytecodes::_iflt: // fall through | ||||
304 | case Bytecodes::_ifge: // fall through | ||||
305 | case Bytecodes::_ifgt: // fall through | ||||
306 | case Bytecodes::_ifle: // fall through | ||||
307 | case Bytecodes::_if_icmpeq: // fall through | ||||
308 | case Bytecodes::_if_icmpne: // fall through | ||||
309 | case Bytecodes::_if_icmplt: // fall through | ||||
310 | case Bytecodes::_if_icmpge: // fall through | ||||
311 | case Bytecodes::_if_icmpgt: // fall through | ||||
312 | case Bytecodes::_if_icmple: // fall through | ||||
313 | case Bytecodes::_if_acmpeq: // fall through | ||||
314 | case Bytecodes::_if_acmpne: // fall through | ||||
315 | case Bytecodes::_ifnull: // fall through | ||||
316 | case Bytecodes::_ifnonnull: | ||||
317 | make_block_at(s.next_bci(), current); | ||||
318 | make_block_at(s.get_dest(), current); | ||||
319 | current = NULL__null; | ||||
320 | break; | ||||
321 | |||||
322 | case Bytecodes::_goto: | ||||
323 | make_block_at(s.get_dest(), current); | ||||
324 | current = NULL__null; | ||||
325 | break; | ||||
326 | |||||
327 | case Bytecodes::_goto_w: | ||||
328 | make_block_at(s.get_far_dest(), current); | ||||
329 | current = NULL__null; | ||||
330 | break; | ||||
331 | |||||
332 | case Bytecodes::_jsr: | ||||
333 | handle_jsr(current, s.get_dest(), s.next_bci()); | ||||
334 | current = NULL__null; | ||||
335 | break; | ||||
336 | |||||
337 | case Bytecodes::_jsr_w: | ||||
338 | handle_jsr(current, s.get_far_dest(), s.next_bci()); | ||||
339 | current = NULL__null; | ||||
340 | break; | ||||
341 | |||||
342 | case Bytecodes::_tableswitch: { | ||||
343 | // set block for each case | ||||
344 | Bytecode_tableswitch sw(&s); | ||||
345 | int l = sw.length(); | ||||
346 | for (int i = 0; i < l; i++) { | ||||
347 | make_block_at(cur_bci + sw.dest_offset_at(i), current); | ||||
348 | } | ||||
349 | make_block_at(cur_bci + sw.default_offset(), current); | ||||
350 | current = NULL__null; | ||||
351 | break; | ||||
352 | } | ||||
353 | |||||
354 | case Bytecodes::_lookupswitch: { | ||||
355 | // set block for each case | ||||
356 | Bytecode_lookupswitch sw(&s); | ||||
357 | int l = sw.number_of_pairs(); | ||||
358 | for (int i = 0; i < l; i++) { | ||||
359 | make_block_at(cur_bci + sw.pair_at(i).offset(), current); | ||||
360 | } | ||||
361 | make_block_at(cur_bci + sw.default_offset(), current); | ||||
362 | current = NULL__null; | ||||
363 | break; | ||||
364 | } | ||||
365 | |||||
366 | default: | ||||
367 | break; | ||||
368 | } | ||||
369 | } | ||||
370 | } | ||||
371 | |||||
372 | |||||
373 | void BlockListBuilder::mark_loops() { | ||||
374 | ResourceMark rm; | ||||
375 | |||||
376 | _active.initialize(BlockBegin::number_of_blocks()); | ||||
377 | _visited.initialize(BlockBegin::number_of_blocks()); | ||||
378 | _loop_map = intArray(BlockBegin::number_of_blocks(), BlockBegin::number_of_blocks(), 0); | ||||
379 | _next_loop_index = 0; | ||||
380 | _next_block_number = _blocks.length(); | ||||
381 | |||||
382 | // recursively iterate the control flow graph | ||||
383 | mark_loops(_bci2block->at(0), false); | ||||
384 | assert(_next_block_number >= 0, "invalid block numbers")do { if (!(_next_block_number >= 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 384, "assert(" "_next_block_number >= 0" ") failed", "invalid block numbers" ); ::breakpoint(); } } while (0); | ||||
385 | |||||
386 | // Remove dangling Resource pointers before the ResourceMark goes out-of-scope. | ||||
387 | _active.resize(0); | ||||
388 | _visited.resize(0); | ||||
389 | } | ||||
390 | |||||
391 | void BlockListBuilder::make_loop_header(BlockBegin* block) { | ||||
392 | if (block->is_set(BlockBegin::exception_entry_flag)) { | ||||
393 | // exception edges may look like loops but don't mark them as such | ||||
394 | // since it screws up block ordering. | ||||
395 | return; | ||||
396 | } | ||||
397 | if (!block->is_set(BlockBegin::parser_loop_header_flag)) { | ||||
398 | block->set(BlockBegin::parser_loop_header_flag); | ||||
399 | |||||
400 | assert(_loop_map.at(block->block_id()) == 0, "must not be set yet")do { if (!(_loop_map.at(block->block_id()) == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 400, "assert(" "_loop_map.at(block->block_id()) == 0" ") failed" , "must not be set yet"); ::breakpoint(); } } while (0); | ||||
401 | assert(0 <= _next_loop_index && _next_loop_index < BitsPerInt, "_next_loop_index is used as a bit-index in integer")do { if (!(0 <= _next_loop_index && _next_loop_index < BitsPerInt)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 401, "assert(" "0 <= _next_loop_index && _next_loop_index < BitsPerInt" ") failed", "_next_loop_index is used as a bit-index in integer" ); ::breakpoint(); } } while (0); | ||||
402 | _loop_map.at_put(block->block_id(), 1 << _next_loop_index); | ||||
403 | if (_next_loop_index < 31) _next_loop_index++; | ||||
404 | } else { | ||||
405 | // block already marked as loop header | ||||
406 | assert(is_power_of_2((unsigned int)_loop_map.at(block->block_id())), "exactly one bit must be set")do { if (!(is_power_of_2((unsigned int)_loop_map.at(block-> block_id())))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 406, "assert(" "is_power_of_2((unsigned int)_loop_map.at(block->block_id()))" ") failed", "exactly one bit must be set"); ::breakpoint(); } } while (0); | ||||
407 | } | ||||
408 | } | ||||
409 | |||||
410 | int BlockListBuilder::mark_loops(BlockBegin* block, bool in_subroutine) { | ||||
411 | int block_id = block->block_id(); | ||||
412 | |||||
413 | if (_visited.at(block_id)) { | ||||
414 | if (_active.at(block_id)) { | ||||
415 | // reached block via backward branch | ||||
416 | make_loop_header(block); | ||||
417 | } | ||||
418 | // return cached loop information for this block | ||||
419 | return _loop_map.at(block_id); | ||||
420 | } | ||||
421 | |||||
422 | if (block->is_set(BlockBegin::subroutine_entry_flag)) { | ||||
423 | in_subroutine = true; | ||||
424 | } | ||||
425 | |||||
426 | // set active and visited bits before successors are processed | ||||
427 | _visited.set_bit(block_id); | ||||
428 | _active.set_bit(block_id); | ||||
429 | |||||
430 | intptr_t loop_state = 0; | ||||
431 | for (int i = number_of_successors(block) - 1; i >= 0; i--) { | ||||
432 | // recursively process all successors | ||||
433 | loop_state |= mark_loops(successor_at(block, i), in_subroutine); | ||||
434 | } | ||||
435 | |||||
436 | // clear active-bit after all successors are processed | ||||
437 | _active.clear_bit(block_id); | ||||
438 | |||||
439 | // reverse-post-order numbering of all blocks | ||||
440 | block->set_depth_first_number(_next_block_number); | ||||
441 | _next_block_number--; | ||||
442 | |||||
443 | if (loop_state != 0 || in_subroutine ) { | ||||
444 | // block is contained at least in one loop, so phi functions are necessary | ||||
445 | // phi functions are also necessary for all locals stored in a subroutine | ||||
446 | scope()->requires_phi_function().set_union(block->stores_to_locals()); | ||||
447 | } | ||||
448 | |||||
449 | if (block->is_set(BlockBegin::parser_loop_header_flag)) { | ||||
450 | int header_loop_state = _loop_map.at(block_id); | ||||
451 | assert(is_power_of_2((unsigned)header_loop_state), "exactly one bit must be set")do { if (!(is_power_of_2((unsigned)header_loop_state))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 451, "assert(" "is_power_of_2((unsigned)header_loop_state)" ") failed", "exactly one bit must be set"); ::breakpoint(); } } while (0); | ||||
452 | |||||
453 | // If the highest bit is set (i.e. when integer value is negative), the method | ||||
454 | // has 32 or more loops. This bit is never cleared because it is used for multiple loops | ||||
455 | if (header_loop_state >= 0) { | ||||
456 | clear_bits(loop_state, header_loop_state); | ||||
457 | } | ||||
458 | } | ||||
459 | |||||
460 | // cache and return loop information for this block | ||||
461 | _loop_map.at_put(block_id, loop_state); | ||||
462 | return loop_state; | ||||
463 | } | ||||
464 | |||||
465 | inline int BlockListBuilder::number_of_successors(BlockBegin* block) | ||||
466 | { | ||||
467 | assert(_bci2block_successors.length() > block->bci(), "sux must exist")do { if (!(_bci2block_successors.length() > block->bci( ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 467, "assert(" "_bci2block_successors.length() > block->bci()" ") failed", "sux must exist"); ::breakpoint(); } } while (0); | ||||
468 | return _bci2block_successors.at(block->bci()).length(); | ||||
469 | } | ||||
470 | |||||
471 | inline BlockBegin* BlockListBuilder::successor_at(BlockBegin* block, int i) | ||||
472 | { | ||||
473 | assert(_bci2block_successors.length() > block->bci(), "sux must exist")do { if (!(_bci2block_successors.length() > block->bci( ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 473, "assert(" "_bci2block_successors.length() > block->bci()" ") failed", "sux must exist"); ::breakpoint(); } } while (0); | ||||
474 | return _bci2block_successors.at(block->bci()).at(i); | ||||
475 | } | ||||
476 | |||||
477 | inline void BlockListBuilder::add_successor(BlockBegin* block, BlockBegin* sux) | ||||
478 | { | ||||
479 | assert(_bci2block_successors.length() > block->bci(), "sux must exist")do { if (!(_bci2block_successors.length() > block->bci( ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 479, "assert(" "_bci2block_successors.length() > block->bci()" ") failed", "sux must exist"); ::breakpoint(); } } while (0); | ||||
480 | _bci2block_successors.at(block->bci()).append(sux); | ||||
481 | } | ||||
482 | |||||
483 | inline bool BlockListBuilder::is_successor(BlockBegin* block, BlockBegin* sux) { | ||||
484 | assert(_bci2block_successors.length() > block->bci(), "sux must exist")do { if (!(_bci2block_successors.length() > block->bci( ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 484, "assert(" "_bci2block_successors.length() > block->bci()" ") failed", "sux must exist"); ::breakpoint(); } } while (0); | ||||
485 | return _bci2block_successors.at(block->bci()).contains(sux); | ||||
486 | } | ||||
487 | |||||
488 | #ifndef PRODUCT | ||||
489 | |||||
490 | int compare_depth_first(BlockBegin** a, BlockBegin** b) { | ||||
491 | return (*a)->depth_first_number() - (*b)->depth_first_number(); | ||||
492 | } | ||||
493 | |||||
494 | void BlockListBuilder::print() { | ||||
495 | tty->print("----- initial block list of BlockListBuilder for method "); | ||||
496 | method()->print_short_name(); | ||||
497 | tty->cr(); | ||||
498 | |||||
499 | // better readability if blocks are sorted in processing order | ||||
500 | _blocks.sort(compare_depth_first); | ||||
501 | |||||
502 | for (int i = 0; i < _blocks.length(); i++) { | ||||
503 | BlockBegin* cur = _blocks.at(i); | ||||
504 | tty->print("%4d: B%-4d bci: %-4d preds: %-4d ", cur->depth_first_number(), cur->block_id(), cur->bci(), cur->total_preds()); | ||||
505 | |||||
506 | tty->print(cur->is_set(BlockBegin::std_entry_flag) ? " std" : " "); | ||||
507 | tty->print(cur->is_set(BlockBegin::osr_entry_flag) ? " osr" : " "); | ||||
508 | tty->print(cur->is_set(BlockBegin::exception_entry_flag) ? " ex" : " "); | ||||
509 | tty->print(cur->is_set(BlockBegin::subroutine_entry_flag) ? " sr" : " "); | ||||
510 | tty->print(cur->is_set(BlockBegin::parser_loop_header_flag) ? " lh" : " "); | ||||
511 | |||||
512 | if (number_of_successors(cur) > 0) { | ||||
513 | tty->print(" sux: "); | ||||
514 | for (int j = 0; j < number_of_successors(cur); j++) { | ||||
515 | BlockBegin* sux = successor_at(cur, j); | ||||
516 | tty->print("B%d ", sux->block_id()); | ||||
517 | } | ||||
518 | } | ||||
519 | tty->cr(); | ||||
520 | } | ||||
521 | } | ||||
522 | |||||
523 | #endif | ||||
524 | |||||
525 | |||||
526 | // A simple growable array of Values indexed by ciFields | ||||
527 | class FieldBuffer: public CompilationResourceObj { | ||||
528 | private: | ||||
529 | GrowableArray<Value> _values; | ||||
530 | |||||
531 | public: | ||||
532 | FieldBuffer() {} | ||||
533 | |||||
534 | void kill() { | ||||
535 | _values.trunc_to(0); | ||||
536 | } | ||||
537 | |||||
538 | Value at(ciField* field) { | ||||
539 | assert(field->holder()->is_loaded(), "must be a loaded field")do { if (!(field->holder()->is_loaded())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 539, "assert(" "field->holder()->is_loaded()" ") failed" , "must be a loaded field"); ::breakpoint(); } } while (0); | ||||
540 | int offset = field->offset(); | ||||
541 | if (offset < _values.length()) { | ||||
542 | return _values.at(offset); | ||||
543 | } else { | ||||
544 | return NULL__null; | ||||
545 | } | ||||
546 | } | ||||
547 | |||||
548 | void at_put(ciField* field, Value value) { | ||||
549 | assert(field->holder()->is_loaded(), "must be a loaded field")do { if (!(field->holder()->is_loaded())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 549, "assert(" "field->holder()->is_loaded()" ") failed" , "must be a loaded field"); ::breakpoint(); } } while (0); | ||||
550 | int offset = field->offset(); | ||||
551 | _values.at_put_grow(offset, value, NULL__null); | ||||
552 | } | ||||
553 | |||||
554 | }; | ||||
555 | |||||
556 | |||||
557 | // MemoryBuffer is fairly simple model of the current state of memory. | ||||
558 | // It partitions memory into several pieces. The first piece is | ||||
559 | // generic memory where little is known about the owner of the memory. | ||||
560 | // This is conceptually represented by the tuple <O, F, V> which says | ||||
561 | // that the field F of object O has value V. This is flattened so | ||||
562 | // that F is represented by the offset of the field and the parallel | ||||
563 | // arrays _objects and _values are used for O and V. Loads of O.F can | ||||
564 | // simply use V. Newly allocated objects are kept in a separate list | ||||
565 | // along with a parallel array for each object which represents the | ||||
566 | // current value of its fields. Stores of the default value to fields | ||||
567 | // which have never been stored to before are eliminated since they | ||||
568 | // are redundant. Once newly allocated objects are stored into | ||||
569 | // another object or they are passed out of the current compile they | ||||
570 | // are treated like generic memory. | ||||
571 | |||||
572 | class MemoryBuffer: public CompilationResourceObj { | ||||
573 | private: | ||||
574 | FieldBuffer _values; | ||||
575 | GrowableArray<Value> _objects; | ||||
576 | GrowableArray<Value> _newobjects; | ||||
577 | GrowableArray<FieldBuffer*> _fields; | ||||
578 | |||||
579 | public: | ||||
580 | MemoryBuffer() {} | ||||
581 | |||||
582 | StoreField* store(StoreField* st) { | ||||
583 | if (!EliminateFieldAccess) { | ||||
584 | return st; | ||||
585 | } | ||||
586 | |||||
587 | Value object = st->obj(); | ||||
588 | Value value = st->value(); | ||||
589 | ciField* field = st->field(); | ||||
590 | if (field->holder()->is_loaded()) { | ||||
591 | int offset = field->offset(); | ||||
592 | int index = _newobjects.find(object); | ||||
593 | if (index != -1) { | ||||
594 | // newly allocated object with no other stores performed on this field | ||||
595 | FieldBuffer* buf = _fields.at(index); | ||||
596 | if (buf->at(field) == NULL__null && is_default_value(value)) { | ||||
597 | #ifndef PRODUCT | ||||
598 | if (PrintIRDuringConstruction && Verbose) { | ||||
599 | tty->print_cr("Eliminated store for object %d:", index); | ||||
600 | st->print_line(); | ||||
601 | } | ||||
602 | #endif | ||||
603 | return NULL__null; | ||||
604 | } else { | ||||
605 | buf->at_put(field, value); | ||||
606 | } | ||||
607 | } else { | ||||
608 | _objects.at_put_grow(offset, object, NULL__null); | ||||
609 | _values.at_put(field, value); | ||||
610 | } | ||||
611 | |||||
612 | store_value(value); | ||||
613 | } else { | ||||
614 | // if we held onto field names we could alias based on names but | ||||
615 | // we don't know what's being stored to so kill it all. | ||||
616 | kill(); | ||||
617 | } | ||||
618 | return st; | ||||
619 | } | ||||
620 | |||||
621 | |||||
622 | // return true if this value correspond to the default value of a field. | ||||
623 | bool is_default_value(Value value) { | ||||
624 | Constant* con = value->as_Constant(); | ||||
625 | if (con) { | ||||
626 | switch (con->type()->tag()) { | ||||
627 | case intTag: return con->type()->as_IntConstant()->value() == 0; | ||||
628 | case longTag: return con->type()->as_LongConstant()->value() == 0; | ||||
629 | case floatTag: return jint_cast(con->type()->as_FloatConstant()->value()) == 0; | ||||
630 | case doubleTag: return jlong_cast(con->type()->as_DoubleConstant()->value()) == jlong_cast(0); | ||||
631 | case objectTag: return con->type() == objectNull; | ||||
632 | default: ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 632); ::breakpoint(); } while (0); | ||||
633 | } | ||||
634 | } | ||||
635 | return false; | ||||
636 | } | ||||
637 | |||||
638 | |||||
639 | // return either the actual value of a load or the load itself | ||||
640 | Value load(LoadField* load) { | ||||
641 | if (!EliminateFieldAccess) { | ||||
642 | return load; | ||||
643 | } | ||||
644 | |||||
645 | if (strict_fp_requires_explicit_rounding && load->type()->is_float_kind()) { | ||||
646 | #ifdef IA32 | ||||
647 | if (UseSSE < 2) { | ||||
648 | // can't skip load since value might get rounded as a side effect | ||||
649 | return load; | ||||
650 | } | ||||
651 | #else | ||||
652 | Unimplemented()do { (*g_assert_poison) = 'X';; report_unimplemented("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 652); ::breakpoint(); } while (0); | ||||
653 | #endif // IA32 | ||||
654 | } | ||||
655 | |||||
656 | ciField* field = load->field(); | ||||
657 | Value object = load->obj(); | ||||
658 | if (field->holder()->is_loaded() && !field->is_volatile()) { | ||||
659 | int offset = field->offset(); | ||||
660 | Value result = NULL__null; | ||||
661 | int index = _newobjects.find(object); | ||||
662 | if (index != -1) { | ||||
663 | result = _fields.at(index)->at(field); | ||||
664 | } else if (_objects.at_grow(offset, NULL__null) == object) { | ||||
665 | result = _values.at(field); | ||||
666 | } | ||||
667 | if (result != NULL__null) { | ||||
668 | #ifndef PRODUCT | ||||
669 | if (PrintIRDuringConstruction && Verbose) { | ||||
670 | tty->print_cr("Eliminated load: "); | ||||
671 | load->print_line(); | ||||
672 | } | ||||
673 | #endif | ||||
674 | assert(result->type()->tag() == load->type()->tag(), "wrong types")do { if (!(result->type()->tag() == load->type()-> tag())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 674, "assert(" "result->type()->tag() == load->type()->tag()" ") failed", "wrong types"); ::breakpoint(); } } while (0); | ||||
675 | return result; | ||||
676 | } | ||||
677 | } | ||||
678 | return load; | ||||
679 | } | ||||
680 | |||||
681 | // Record this newly allocated object | ||||
682 | void new_instance(NewInstance* object) { | ||||
683 | int index = _newobjects.length(); | ||||
684 | _newobjects.append(object); | ||||
685 | if (_fields.at_grow(index, NULL__null) == NULL__null) { | ||||
686 | _fields.at_put(index, new FieldBuffer()); | ||||
687 | } else { | ||||
688 | _fields.at(index)->kill(); | ||||
689 | } | ||||
690 | } | ||||
691 | |||||
692 | void store_value(Value value) { | ||||
693 | int index = _newobjects.find(value); | ||||
694 | if (index != -1) { | ||||
695 | // stored a newly allocated object into another object. | ||||
696 | // Assume we've lost track of it as separate slice of memory. | ||||
697 | // We could do better by keeping track of whether individual | ||||
698 | // fields could alias each other. | ||||
699 | _newobjects.remove_at(index); | ||||
700 | // pull out the field info and store it at the end up the list | ||||
701 | // of field info list to be reused later. | ||||
702 | _fields.append(_fields.at(index)); | ||||
703 | _fields.remove_at(index); | ||||
704 | } | ||||
705 | } | ||||
706 | |||||
707 | void kill() { | ||||
708 | _newobjects.trunc_to(0); | ||||
709 | _objects.trunc_to(0); | ||||
710 | _values.kill(); | ||||
711 | } | ||||
712 | }; | ||||
713 | |||||
714 | |||||
715 | // Implementation of GraphBuilder's ScopeData | ||||
716 | |||||
717 | GraphBuilder::ScopeData::ScopeData(ScopeData* parent) | ||||
718 | : _parent(parent) | ||||
719 | , _bci2block(NULL__null) | ||||
720 | , _scope(NULL__null) | ||||
721 | , _has_handler(false) | ||||
722 | , _stream(NULL__null) | ||||
723 | , _work_list(NULL__null) | ||||
724 | , _caller_stack_size(-1) | ||||
725 | , _continuation(NULL__null) | ||||
726 | , _parsing_jsr(false) | ||||
727 | , _jsr_xhandlers(NULL__null) | ||||
728 | , _num_returns(0) | ||||
729 | , _cleanup_block(NULL__null) | ||||
730 | , _cleanup_return_prev(NULL__null) | ||||
731 | , _cleanup_state(NULL__null) | ||||
732 | , _ignore_return(false) | ||||
733 | { | ||||
734 | if (parent != NULL__null) { | ||||
735 | _max_inline_size = (intx) ((float) NestedInliningSizeRatio * (float) parent->max_inline_size() / 100.0f); | ||||
736 | } else { | ||||
737 | _max_inline_size = C1MaxInlineSize; | ||||
738 | } | ||||
739 | if (_max_inline_size < C1MaxTrivialSize) { | ||||
740 | _max_inline_size = C1MaxTrivialSize; | ||||
741 | } | ||||
742 | } | ||||
743 | |||||
744 | |||||
745 | void GraphBuilder::kill_all() { | ||||
746 | if (UseLocalValueNumbering) { | ||||
747 | vmap()->kill_all(); | ||||
748 | } | ||||
749 | _memory->kill(); | ||||
750 | } | ||||
751 | |||||
752 | |||||
753 | BlockBegin* GraphBuilder::ScopeData::block_at(int bci) { | ||||
754 | if (parsing_jsr()) { | ||||
755 | // It is necessary to clone all blocks associated with a | ||||
756 | // subroutine, including those for exception handlers in the scope | ||||
757 | // of the method containing the jsr (because those exception | ||||
758 | // handlers may contain ret instructions in some cases). | ||||
759 | BlockBegin* block = bci2block()->at(bci); | ||||
760 | if (block != NULL__null && block == parent()->bci2block()->at(bci)) { | ||||
761 | BlockBegin* new_block = new BlockBegin(block->bci()); | ||||
762 | if (PrintInitialBlockList) { | ||||
763 | tty->print_cr("CFG: cloned block %d (bci %d) as block %d for jsr", | ||||
764 | block->block_id(), block->bci(), new_block->block_id()); | ||||
765 | } | ||||
766 | // copy data from cloned blocked | ||||
767 | new_block->set_depth_first_number(block->depth_first_number()); | ||||
768 | if (block->is_set(BlockBegin::parser_loop_header_flag)) new_block->set(BlockBegin::parser_loop_header_flag); | ||||
769 | // Preserve certain flags for assertion checking | ||||
770 | if (block->is_set(BlockBegin::subroutine_entry_flag)) new_block->set(BlockBegin::subroutine_entry_flag); | ||||
771 | if (block->is_set(BlockBegin::exception_entry_flag)) new_block->set(BlockBegin::exception_entry_flag); | ||||
772 | |||||
773 | // copy was_visited_flag to allow early detection of bailouts | ||||
774 | // if a block that is used in a jsr has already been visited before, | ||||
775 | // it is shared between the normal control flow and a subroutine | ||||
776 | // BlockBegin::try_merge returns false when the flag is set, this leads | ||||
777 | // to a compilation bailout | ||||
778 | if (block->is_set(BlockBegin::was_visited_flag)) new_block->set(BlockBegin::was_visited_flag); | ||||
779 | |||||
780 | bci2block()->at_put(bci, new_block); | ||||
781 | block = new_block; | ||||
782 | } | ||||
783 | return block; | ||||
784 | } else { | ||||
785 | return bci2block()->at(bci); | ||||
786 | } | ||||
787 | } | ||||
788 | |||||
789 | |||||
790 | XHandlers* GraphBuilder::ScopeData::xhandlers() const { | ||||
791 | if (_jsr_xhandlers == NULL__null) { | ||||
792 | assert(!parsing_jsr(), "")do { if (!(!parsing_jsr())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 792, "assert(" "!parsing_jsr()" ") failed", ""); ::breakpoint (); } } while (0); | ||||
793 | return scope()->xhandlers(); | ||||
794 | } | ||||
795 | assert(parsing_jsr(), "")do { if (!(parsing_jsr())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 795, "assert(" "parsing_jsr()" ") failed", ""); ::breakpoint (); } } while (0); | ||||
796 | return _jsr_xhandlers; | ||||
797 | } | ||||
798 | |||||
799 | |||||
800 | void GraphBuilder::ScopeData::set_scope(IRScope* scope) { | ||||
801 | _scope = scope; | ||||
802 | bool parent_has_handler = false; | ||||
803 | if (parent() != NULL__null) { | ||||
804 | parent_has_handler = parent()->has_handler(); | ||||
805 | } | ||||
806 | _has_handler = parent_has_handler || scope->xhandlers()->has_handlers(); | ||||
807 | } | ||||
808 | |||||
809 | |||||
810 | void GraphBuilder::ScopeData::set_inline_cleanup_info(BlockBegin* block, | ||||
811 | Instruction* return_prev, | ||||
812 | ValueStack* return_state) { | ||||
813 | _cleanup_block = block; | ||||
814 | _cleanup_return_prev = return_prev; | ||||
815 | _cleanup_state = return_state; | ||||
816 | } | ||||
817 | |||||
818 | |||||
819 | void GraphBuilder::ScopeData::add_to_work_list(BlockBegin* block) { | ||||
820 | if (_work_list == NULL__null) { | ||||
821 | _work_list = new BlockList(); | ||||
822 | } | ||||
823 | |||||
824 | if (!block->is_set(BlockBegin::is_on_work_list_flag)) { | ||||
825 | // Do not start parsing the continuation block while in a | ||||
826 | // sub-scope | ||||
827 | if (parsing_jsr()) { | ||||
828 | if (block == jsr_continuation()) { | ||||
829 | return; | ||||
830 | } | ||||
831 | } else { | ||||
832 | if (block == continuation()) { | ||||
833 | return; | ||||
834 | } | ||||
835 | } | ||||
836 | block->set(BlockBegin::is_on_work_list_flag); | ||||
837 | _work_list->push(block); | ||||
838 | |||||
839 | sort_top_into_worklist(_work_list, block); | ||||
840 | } | ||||
841 | } | ||||
842 | |||||
843 | |||||
844 | void GraphBuilder::sort_top_into_worklist(BlockList* worklist, BlockBegin* top) { | ||||
845 | assert(worklist->top() == top, "")do { if (!(worklist->top() == top)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 845, "assert(" "worklist->top() == top" ") failed", ""); ::breakpoint(); } } while (0); | ||||
846 | // sort block descending into work list | ||||
847 | const int dfn = top->depth_first_number(); | ||||
848 | assert(dfn != -1, "unknown depth first number")do { if (!(dfn != -1)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 848, "assert(" "dfn != -1" ") failed", "unknown depth first number" ); ::breakpoint(); } } while (0); | ||||
849 | int i = worklist->length()-2; | ||||
850 | while (i >= 0) { | ||||
851 | BlockBegin* b = worklist->at(i); | ||||
852 | if (b->depth_first_number() < dfn) { | ||||
853 | worklist->at_put(i+1, b); | ||||
854 | } else { | ||||
855 | break; | ||||
856 | } | ||||
857 | i --; | ||||
858 | } | ||||
859 | if (i >= -1) worklist->at_put(i + 1, top); | ||||
860 | } | ||||
861 | |||||
862 | |||||
863 | BlockBegin* GraphBuilder::ScopeData::remove_from_work_list() { | ||||
864 | if (is_work_list_empty()) { | ||||
865 | return NULL__null; | ||||
866 | } | ||||
867 | return _work_list->pop(); | ||||
868 | } | ||||
869 | |||||
870 | |||||
871 | bool GraphBuilder::ScopeData::is_work_list_empty() const { | ||||
872 | return (_work_list == NULL__null || _work_list->length() == 0); | ||||
873 | } | ||||
874 | |||||
875 | |||||
876 | void GraphBuilder::ScopeData::setup_jsr_xhandlers() { | ||||
877 | assert(parsing_jsr(), "")do { if (!(parsing_jsr())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 877, "assert(" "parsing_jsr()" ") failed", ""); ::breakpoint (); } } while (0); | ||||
878 | // clone all the exception handlers from the scope | ||||
879 | XHandlers* handlers = new XHandlers(scope()->xhandlers()); | ||||
880 | const int n = handlers->length(); | ||||
881 | for (int i = 0; i < n; i++) { | ||||
882 | // The XHandlers need to be adjusted to dispatch to the cloned | ||||
883 | // handler block instead of the default one but the synthetic | ||||
884 | // unlocker needs to be handled specially. The synthetic unlocker | ||||
885 | // should be left alone since there can be only one and all code | ||||
886 | // should dispatch to the same one. | ||||
887 | XHandler* h = handlers->handler_at(i); | ||||
888 | assert(h->handler_bci() != SynchronizationEntryBCI, "must be real")do { if (!(h->handler_bci() != SynchronizationEntryBCI)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 888, "assert(" "h->handler_bci() != SynchronizationEntryBCI" ") failed", "must be real"); ::breakpoint(); } } while (0); | ||||
889 | h->set_entry_block(block_at(h->handler_bci())); | ||||
890 | } | ||||
891 | _jsr_xhandlers = handlers; | ||||
892 | } | ||||
893 | |||||
894 | |||||
895 | int GraphBuilder::ScopeData::num_returns() { | ||||
896 | if (parsing_jsr()) { | ||||
897 | return parent()->num_returns(); | ||||
898 | } | ||||
899 | return _num_returns; | ||||
900 | } | ||||
901 | |||||
902 | |||||
903 | void GraphBuilder::ScopeData::incr_num_returns() { | ||||
904 | if (parsing_jsr()) { | ||||
905 | parent()->incr_num_returns(); | ||||
906 | } else { | ||||
907 | ++_num_returns; | ||||
908 | } | ||||
909 | } | ||||
910 | |||||
911 | |||||
912 | // Implementation of GraphBuilder | ||||
913 | |||||
914 | #define INLINE_BAILOUT(msg){ inline_bailout(msg); return false; } { inline_bailout(msg); return false; } | ||||
915 | |||||
916 | |||||
917 | void GraphBuilder::load_constant() { | ||||
918 | ciConstant con = stream()->get_constant(); | ||||
919 | if (con.basic_type() == T_ILLEGAL) { | ||||
920 | // FIXME: an unresolved Dynamic constant can get here, | ||||
921 | // and that should not terminate the whole compilation. | ||||
922 | BAILOUT("could not resolve a constant"){ bailout("could not resolve a constant"); return; }; | ||||
923 | } else { | ||||
924 | ValueType* t = illegalType; | ||||
925 | ValueStack* patch_state = NULL__null; | ||||
926 | switch (con.basic_type()) { | ||||
927 | case T_BOOLEAN: t = new IntConstant (con.as_boolean()); break; | ||||
928 | case T_BYTE : t = new IntConstant (con.as_byte ()); break; | ||||
929 | case T_CHAR : t = new IntConstant (con.as_char ()); break; | ||||
930 | case T_SHORT : t = new IntConstant (con.as_short ()); break; | ||||
931 | case T_INT : t = new IntConstant (con.as_int ()); break; | ||||
932 | case T_LONG : t = new LongConstant (con.as_long ()); break; | ||||
933 | case T_FLOAT : t = new FloatConstant (con.as_float ()); break; | ||||
934 | case T_DOUBLE : t = new DoubleConstant (con.as_double ()); break; | ||||
935 | case T_ARRAY : t = new ArrayConstant (con.as_object ()->as_array ()); break; | ||||
936 | case T_OBJECT : | ||||
937 | { | ||||
938 | ciObject* obj = con.as_object(); | ||||
939 | if (!obj->is_loaded() | ||||
940 | || (PatchALot && obj->klass() != ciEnv::current()->String_klass())) { | ||||
941 | // A Class, MethodType, MethodHandle, or String. | ||||
942 | // Unloaded condy nodes show up as T_ILLEGAL, above. | ||||
943 | patch_state = copy_state_before(); | ||||
944 | t = new ObjectConstant(obj); | ||||
945 | } else { | ||||
946 | // Might be a Class, MethodType, MethodHandle, or Dynamic constant | ||||
947 | // result, which might turn out to be an array. | ||||
948 | if (obj->is_null_object()) | ||||
949 | t = objectNull; | ||||
950 | else if (obj->is_array()) | ||||
951 | t = new ArrayConstant(obj->as_array()); | ||||
952 | else | ||||
953 | t = new InstanceConstant(obj->as_instance()); | ||||
954 | } | ||||
955 | break; | ||||
956 | } | ||||
957 | default : ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 957); ::breakpoint(); } while (0); | ||||
958 | } | ||||
959 | Value x; | ||||
960 | if (patch_state != NULL__null) { | ||||
961 | x = new Constant(t, patch_state); | ||||
962 | } else { | ||||
963 | x = new Constant(t); | ||||
964 | } | ||||
965 | push(t, append(x)); | ||||
966 | } | ||||
967 | } | ||||
968 | |||||
969 | |||||
970 | void GraphBuilder::load_local(ValueType* type, int index) { | ||||
971 | Value x = state()->local_at(index); | ||||
972 | assert(x != NULL && !x->type()->is_illegal(), "access of illegal local variable")do { if (!(x != __null && !x->type()->is_illegal ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 972, "assert(" "x != __null && !x->type()->is_illegal()" ") failed", "access of illegal local variable"); ::breakpoint (); } } while (0); | ||||
973 | push(type, x); | ||||
974 | } | ||||
975 | |||||
976 | |||||
977 | void GraphBuilder::store_local(ValueType* type, int index) { | ||||
978 | Value x = pop(type); | ||||
979 | store_local(state(), x, index); | ||||
980 | } | ||||
981 | |||||
982 | |||||
983 | void GraphBuilder::store_local(ValueStack* state, Value x, int index) { | ||||
984 | if (parsing_jsr()) { | ||||
985 | // We need to do additional tracking of the location of the return | ||||
986 | // address for jsrs since we don't handle arbitrary jsr/ret | ||||
987 | // constructs. Here we are figuring out in which circumstances we | ||||
988 | // need to bail out. | ||||
989 | if (x->type()->is_address()) { | ||||
990 | scope_data()->set_jsr_return_address_local(index); | ||||
991 | |||||
992 | // Also check parent jsrs (if any) at this time to see whether | ||||
993 | // they are using this local. We don't handle skipping over a | ||||
994 | // ret. | ||||
995 | for (ScopeData* cur_scope_data = scope_data()->parent(); | ||||
996 | cur_scope_data != NULL__null && cur_scope_data->parsing_jsr() && cur_scope_data->scope() == scope(); | ||||
997 | cur_scope_data = cur_scope_data->parent()) { | ||||
998 | if (cur_scope_data->jsr_return_address_local() == index) { | ||||
999 | BAILOUT("subroutine overwrites return address from previous subroutine"){ bailout("subroutine overwrites return address from previous subroutine" ); return; }; | ||||
1000 | } | ||||
1001 | } | ||||
1002 | } else if (index == scope_data()->jsr_return_address_local()) { | ||||
1003 | scope_data()->set_jsr_return_address_local(-1); | ||||
1004 | } | ||||
1005 | } | ||||
1006 | |||||
1007 | state->store_local(index, round_fp(x)); | ||||
1008 | } | ||||
1009 | |||||
1010 | |||||
1011 | void GraphBuilder::load_indexed(BasicType type) { | ||||
1012 | // In case of in block code motion in range check elimination | ||||
1013 | ValueStack* state_before = copy_state_indexed_access(); | ||||
1014 | compilation()->set_has_access_indexed(true); | ||||
1015 | Value index = ipop(); | ||||
1016 | Value array = apop(); | ||||
1017 | Value length = NULL__null; | ||||
1018 | if (CSEArrayLength || | ||||
1019 | (array->as_Constant() != NULL__null) || | ||||
1020 | (array->as_AccessField() && array->as_AccessField()->field()->is_constant()) || | ||||
1021 | (array->as_NewArray() && array->as_NewArray()->length() && array->as_NewArray()->length()->type()->is_constant()) || | ||||
1022 | (array->as_NewMultiArray() && array->as_NewMultiArray()->dims()->at(0)->type()->is_constant())) { | ||||
1023 | length = append(new ArrayLength(array, state_before)); | ||||
1024 | } | ||||
1025 | push(as_ValueType(type), append(new LoadIndexed(array, index, length, type, state_before))); | ||||
1026 | } | ||||
1027 | |||||
1028 | |||||
1029 | void GraphBuilder::store_indexed(BasicType type) { | ||||
1030 | // In case of in block code motion in range check elimination | ||||
1031 | ValueStack* state_before = copy_state_indexed_access(); | ||||
1032 | compilation()->set_has_access_indexed(true); | ||||
1033 | Value value = pop(as_ValueType(type)); | ||||
1034 | Value index = ipop(); | ||||
1035 | Value array = apop(); | ||||
1036 | Value length = NULL__null; | ||||
1037 | if (CSEArrayLength || | ||||
1038 | (array->as_Constant() != NULL__null) || | ||||
1039 | (array->as_AccessField() && array->as_AccessField()->field()->is_constant()) || | ||||
1040 | (array->as_NewArray() && array->as_NewArray()->length() && array->as_NewArray()->length()->type()->is_constant()) || | ||||
1041 | (array->as_NewMultiArray() && array->as_NewMultiArray()->dims()->at(0)->type()->is_constant())) { | ||||
1042 | length = append(new ArrayLength(array, state_before)); | ||||
1043 | } | ||||
1044 | ciType* array_type = array->declared_type(); | ||||
1045 | bool check_boolean = false; | ||||
1046 | if (array_type != NULL__null) { | ||||
1047 | if (array_type->is_loaded() && | ||||
1048 | array_type->as_array_klass()->element_type()->basic_type() == T_BOOLEAN) { | ||||
1049 | assert(type == T_BYTE, "boolean store uses bastore")do { if (!(type == T_BYTE)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1049, "assert(" "type == T_BYTE" ") failed", "boolean store uses bastore" ); ::breakpoint(); } } while (0); | ||||
1050 | Value mask = append(new Constant(new IntConstant(1))); | ||||
1051 | value = append(new LogicOp(Bytecodes::_iand, value, mask)); | ||||
1052 | } | ||||
1053 | } else if (type == T_BYTE) { | ||||
1054 | check_boolean = true; | ||||
1055 | } | ||||
1056 | StoreIndexed* result = new StoreIndexed(array, index, length, type, value, state_before, check_boolean); | ||||
1057 | append(result); | ||||
1058 | _memory->store_value(value); | ||||
1059 | |||||
1060 | if (type == T_OBJECT && is_profiling()) { | ||||
1061 | // Note that we'd collect profile data in this method if we wanted it. | ||||
1062 | compilation()->set_would_profile(true); | ||||
1063 | |||||
1064 | if (profile_checkcasts()) { | ||||
1065 | result->set_profiled_method(method()); | ||||
1066 | result->set_profiled_bci(bci()); | ||||
1067 | result->set_should_profile(true); | ||||
1068 | } | ||||
1069 | } | ||||
1070 | } | ||||
1071 | |||||
1072 | |||||
1073 | void GraphBuilder::stack_op(Bytecodes::Code code) { | ||||
1074 | switch (code) { | ||||
1075 | case Bytecodes::_pop: | ||||
1076 | { state()->raw_pop(); | ||||
1077 | } | ||||
1078 | break; | ||||
1079 | case Bytecodes::_pop2: | ||||
1080 | { state()->raw_pop(); | ||||
1081 | state()->raw_pop(); | ||||
1082 | } | ||||
1083 | break; | ||||
1084 | case Bytecodes::_dup: | ||||
1085 | { Value w = state()->raw_pop(); | ||||
1086 | state()->raw_push(w); | ||||
1087 | state()->raw_push(w); | ||||
1088 | } | ||||
1089 | break; | ||||
1090 | case Bytecodes::_dup_x1: | ||||
1091 | { Value w1 = state()->raw_pop(); | ||||
1092 | Value w2 = state()->raw_pop(); | ||||
1093 | state()->raw_push(w1); | ||||
1094 | state()->raw_push(w2); | ||||
1095 | state()->raw_push(w1); | ||||
1096 | } | ||||
1097 | break; | ||||
1098 | case Bytecodes::_dup_x2: | ||||
1099 | { Value w1 = state()->raw_pop(); | ||||
1100 | Value w2 = state()->raw_pop(); | ||||
1101 | Value w3 = state()->raw_pop(); | ||||
1102 | state()->raw_push(w1); | ||||
1103 | state()->raw_push(w3); | ||||
1104 | state()->raw_push(w2); | ||||
1105 | state()->raw_push(w1); | ||||
1106 | } | ||||
1107 | break; | ||||
1108 | case Bytecodes::_dup2: | ||||
1109 | { Value w1 = state()->raw_pop(); | ||||
1110 | Value w2 = state()->raw_pop(); | ||||
1111 | state()->raw_push(w2); | ||||
1112 | state()->raw_push(w1); | ||||
1113 | state()->raw_push(w2); | ||||
1114 | state()->raw_push(w1); | ||||
1115 | } | ||||
1116 | break; | ||||
1117 | case Bytecodes::_dup2_x1: | ||||
1118 | { Value w1 = state()->raw_pop(); | ||||
1119 | Value w2 = state()->raw_pop(); | ||||
1120 | Value w3 = state()->raw_pop(); | ||||
1121 | state()->raw_push(w2); | ||||
1122 | state()->raw_push(w1); | ||||
1123 | state()->raw_push(w3); | ||||
1124 | state()->raw_push(w2); | ||||
1125 | state()->raw_push(w1); | ||||
1126 | } | ||||
1127 | break; | ||||
1128 | case Bytecodes::_dup2_x2: | ||||
1129 | { Value w1 = state()->raw_pop(); | ||||
1130 | Value w2 = state()->raw_pop(); | ||||
1131 | Value w3 = state()->raw_pop(); | ||||
1132 | Value w4 = state()->raw_pop(); | ||||
1133 | state()->raw_push(w2); | ||||
1134 | state()->raw_push(w1); | ||||
1135 | state()->raw_push(w4); | ||||
1136 | state()->raw_push(w3); | ||||
1137 | state()->raw_push(w2); | ||||
1138 | state()->raw_push(w1); | ||||
1139 | } | ||||
1140 | break; | ||||
1141 | case Bytecodes::_swap: | ||||
1142 | { Value w1 = state()->raw_pop(); | ||||
1143 | Value w2 = state()->raw_pop(); | ||||
1144 | state()->raw_push(w1); | ||||
1145 | state()->raw_push(w2); | ||||
1146 | } | ||||
1147 | break; | ||||
1148 | default: | ||||
1149 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1149); ::breakpoint(); } while (0); | ||||
1150 | break; | ||||
1151 | } | ||||
1152 | } | ||||
1153 | |||||
1154 | |||||
1155 | void GraphBuilder::arithmetic_op(ValueType* type, Bytecodes::Code code, ValueStack* state_before) { | ||||
1156 | Value y = pop(type); | ||||
1157 | Value x = pop(type); | ||||
1158 | Value res = new ArithmeticOp(code, x, y, state_before); | ||||
1159 | // Note: currently single-precision floating-point rounding on Intel is handled at the LIRGenerator level | ||||
1160 | res = append(res); | ||||
1161 | res = round_fp(res); | ||||
1162 | push(type, res); | ||||
1163 | } | ||||
1164 | |||||
1165 | |||||
1166 | void GraphBuilder::negate_op(ValueType* type) { | ||||
1167 | push(type, append(new NegateOp(pop(type)))); | ||||
1168 | } | ||||
1169 | |||||
1170 | |||||
1171 | void GraphBuilder::shift_op(ValueType* type, Bytecodes::Code code) { | ||||
1172 | Value s = ipop(); | ||||
1173 | Value x = pop(type); | ||||
1174 | // try to simplify | ||||
1175 | // Note: This code should go into the canonicalizer as soon as it can | ||||
1176 | // can handle canonicalized forms that contain more than one node. | ||||
1177 | if (CanonicalizeNodes && code == Bytecodes::_iushr) { | ||||
1178 | // pattern: x >>> s | ||||
1179 | IntConstant* s1 = s->type()->as_IntConstant(); | ||||
1180 | if (s1 != NULL__null) { | ||||
1181 | // pattern: x >>> s1, with s1 constant | ||||
1182 | ShiftOp* l = x->as_ShiftOp(); | ||||
1183 | if (l != NULL__null && l->op() == Bytecodes::_ishl) { | ||||
1184 | // pattern: (a << b) >>> s1 | ||||
1185 | IntConstant* s0 = l->y()->type()->as_IntConstant(); | ||||
1186 | if (s0 != NULL__null) { | ||||
1187 | // pattern: (a << s0) >>> s1 | ||||
1188 | const int s0c = s0->value() & 0x1F; // only the low 5 bits are significant for shifts | ||||
1189 | const int s1c = s1->value() & 0x1F; // only the low 5 bits are significant for shifts | ||||
1190 | if (s0c == s1c) { | ||||
1191 | if (s0c == 0) { | ||||
1192 | // pattern: (a << 0) >>> 0 => simplify to: a | ||||
1193 | ipush(l->x()); | ||||
1194 | } else { | ||||
1195 | // pattern: (a << s0c) >>> s0c => simplify to: a & m, with m constant | ||||
1196 | assert(0 < s0c && s0c < BitsPerInt, "adjust code below to handle corner cases")do { if (!(0 < s0c && s0c < BitsPerInt)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1196, "assert(" "0 < s0c && s0c < BitsPerInt" ") failed", "adjust code below to handle corner cases"); ::breakpoint (); } } while (0); | ||||
1197 | const int m = (1 << (BitsPerInt - s0c)) - 1; | ||||
1198 | Value s = append(new Constant(new IntConstant(m))); | ||||
1199 | ipush(append(new LogicOp(Bytecodes::_iand, l->x(), s))); | ||||
1200 | } | ||||
1201 | return; | ||||
1202 | } | ||||
1203 | } | ||||
1204 | } | ||||
1205 | } | ||||
1206 | } | ||||
1207 | // could not simplify | ||||
1208 | push(type, append(new ShiftOp(code, x, s))); | ||||
1209 | } | ||||
1210 | |||||
1211 | |||||
1212 | void GraphBuilder::logic_op(ValueType* type, Bytecodes::Code code) { | ||||
1213 | Value y = pop(type); | ||||
1214 | Value x = pop(type); | ||||
1215 | push(type, append(new LogicOp(code, x, y))); | ||||
1216 | } | ||||
1217 | |||||
1218 | |||||
1219 | void GraphBuilder::compare_op(ValueType* type, Bytecodes::Code code) { | ||||
1220 | ValueStack* state_before = copy_state_before(); | ||||
1221 | Value y = pop(type); | ||||
1222 | Value x = pop(type); | ||||
1223 | ipush(append(new CompareOp(code, x, y, state_before))); | ||||
1224 | } | ||||
1225 | |||||
1226 | |||||
1227 | void GraphBuilder::convert(Bytecodes::Code op, BasicType from, BasicType to) { | ||||
1228 | push(as_ValueType(to), append(new Convert(op, pop(as_ValueType(from)), as_ValueType(to)))); | ||||
1229 | } | ||||
1230 | |||||
1231 | |||||
1232 | void GraphBuilder::increment() { | ||||
1233 | int index = stream()->get_index(); | ||||
1234 | int delta = stream()->is_wide() ? (signed short)Bytes::get_Java_u2(stream()->cur_bcp() + 4) : (signed char)(stream()->cur_bcp()[2]); | ||||
1235 | load_local(intType, index); | ||||
1236 | ipush(append(new Constant(new IntConstant(delta)))); | ||||
1237 | arithmetic_op(intType, Bytecodes::_iadd); | ||||
1238 | store_local(intType, index); | ||||
1239 | } | ||||
1240 | |||||
1241 | |||||
1242 | void GraphBuilder::_goto(int from_bci, int to_bci) { | ||||
1243 | Goto *x = new Goto(block_at(to_bci), to_bci <= from_bci); | ||||
1244 | if (is_profiling()) { | ||||
1245 | compilation()->set_would_profile(true); | ||||
1246 | x->set_profiled_bci(bci()); | ||||
1247 | if (profile_branches()) { | ||||
1248 | x->set_profiled_method(method()); | ||||
1249 | x->set_should_profile(true); | ||||
1250 | } | ||||
1251 | } | ||||
1252 | append(x); | ||||
1253 | } | ||||
1254 | |||||
1255 | |||||
1256 | void GraphBuilder::if_node(Value x, If::Condition cond, Value y, ValueStack* state_before) { | ||||
1257 | BlockBegin* tsux = block_at(stream()->get_dest()); | ||||
1258 | BlockBegin* fsux = block_at(stream()->next_bci()); | ||||
1259 | bool is_bb = tsux->bci() < stream()->cur_bci() || fsux->bci() < stream()->cur_bci(); | ||||
1260 | // In case of loop invariant code motion or predicate insertion | ||||
1261 | // before the body of a loop the state is needed | ||||
1262 | Instruction *i = append(new If(x, cond, false, y, tsux, fsux, (is_bb || compilation()->is_optimistic()) ? state_before : NULL__null, is_bb)); | ||||
1263 | |||||
1264 | assert(i->as_Goto() == NULL ||do { if (!(i->as_Goto() == __null || (i->as_Goto()-> sux_at(0) == tsux && i->as_Goto()->is_safepoint () == tsux->bci() < stream()->cur_bci()) || (i->as_Goto ()->sux_at(0) == fsux && i->as_Goto()->is_safepoint () == fsux->bci() < stream()->cur_bci()))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1267, "assert(" "i->as_Goto() == __null || (i->as_Goto()->sux_at(0) == tsux && i->as_Goto()->is_safepoint() == tsux->bci() < stream()->cur_bci()) || (i->as_Goto()->sux_at(0) == fsux && i->as_Goto()->is_safepoint() == fsux->bci() < stream()->cur_bci())" ") failed", "safepoint state of Goto returned by canonicalizer incorrect" ); ::breakpoint(); } } while (0) | ||||
1265 | (i->as_Goto()->sux_at(0) == tsux && i->as_Goto()->is_safepoint() == tsux->bci() < stream()->cur_bci()) ||do { if (!(i->as_Goto() == __null || (i->as_Goto()-> sux_at(0) == tsux && i->as_Goto()->is_safepoint () == tsux->bci() < stream()->cur_bci()) || (i->as_Goto ()->sux_at(0) == fsux && i->as_Goto()->is_safepoint () == fsux->bci() < stream()->cur_bci()))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1267, "assert(" "i->as_Goto() == __null || (i->as_Goto()->sux_at(0) == tsux && i->as_Goto()->is_safepoint() == tsux->bci() < stream()->cur_bci()) || (i->as_Goto()->sux_at(0) == fsux && i->as_Goto()->is_safepoint() == fsux->bci() < stream()->cur_bci())" ") failed", "safepoint state of Goto returned by canonicalizer incorrect" ); ::breakpoint(); } } while (0) | ||||
1266 | (i->as_Goto()->sux_at(0) == fsux && i->as_Goto()->is_safepoint() == fsux->bci() < stream()->cur_bci()),do { if (!(i->as_Goto() == __null || (i->as_Goto()-> sux_at(0) == tsux && i->as_Goto()->is_safepoint () == tsux->bci() < stream()->cur_bci()) || (i->as_Goto ()->sux_at(0) == fsux && i->as_Goto()->is_safepoint () == fsux->bci() < stream()->cur_bci()))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1267, "assert(" "i->as_Goto() == __null || (i->as_Goto()->sux_at(0) == tsux && i->as_Goto()->is_safepoint() == tsux->bci() < stream()->cur_bci()) || (i->as_Goto()->sux_at(0) == fsux && i->as_Goto()->is_safepoint() == fsux->bci() < stream()->cur_bci())" ") failed", "safepoint state of Goto returned by canonicalizer incorrect" ); ::breakpoint(); } } while (0) | ||||
1267 | "safepoint state of Goto returned by canonicalizer incorrect")do { if (!(i->as_Goto() == __null || (i->as_Goto()-> sux_at(0) == tsux && i->as_Goto()->is_safepoint () == tsux->bci() < stream()->cur_bci()) || (i->as_Goto ()->sux_at(0) == fsux && i->as_Goto()->is_safepoint () == fsux->bci() < stream()->cur_bci()))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1267, "assert(" "i->as_Goto() == __null || (i->as_Goto()->sux_at(0) == tsux && i->as_Goto()->is_safepoint() == tsux->bci() < stream()->cur_bci()) || (i->as_Goto()->sux_at(0) == fsux && i->as_Goto()->is_safepoint() == fsux->bci() < stream()->cur_bci())" ") failed", "safepoint state of Goto returned by canonicalizer incorrect" ); ::breakpoint(); } } while (0); | ||||
1268 | |||||
1269 | if (is_profiling()) { | ||||
1270 | If* if_node = i->as_If(); | ||||
1271 | if (if_node != NULL__null) { | ||||
1272 | // Note that we'd collect profile data in this method if we wanted it. | ||||
1273 | compilation()->set_would_profile(true); | ||||
1274 | // At level 2 we need the proper bci to count backedges | ||||
1275 | if_node->set_profiled_bci(bci()); | ||||
1276 | if (profile_branches()) { | ||||
1277 | // Successors can be rotated by the canonicalizer, check for this case. | ||||
1278 | if_node->set_profiled_method(method()); | ||||
1279 | if_node->set_should_profile(true); | ||||
1280 | if (if_node->tsux() == fsux) { | ||||
1281 | if_node->set_swapped(true); | ||||
1282 | } | ||||
1283 | } | ||||
1284 | return; | ||||
1285 | } | ||||
1286 | |||||
1287 | // Check if this If was reduced to Goto. | ||||
1288 | Goto *goto_node = i->as_Goto(); | ||||
1289 | if (goto_node != NULL__null) { | ||||
1290 | compilation()->set_would_profile(true); | ||||
1291 | goto_node->set_profiled_bci(bci()); | ||||
1292 | if (profile_branches()) { | ||||
1293 | goto_node->set_profiled_method(method()); | ||||
1294 | goto_node->set_should_profile(true); | ||||
1295 | // Find out which successor is used. | ||||
1296 | if (goto_node->default_sux() == tsux) { | ||||
1297 | goto_node->set_direction(Goto::taken); | ||||
1298 | } else if (goto_node->default_sux() == fsux) { | ||||
1299 | goto_node->set_direction(Goto::not_taken); | ||||
1300 | } else { | ||||
1301 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1301); ::breakpoint(); } while (0); | ||||
1302 | } | ||||
1303 | } | ||||
1304 | return; | ||||
1305 | } | ||||
1306 | } | ||||
1307 | } | ||||
1308 | |||||
1309 | |||||
1310 | void GraphBuilder::if_zero(ValueType* type, If::Condition cond) { | ||||
1311 | Value y = append(new Constant(intZero)); | ||||
1312 | ValueStack* state_before = copy_state_before(); | ||||
1313 | Value x = ipop(); | ||||
1314 | if_node(x, cond, y, state_before); | ||||
1315 | } | ||||
1316 | |||||
1317 | |||||
1318 | void GraphBuilder::if_null(ValueType* type, If::Condition cond) { | ||||
1319 | Value y = append(new Constant(objectNull)); | ||||
1320 | ValueStack* state_before = copy_state_before(); | ||||
1321 | Value x = apop(); | ||||
1322 | if_node(x, cond, y, state_before); | ||||
1323 | } | ||||
1324 | |||||
1325 | |||||
1326 | void GraphBuilder::if_same(ValueType* type, If::Condition cond) { | ||||
1327 | ValueStack* state_before = copy_state_before(); | ||||
1328 | Value y = pop(type); | ||||
1329 | Value x = pop(type); | ||||
1330 | if_node(x, cond, y, state_before); | ||||
1331 | } | ||||
1332 | |||||
1333 | |||||
1334 | void GraphBuilder::jsr(int dest) { | ||||
1335 | // We only handle well-formed jsrs (those which are "block-structured"). | ||||
1336 | // If the bytecodes are strange (jumping out of a jsr block) then we | ||||
1337 | // might end up trying to re-parse a block containing a jsr which | ||||
1338 | // has already been activated. Watch for this case and bail out. | ||||
1339 | for (ScopeData* cur_scope_data = scope_data(); | ||||
1340 | cur_scope_data != NULL__null && cur_scope_data->parsing_jsr() && cur_scope_data->scope() == scope(); | ||||
1341 | cur_scope_data = cur_scope_data->parent()) { | ||||
1342 | if (cur_scope_data->jsr_entry_bci() == dest) { | ||||
1343 | BAILOUT("too-complicated jsr/ret structure"){ bailout("too-complicated jsr/ret structure"); return; }; | ||||
1344 | } | ||||
1345 | } | ||||
1346 | |||||
1347 | push(addressType, append(new Constant(new AddressConstant(next_bci())))); | ||||
1348 | if (!try_inline_jsr(dest)) { | ||||
1349 | return; // bailed out while parsing and inlining subroutine | ||||
1350 | } | ||||
1351 | } | ||||
1352 | |||||
1353 | |||||
1354 | void GraphBuilder::ret(int local_index) { | ||||
1355 | if (!parsing_jsr()) BAILOUT("ret encountered while not parsing subroutine"){ bailout("ret encountered while not parsing subroutine"); return ; }; | ||||
1356 | |||||
1357 | if (local_index != scope_data()->jsr_return_address_local()) { | ||||
1358 | BAILOUT("can not handle complicated jsr/ret constructs"){ bailout("can not handle complicated jsr/ret constructs"); return ; }; | ||||
1359 | } | ||||
1360 | |||||
1361 | // Rets simply become (NON-SAFEPOINT) gotos to the jsr continuation | ||||
1362 | append(new Goto(scope_data()->jsr_continuation(), false)); | ||||
1363 | } | ||||
1364 | |||||
1365 | |||||
1366 | void GraphBuilder::table_switch() { | ||||
1367 | Bytecode_tableswitch sw(stream()); | ||||
1368 | const int l = sw.length(); | ||||
1369 | if (CanonicalizeNodes && l == 1 && compilation()->env()->comp_level() != CompLevel_full_profile) { | ||||
1370 | // total of 2 successors => use If instead of switch | ||||
1371 | // Note: This code should go into the canonicalizer as soon as it can | ||||
1372 | // can handle canonicalized forms that contain more than one node. | ||||
1373 | Value key = append(new Constant(new IntConstant(sw.low_key()))); | ||||
1374 | BlockBegin* tsux = block_at(bci() + sw.dest_offset_at(0)); | ||||
1375 | BlockBegin* fsux = block_at(bci() + sw.default_offset()); | ||||
1376 | bool is_bb = tsux->bci() < bci() || fsux->bci() < bci(); | ||||
1377 | // In case of loop invariant code motion or predicate insertion | ||||
1378 | // before the body of a loop the state is needed | ||||
1379 | ValueStack* state_before = copy_state_if_bb(is_bb); | ||||
1380 | append(new If(ipop(), If::eql, true, key, tsux, fsux, state_before, is_bb)); | ||||
1381 | } else { | ||||
1382 | // collect successors | ||||
1383 | BlockList* sux = new BlockList(l + 1, NULL__null); | ||||
1384 | int i; | ||||
1385 | bool has_bb = false; | ||||
1386 | for (i = 0; i < l; i++) { | ||||
1387 | sux->at_put(i, block_at(bci() + sw.dest_offset_at(i))); | ||||
1388 | if (sw.dest_offset_at(i) < 0) has_bb = true; | ||||
1389 | } | ||||
1390 | // add default successor | ||||
1391 | if (sw.default_offset() < 0) has_bb = true; | ||||
1392 | sux->at_put(i, block_at(bci() + sw.default_offset())); | ||||
1393 | // In case of loop invariant code motion or predicate insertion | ||||
1394 | // before the body of a loop the state is needed | ||||
1395 | ValueStack* state_before = copy_state_if_bb(has_bb); | ||||
1396 | Instruction* res = append(new TableSwitch(ipop(), sux, sw.low_key(), state_before, has_bb)); | ||||
1397 | #ifdef ASSERT1 | ||||
1398 | if (res->as_Goto()) { | ||||
1399 | for (i = 0; i < l; i++) { | ||||
1400 | if (sux->at(i) == res->as_Goto()->sux_at(0)) { | ||||
1401 | assert(res->as_Goto()->is_safepoint() == sw.dest_offset_at(i) < 0, "safepoint state of Goto returned by canonicalizer incorrect")do { if (!(res->as_Goto()->is_safepoint() == sw.dest_offset_at (i) < 0)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1401, "assert(" "res->as_Goto()->is_safepoint() == sw.dest_offset_at(i) < 0" ") failed", "safepoint state of Goto returned by canonicalizer incorrect" ); ::breakpoint(); } } while (0); | ||||
1402 | } | ||||
1403 | } | ||||
1404 | } | ||||
1405 | #endif | ||||
1406 | } | ||||
1407 | } | ||||
1408 | |||||
1409 | |||||
1410 | void GraphBuilder::lookup_switch() { | ||||
1411 | Bytecode_lookupswitch sw(stream()); | ||||
1412 | const int l = sw.number_of_pairs(); | ||||
1413 | if (CanonicalizeNodes && l == 1 && compilation()->env()->comp_level() != CompLevel_full_profile) { | ||||
1414 | // total of 2 successors => use If instead of switch | ||||
1415 | // Note: This code should go into the canonicalizer as soon as it can | ||||
1416 | // can handle canonicalized forms that contain more than one node. | ||||
1417 | // simplify to If | ||||
1418 | LookupswitchPair pair = sw.pair_at(0); | ||||
1419 | Value key = append(new Constant(new IntConstant(pair.match()))); | ||||
1420 | BlockBegin* tsux = block_at(bci() + pair.offset()); | ||||
1421 | BlockBegin* fsux = block_at(bci() + sw.default_offset()); | ||||
1422 | bool is_bb = tsux->bci() < bci() || fsux->bci() < bci(); | ||||
1423 | // In case of loop invariant code motion or predicate insertion | ||||
1424 | // before the body of a loop the state is needed | ||||
1425 | ValueStack* state_before = copy_state_if_bb(is_bb);; | ||||
1426 | append(new If(ipop(), If::eql, true, key, tsux, fsux, state_before, is_bb)); | ||||
1427 | } else { | ||||
1428 | // collect successors & keys | ||||
1429 | BlockList* sux = new BlockList(l + 1, NULL__null); | ||||
1430 | intArray* keys = new intArray(l, l, 0); | ||||
1431 | int i; | ||||
1432 | bool has_bb = false; | ||||
1433 | for (i = 0; i < l; i++) { | ||||
1434 | LookupswitchPair pair = sw.pair_at(i); | ||||
1435 | if (pair.offset() < 0) has_bb = true; | ||||
1436 | sux->at_put(i, block_at(bci() + pair.offset())); | ||||
1437 | keys->at_put(i, pair.match()); | ||||
1438 | } | ||||
1439 | // add default successor | ||||
1440 | if (sw.default_offset() < 0) has_bb = true; | ||||
1441 | sux->at_put(i, block_at(bci() + sw.default_offset())); | ||||
1442 | // In case of loop invariant code motion or predicate insertion | ||||
1443 | // before the body of a loop the state is needed | ||||
1444 | ValueStack* state_before = copy_state_if_bb(has_bb); | ||||
1445 | Instruction* res = append(new LookupSwitch(ipop(), sux, keys, state_before, has_bb)); | ||||
1446 | #ifdef ASSERT1 | ||||
1447 | if (res->as_Goto()) { | ||||
1448 | for (i = 0; i < l; i++) { | ||||
1449 | if (sux->at(i) == res->as_Goto()->sux_at(0)) { | ||||
1450 | assert(res->as_Goto()->is_safepoint() == sw.pair_at(i).offset() < 0, "safepoint state of Goto returned by canonicalizer incorrect")do { if (!(res->as_Goto()->is_safepoint() == sw.pair_at (i).offset() < 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1450, "assert(" "res->as_Goto()->is_safepoint() == sw.pair_at(i).offset() < 0" ") failed", "safepoint state of Goto returned by canonicalizer incorrect" ); ::breakpoint(); } } while (0); | ||||
1451 | } | ||||
1452 | } | ||||
1453 | } | ||||
1454 | #endif | ||||
1455 | } | ||||
1456 | } | ||||
1457 | |||||
1458 | void GraphBuilder::call_register_finalizer() { | ||||
1459 | // If the receiver requires finalization then emit code to perform | ||||
1460 | // the registration on return. | ||||
1461 | |||||
1462 | // Gather some type information about the receiver | ||||
1463 | Value receiver = state()->local_at(0); | ||||
1464 | assert(receiver != NULL, "must have a receiver")do { if (!(receiver != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1464, "assert(" "receiver != __null" ") failed", "must have a receiver" ); ::breakpoint(); } } while (0); | ||||
1465 | ciType* declared_type = receiver->declared_type(); | ||||
1466 | ciType* exact_type = receiver->exact_type(); | ||||
1467 | if (exact_type == NULL__null && | ||||
1468 | receiver->as_Local() && | ||||
1469 | receiver->as_Local()->java_index() == 0) { | ||||
1470 | ciInstanceKlass* ik = compilation()->method()->holder(); | ||||
1471 | if (ik->is_final()) { | ||||
1472 | exact_type = ik; | ||||
1473 | } else if (UseCHA && !(ik->has_subklass() || ik->is_interface())) { | ||||
1474 | // test class is leaf class | ||||
1475 | compilation()->dependency_recorder()->assert_leaf_type(ik); | ||||
1476 | exact_type = ik; | ||||
1477 | } else { | ||||
1478 | declared_type = ik; | ||||
1479 | } | ||||
1480 | } | ||||
1481 | |||||
1482 | // see if we know statically that registration isn't required | ||||
1483 | bool needs_check = true; | ||||
1484 | if (exact_type != NULL__null) { | ||||
1485 | needs_check = exact_type->as_instance_klass()->has_finalizer(); | ||||
1486 | } else if (declared_type != NULL__null) { | ||||
1487 | ciInstanceKlass* ik = declared_type->as_instance_klass(); | ||||
1488 | if (!Dependencies::has_finalizable_subclass(ik)) { | ||||
1489 | compilation()->dependency_recorder()->assert_has_no_finalizable_subclasses(ik); | ||||
1490 | needs_check = false; | ||||
1491 | } | ||||
1492 | } | ||||
1493 | |||||
1494 | if (needs_check) { | ||||
1495 | // Perform the registration of finalizable objects. | ||||
1496 | ValueStack* state_before = copy_state_for_exception(); | ||||
1497 | load_local(objectType, 0); | ||||
1498 | append_split(new Intrinsic(voidType, vmIntrinsics::_Object_init, | ||||
1499 | state()->pop_arguments(1), | ||||
1500 | true, state_before, true)); | ||||
1501 | } | ||||
1502 | } | ||||
1503 | |||||
1504 | |||||
1505 | void GraphBuilder::method_return(Value x, bool ignore_return) { | ||||
1506 | if (RegisterFinalizersAtInit && | ||||
1507 | method()->intrinsic_id() == vmIntrinsics::_Object_init) { | ||||
1508 | call_register_finalizer(); | ||||
1509 | } | ||||
1510 | |||||
1511 | // The conditions for a memory barrier are described in Parse::do_exits(). | ||||
1512 | bool need_mem_bar = false; | ||||
1513 | if (method()->name() == ciSymbols::object_initializer_name() && | ||||
1514 | (scope()->wrote_final() || | ||||
1515 | (AlwaysSafeConstructors && scope()->wrote_fields()) || | ||||
1516 | (support_IRIW_for_not_multiple_copy_atomic_cpu && scope()->wrote_volatile()))) { | ||||
1517 | need_mem_bar = true; | ||||
1518 | } | ||||
1519 | |||||
1520 | BasicType bt = method()->return_type()->basic_type(); | ||||
1521 | switch (bt) { | ||||
1522 | case T_BYTE: | ||||
1523 | { | ||||
1524 | Value shift = append(new Constant(new IntConstant(24))); | ||||
1525 | x = append(new ShiftOp(Bytecodes::_ishl, x, shift)); | ||||
1526 | x = append(new ShiftOp(Bytecodes::_ishr, x, shift)); | ||||
1527 | break; | ||||
1528 | } | ||||
1529 | case T_SHORT: | ||||
1530 | { | ||||
1531 | Value shift = append(new Constant(new IntConstant(16))); | ||||
1532 | x = append(new ShiftOp(Bytecodes::_ishl, x, shift)); | ||||
1533 | x = append(new ShiftOp(Bytecodes::_ishr, x, shift)); | ||||
1534 | break; | ||||
1535 | } | ||||
1536 | case T_CHAR: | ||||
1537 | { | ||||
1538 | Value mask = append(new Constant(new IntConstant(0xFFFF))); | ||||
1539 | x = append(new LogicOp(Bytecodes::_iand, x, mask)); | ||||
1540 | break; | ||||
1541 | } | ||||
1542 | case T_BOOLEAN: | ||||
1543 | { | ||||
1544 | Value mask = append(new Constant(new IntConstant(1))); | ||||
1545 | x = append(new LogicOp(Bytecodes::_iand, x, mask)); | ||||
1546 | break; | ||||
1547 | } | ||||
1548 | default: | ||||
1549 | break; | ||||
1550 | } | ||||
1551 | |||||
1552 | // Check to see whether we are inlining. If so, Return | ||||
1553 | // instructions become Gotos to the continuation point. | ||||
1554 | if (continuation() != NULL__null) { | ||||
1555 | |||||
1556 | int invoke_bci = state()->caller_state()->bci(); | ||||
1557 | |||||
1558 | if (x != NULL__null && !ignore_return) { | ||||
1559 | ciMethod* caller = state()->scope()->caller()->method(); | ||||
1560 | Bytecodes::Code invoke_raw_bc = caller->raw_code_at_bci(invoke_bci); | ||||
1561 | if (invoke_raw_bc == Bytecodes::_invokehandle || invoke_raw_bc == Bytecodes::_invokedynamic) { | ||||
1562 | ciType* declared_ret_type = caller->get_declared_signature_at_bci(invoke_bci)->return_type(); | ||||
1563 | if (declared_ret_type->is_klass() && x->exact_type() == NULL__null && | ||||
1564 | x->declared_type() != declared_ret_type && declared_ret_type != compilation()->env()->Object_klass()) { | ||||
1565 | x = append(new TypeCast(declared_ret_type->as_klass(), x, copy_state_before())); | ||||
1566 | } | ||||
1567 | } | ||||
1568 | } | ||||
1569 | |||||
1570 | assert(!method()->is_synchronized() || InlineSynchronizedMethods, "can not inline synchronized methods yet")do { if (!(!method()->is_synchronized() || InlineSynchronizedMethods )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1570, "assert(" "!method()->is_synchronized() || InlineSynchronizedMethods" ") failed", "can not inline synchronized methods yet"); ::breakpoint (); } } while (0); | ||||
1571 | |||||
1572 | if (compilation()->env()->dtrace_method_probes()) { | ||||
1573 | // Report exit from inline methods | ||||
1574 | Values* args = new Values(1); | ||||
1575 | args->push(append(new Constant(new MethodConstant(method())))); | ||||
1576 | append(new RuntimeCall(voidType, "dtrace_method_exit", CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit)((address)((address_word)(SharedRuntime::dtrace_method_exit)) ), args)); | ||||
1577 | } | ||||
1578 | |||||
1579 | // If the inlined method is synchronized, the monitor must be | ||||
1580 | // released before we jump to the continuation block. | ||||
1581 | if (method()->is_synchronized()) { | ||||
1582 | assert(state()->locks_size() == 1, "receiver must be locked here")do { if (!(state()->locks_size() == 1)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1582, "assert(" "state()->locks_size() == 1" ") failed", "receiver must be locked here"); ::breakpoint(); } } while ( 0); | ||||
1583 | monitorexit(state()->lock_at(0), SynchronizationEntryBCI); | ||||
1584 | } | ||||
1585 | |||||
1586 | if (need_mem_bar) { | ||||
1587 | append(new MemBar(lir_membar_storestore)); | ||||
1588 | } | ||||
1589 | |||||
1590 | // State at end of inlined method is the state of the caller | ||||
1591 | // without the method parameters on stack, including the | ||||
1592 | // return value, if any, of the inlined method on operand stack. | ||||
1593 | set_state(state()->caller_state()->copy_for_parsing()); | ||||
1594 | if (x != NULL__null) { | ||||
1595 | if (!ignore_return) { | ||||
1596 | state()->push(x->type(), x); | ||||
1597 | } | ||||
1598 | if (profile_return() && x->type()->is_object_kind()) { | ||||
1599 | ciMethod* caller = state()->scope()->method(); | ||||
1600 | profile_return_type(x, method(), caller, invoke_bci); | ||||
1601 | } | ||||
1602 | } | ||||
1603 | Goto* goto_callee = new Goto(continuation(), false); | ||||
1604 | |||||
1605 | // See whether this is the first return; if so, store off some | ||||
1606 | // of the state for later examination | ||||
1607 | if (num_returns() == 0) { | ||||
1608 | set_inline_cleanup_info(); | ||||
1609 | } | ||||
1610 | |||||
1611 | // The current bci() is in the wrong scope, so use the bci() of | ||||
1612 | // the continuation point. | ||||
1613 | append_with_bci(goto_callee, scope_data()->continuation()->bci()); | ||||
1614 | incr_num_returns(); | ||||
1615 | return; | ||||
1616 | } | ||||
1617 | |||||
1618 | state()->truncate_stack(0); | ||||
1619 | if (method()->is_synchronized()) { | ||||
1620 | // perform the unlocking before exiting the method | ||||
1621 | Value receiver; | ||||
1622 | if (!method()->is_static()) { | ||||
1623 | receiver = _initial_state->local_at(0); | ||||
1624 | } else { | ||||
1625 | receiver = append(new Constant(new ClassConstant(method()->holder()))); | ||||
1626 | } | ||||
1627 | append_split(new MonitorExit(receiver, state()->unlock())); | ||||
1628 | } | ||||
1629 | |||||
1630 | if (need_mem_bar) { | ||||
1631 | append(new MemBar(lir_membar_storestore)); | ||||
1632 | } | ||||
1633 | |||||
1634 | assert(!ignore_return, "Ignoring return value works only for inlining")do { if (!(!ignore_return)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1634, "assert(" "!ignore_return" ") failed", "Ignoring return value works only for inlining" ); ::breakpoint(); } } while (0); | ||||
1635 | append(new Return(x)); | ||||
1636 | } | ||||
1637 | |||||
1638 | Value GraphBuilder::make_constant(ciConstant field_value, ciField* field) { | ||||
1639 | if (!field_value.is_valid()) return NULL__null; | ||||
1640 | |||||
1641 | BasicType field_type = field_value.basic_type(); | ||||
1642 | ValueType* value = as_ValueType(field_value); | ||||
1643 | |||||
1644 | // Attach dimension info to stable arrays. | ||||
1645 | if (FoldStableValues && | ||||
1646 | field->is_stable() && field_type == T_ARRAY && !field_value.is_null_or_zero()) { | ||||
1647 | ciArray* array = field_value.as_object()->as_array(); | ||||
1648 | jint dimension = field->type()->as_array_klass()->dimension(); | ||||
1649 | value = new StableArrayConstant(array, dimension); | ||||
1650 | } | ||||
1651 | |||||
1652 | switch (field_type) { | ||||
1653 | case T_ARRAY: | ||||
1654 | case T_OBJECT: | ||||
1655 | if (field_value.as_object()->should_be_constant()) { | ||||
1656 | return new Constant(value); | ||||
1657 | } | ||||
1658 | return NULL__null; // Not a constant. | ||||
1659 | default: | ||||
1660 | return new Constant(value); | ||||
1661 | } | ||||
1662 | } | ||||
1663 | |||||
1664 | void GraphBuilder::access_field(Bytecodes::Code code) { | ||||
1665 | bool will_link; | ||||
1666 | ciField* field = stream()->get_field(will_link); | ||||
1667 | ciInstanceKlass* holder = field->holder(); | ||||
1668 | BasicType field_type = field->type()->basic_type(); | ||||
1669 | ValueType* type = as_ValueType(field_type); | ||||
1670 | // call will_link again to determine if the field is valid. | ||||
1671 | const bool needs_patching = !holder->is_loaded() || | ||||
1672 | !field->will_link(method(), code) || | ||||
1673 | PatchALot; | ||||
1674 | |||||
1675 | ValueStack* state_before = NULL__null; | ||||
1676 | if (!holder->is_initialized() || needs_patching) { | ||||
1677 | // save state before instruction for debug info when | ||||
1678 | // deoptimization happens during patching | ||||
1679 | state_before = copy_state_before(); | ||||
1680 | } | ||||
1681 | |||||
1682 | Value obj = NULL__null; | ||||
1683 | if (code == Bytecodes::_getstatic || code == Bytecodes::_putstatic) { | ||||
1684 | if (state_before != NULL__null) { | ||||
1685 | // build a patching constant | ||||
1686 | obj = new Constant(new InstanceConstant(holder->java_mirror()), state_before); | ||||
1687 | } else { | ||||
1688 | obj = new Constant(new InstanceConstant(holder->java_mirror())); | ||||
1689 | } | ||||
1690 | } | ||||
1691 | |||||
1692 | if (field->is_final() && (code == Bytecodes::_putfield)) { | ||||
1693 | scope()->set_wrote_final(); | ||||
1694 | } | ||||
1695 | |||||
1696 | if (code == Bytecodes::_putfield) { | ||||
1697 | scope()->set_wrote_fields(); | ||||
1698 | if (field->is_volatile()) { | ||||
1699 | scope()->set_wrote_volatile(); | ||||
1700 | } | ||||
1701 | } | ||||
1702 | |||||
1703 | const int offset = !needs_patching ? field->offset() : -1; | ||||
1704 | switch (code) { | ||||
1705 | case Bytecodes::_getstatic: { | ||||
1706 | // check for compile-time constants, i.e., initialized static final fields | ||||
1707 | Value constant = NULL__null; | ||||
1708 | if (field->is_static_constant() && !PatchALot) { | ||||
1709 | ciConstant field_value = field->constant_value(); | ||||
1710 | assert(!field->is_stable() || !field_value.is_null_or_zero(),do { if (!(!field->is_stable() || !field_value.is_null_or_zero ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1711, "assert(" "!field->is_stable() || !field_value.is_null_or_zero()" ") failed", "stable static w/ default value shouldn't be a constant" ); ::breakpoint(); } } while (0) | ||||
1711 | "stable static w/ default value shouldn't be a constant")do { if (!(!field->is_stable() || !field_value.is_null_or_zero ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1711, "assert(" "!field->is_stable() || !field_value.is_null_or_zero()" ") failed", "stable static w/ default value shouldn't be a constant" ); ::breakpoint(); } } while (0); | ||||
1712 | constant = make_constant(field_value, field); | ||||
1713 | } | ||||
1714 | if (constant != NULL__null) { | ||||
1715 | push(type, append(constant)); | ||||
1716 | } else { | ||||
1717 | if (state_before == NULL__null) { | ||||
1718 | state_before = copy_state_for_exception(); | ||||
1719 | } | ||||
1720 | push(type, append(new LoadField(append(obj), offset, field, true, | ||||
1721 | state_before, needs_patching))); | ||||
1722 | } | ||||
1723 | break; | ||||
1724 | } | ||||
1725 | case Bytecodes::_putstatic: { | ||||
1726 | Value val = pop(type); | ||||
1727 | if (state_before == NULL__null) { | ||||
1728 | state_before = copy_state_for_exception(); | ||||
1729 | } | ||||
1730 | if (field->type()->basic_type() == T_BOOLEAN) { | ||||
1731 | Value mask = append(new Constant(new IntConstant(1))); | ||||
1732 | val = append(new LogicOp(Bytecodes::_iand, val, mask)); | ||||
1733 | } | ||||
1734 | append(new StoreField(append(obj), offset, field, val, true, state_before, needs_patching)); | ||||
1735 | break; | ||||
1736 | } | ||||
1737 | case Bytecodes::_getfield: { | ||||
1738 | // Check for compile-time constants, i.e., trusted final non-static fields. | ||||
1739 | Value constant = NULL__null; | ||||
1740 | obj = apop(); | ||||
1741 | ObjectType* obj_type = obj->type()->as_ObjectType(); | ||||
1742 | if (field->is_constant() && obj_type->is_constant() && !PatchALot) { | ||||
1743 | ciObject* const_oop = obj_type->constant_value(); | ||||
1744 | if (!const_oop->is_null_object() && const_oop->is_loaded()) { | ||||
1745 | ciConstant field_value = field->constant_value_of(const_oop); | ||||
1746 | if (field_value.is_valid()) { | ||||
1747 | constant = make_constant(field_value, field); | ||||
1748 | // For CallSite objects add a dependency for invalidation of the optimization. | ||||
1749 | if (field->is_call_site_target()) { | ||||
1750 | ciCallSite* call_site = const_oop->as_call_site(); | ||||
1751 | if (!call_site->is_fully_initialized_constant_call_site()) { | ||||
1752 | ciMethodHandle* target = field_value.as_object()->as_method_handle(); | ||||
1753 | dependency_recorder()->assert_call_site_target_value(call_site, target); | ||||
1754 | } | ||||
1755 | } | ||||
1756 | } | ||||
1757 | } | ||||
1758 | } | ||||
1759 | if (constant != NULL__null) { | ||||
1760 | push(type, append(constant)); | ||||
1761 | } else { | ||||
1762 | if (state_before == NULL__null) { | ||||
1763 | state_before = copy_state_for_exception(); | ||||
1764 | } | ||||
1765 | LoadField* load = new LoadField(obj, offset, field, false, state_before, needs_patching); | ||||
1766 | Value replacement = !needs_patching ? _memory->load(load) : load; | ||||
1767 | if (replacement != load) { | ||||
1768 | assert(replacement->is_linked() || !replacement->can_be_linked(), "should already by linked")do { if (!(replacement->is_linked() || !replacement->can_be_linked ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1768, "assert(" "replacement->is_linked() || !replacement->can_be_linked()" ") failed", "should already by linked"); ::breakpoint(); } } while (0); | ||||
1769 | // Writing an (integer) value to a boolean, byte, char or short field includes an implicit narrowing | ||||
1770 | // conversion. Emit an explicit conversion here to get the correct field value after the write. | ||||
1771 | BasicType bt = field->type()->basic_type(); | ||||
1772 | switch (bt) { | ||||
1773 | case T_BOOLEAN: | ||||
1774 | case T_BYTE: | ||||
1775 | replacement = append(new Convert(Bytecodes::_i2b, replacement, as_ValueType(bt))); | ||||
1776 | break; | ||||
1777 | case T_CHAR: | ||||
1778 | replacement = append(new Convert(Bytecodes::_i2c, replacement, as_ValueType(bt))); | ||||
1779 | break; | ||||
1780 | case T_SHORT: | ||||
1781 | replacement = append(new Convert(Bytecodes::_i2s, replacement, as_ValueType(bt))); | ||||
1782 | break; | ||||
1783 | default: | ||||
1784 | break; | ||||
1785 | } | ||||
1786 | push(type, replacement); | ||||
1787 | } else { | ||||
1788 | push(type, append(load)); | ||||
1789 | } | ||||
1790 | } | ||||
1791 | break; | ||||
1792 | } | ||||
1793 | case Bytecodes::_putfield: { | ||||
1794 | Value val = pop(type); | ||||
1795 | obj = apop(); | ||||
1796 | if (state_before == NULL__null) { | ||||
1797 | state_before = copy_state_for_exception(); | ||||
1798 | } | ||||
1799 | if (field->type()->basic_type() == T_BOOLEAN) { | ||||
1800 | Value mask = append(new Constant(new IntConstant(1))); | ||||
1801 | val = append(new LogicOp(Bytecodes::_iand, val, mask)); | ||||
1802 | } | ||||
1803 | StoreField* store = new StoreField(obj, offset, field, val, false, state_before, needs_patching); | ||||
1804 | if (!needs_patching) store = _memory->store(store); | ||||
1805 | if (store != NULL__null) { | ||||
1806 | append(store); | ||||
1807 | } | ||||
1808 | break; | ||||
1809 | } | ||||
1810 | default: | ||||
1811 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1811); ::breakpoint(); } while (0); | ||||
1812 | break; | ||||
1813 | } | ||||
1814 | } | ||||
1815 | |||||
1816 | |||||
1817 | Dependencies* GraphBuilder::dependency_recorder() const { | ||||
1818 | assert(DeoptC1, "need debug information")do { if (!(DeoptC1)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1818, "assert(" "DeoptC1" ") failed", "need debug information" ); ::breakpoint(); } } while (0); | ||||
1819 | return compilation()->dependency_recorder(); | ||||
1820 | } | ||||
1821 | |||||
1822 | // How many arguments do we want to profile? | ||||
1823 | Values* GraphBuilder::args_list_for_profiling(ciMethod* target, int& start, bool may_have_receiver) { | ||||
1824 | int n = 0; | ||||
1825 | bool has_receiver = may_have_receiver && Bytecodes::has_receiver(method()->java_code_at_bci(bci())); | ||||
1826 | start = has_receiver ? 1 : 0; | ||||
1827 | if (profile_arguments()) { | ||||
1828 | ciProfileData* data = method()->method_data()->bci_to_data(bci()); | ||||
1829 | if (data != NULL__null && (data->is_CallTypeData() || data->is_VirtualCallTypeData())) { | ||||
1830 | n = data->is_CallTypeData() ? data->as_CallTypeData()->number_of_arguments() : data->as_VirtualCallTypeData()->number_of_arguments(); | ||||
1831 | } | ||||
1832 | } | ||||
1833 | // If we are inlining then we need to collect arguments to profile parameters for the target | ||||
1834 | if (profile_parameters() && target != NULL__null) { | ||||
1835 | if (target->method_data() != NULL__null && target->method_data()->parameters_type_data() != NULL__null) { | ||||
1836 | // The receiver is profiled on method entry so it's included in | ||||
1837 | // the number of parameters but here we're only interested in | ||||
1838 | // actual arguments. | ||||
1839 | n = MAX2(n, target->method_data()->parameters_type_data()->number_of_parameters() - start); | ||||
1840 | } | ||||
1841 | } | ||||
1842 | if (n > 0) { | ||||
1843 | return new Values(n); | ||||
1844 | } | ||||
1845 | return NULL__null; | ||||
1846 | } | ||||
1847 | |||||
1848 | void GraphBuilder::check_args_for_profiling(Values* obj_args, int expected) { | ||||
1849 | #ifdef ASSERT1 | ||||
1850 | bool ignored_will_link; | ||||
1851 | ciSignature* declared_signature = NULL__null; | ||||
1852 | ciMethod* real_target = method()->get_method_at_bci(bci(), ignored_will_link, &declared_signature); | ||||
1853 | assert(expected == obj_args->max_length() || real_target->is_method_handle_intrinsic(), "missed on arg?")do { if (!(expected == obj_args->max_length() || real_target ->is_method_handle_intrinsic())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1853, "assert(" "expected == obj_args->max_length() || real_target->is_method_handle_intrinsic()" ") failed", "missed on arg?"); ::breakpoint(); } } while (0); | ||||
1854 | #endif | ||||
1855 | } | ||||
1856 | |||||
1857 | // Collect arguments that we want to profile in a list | ||||
1858 | Values* GraphBuilder::collect_args_for_profiling(Values* args, ciMethod* target, bool may_have_receiver) { | ||||
1859 | int start = 0; | ||||
1860 | Values* obj_args = args_list_for_profiling(target, start, may_have_receiver); | ||||
1861 | if (obj_args == NULL__null) { | ||||
1862 | return NULL__null; | ||||
1863 | } | ||||
1864 | int s = obj_args->max_length(); | ||||
1865 | // if called through method handle invoke, some arguments may have been popped | ||||
1866 | for (int i = start, j = 0; j < s && i < args->length(); i++) { | ||||
1867 | if (args->at(i)->type()->is_object_kind()) { | ||||
1868 | obj_args->push(args->at(i)); | ||||
1869 | j++; | ||||
1870 | } | ||||
1871 | } | ||||
1872 | check_args_for_profiling(obj_args, s); | ||||
1873 | return obj_args; | ||||
1874 | } | ||||
1875 | |||||
1876 | |||||
1877 | void GraphBuilder::invoke(Bytecodes::Code code) { | ||||
1878 | bool will_link; | ||||
1879 | ciSignature* declared_signature = NULL__null; | ||||
1880 | ciMethod* target = stream()->get_method(will_link, &declared_signature); | ||||
1881 | ciKlass* holder = stream()->get_declared_method_holder(); | ||||
1882 | const Bytecodes::Code bc_raw = stream()->cur_bc_raw(); | ||||
1883 | assert(declared_signature != NULL, "cannot be null")do { if (!(declared_signature != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1883, "assert(" "declared_signature != __null" ") failed", "cannot be null" ); ::breakpoint(); } } while (0); | ||||
1884 | assert(will_link == target->is_loaded(), "")do { if (!(will_link == target->is_loaded())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1884, "assert(" "will_link == target->is_loaded()" ") failed" , ""); ::breakpoint(); } } while (0); | ||||
1885 | |||||
1886 | ciInstanceKlass* klass = target->holder(); | ||||
1887 | assert(!target->is_loaded() || klass->is_loaded(), "loaded target must imply loaded klass")do { if (!(!target->is_loaded() || klass->is_loaded())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1887, "assert(" "!target->is_loaded() || klass->is_loaded()" ") failed", "loaded target must imply loaded klass"); ::breakpoint (); } } while (0); | ||||
1888 | |||||
1889 | // check if CHA possible: if so, change the code to invoke_special | ||||
1890 | ciInstanceKlass* calling_klass = method()->holder(); | ||||
1891 | ciInstanceKlass* callee_holder = ciEnv::get_instance_klass_for_declared_method_holder(holder); | ||||
1892 | ciInstanceKlass* actual_recv = callee_holder; | ||||
1893 | |||||
1894 | CompileLog* log = compilation()->log(); | ||||
1895 | if (log != NULL__null) | ||||
1896 | log->elem("call method='%d' instr='%s'", | ||||
1897 | log->identify(target), | ||||
1898 | Bytecodes::name(code)); | ||||
1899 | |||||
1900 | // Some methods are obviously bindable without any type checks so | ||||
1901 | // convert them directly to an invokespecial or invokestatic. | ||||
1902 | if (target->is_loaded() && !target->is_abstract() && target->can_be_statically_bound()) { | ||||
1903 | switch (bc_raw) { | ||||
1904 | case Bytecodes::_invokeinterface: | ||||
1905 | // convert to invokespecial if the target is the private interface method. | ||||
1906 | if (target->is_private()) { | ||||
1907 | assert(holder->is_interface(), "How did we get a non-interface method here!")do { if (!(holder->is_interface())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1907, "assert(" "holder->is_interface()" ") failed", "How did we get a non-interface method here!" ); ::breakpoint(); } } while (0); | ||||
1908 | code = Bytecodes::_invokespecial; | ||||
1909 | } | ||||
1910 | break; | ||||
1911 | case Bytecodes::_invokevirtual: | ||||
1912 | code = Bytecodes::_invokespecial; | ||||
1913 | break; | ||||
1914 | case Bytecodes::_invokehandle: | ||||
1915 | code = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokespecial; | ||||
1916 | break; | ||||
1917 | default: | ||||
1918 | break; | ||||
1919 | } | ||||
1920 | } else { | ||||
1921 | if (bc_raw == Bytecodes::_invokehandle) { | ||||
1922 | assert(!will_link, "should come here only for unlinked call")do { if (!(!will_link)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 1922, "assert(" "!will_link" ") failed", "should come here only for unlinked call" ); ::breakpoint(); } } while (0); | ||||
1923 | code = Bytecodes::_invokespecial; | ||||
1924 | } | ||||
1925 | } | ||||
1926 | |||||
1927 | if (code == Bytecodes::_invokespecial) { | ||||
1928 | // Additional receiver subtype checks for interface calls via invokespecial or invokeinterface. | ||||
1929 | ciKlass* receiver_constraint = nullptr; | ||||
1930 | |||||
1931 | if (bc_raw == Bytecodes::_invokeinterface) { | ||||
1932 | receiver_constraint = holder; | ||||
1933 | } else if (bc_raw == Bytecodes::_invokespecial && !target->is_object_initializer() && calling_klass->is_interface()) { | ||||
1934 | receiver_constraint = calling_klass; | ||||
1935 | } | ||||
1936 | |||||
1937 | if (receiver_constraint != nullptr) { | ||||
1938 | int index = state()->stack_size() - (target->arg_size_no_receiver() + 1); | ||||
1939 | Value receiver = state()->stack_at(index); | ||||
1940 | CheckCast* c = new CheckCast(receiver_constraint, receiver, copy_state_before()); | ||||
1941 | // go to uncommon_trap when checkcast fails | ||||
1942 | c->set_invokespecial_receiver_check(); | ||||
1943 | state()->stack_at_put(index, append_split(c)); | ||||
1944 | } | ||||
1945 | } | ||||
1946 | |||||
1947 | // Push appendix argument (MethodType, CallSite, etc.), if one. | ||||
1948 | bool patch_for_appendix = false; | ||||
1949 | int patching_appendix_arg = 0; | ||||
1950 | if (Bytecodes::has_optional_appendix(bc_raw) && (!will_link || PatchALot)) { | ||||
1951 | Value arg = append(new Constant(new ObjectConstant(compilation()->env()->unloaded_ciinstance()), copy_state_before())); | ||||
1952 | apush(arg); | ||||
1953 | patch_for_appendix = true; | ||||
1954 | patching_appendix_arg = (will_link && stream()->has_appendix()) ? 0 : 1; | ||||
1955 | } else if (stream()->has_appendix()) { | ||||
1956 | ciObject* appendix = stream()->get_appendix(); | ||||
1957 | Value arg = append(new Constant(new ObjectConstant(appendix))); | ||||
1958 | apush(arg); | ||||
1959 | } | ||||
1960 | |||||
1961 | ciMethod* cha_monomorphic_target = NULL__null; | ||||
1962 | ciMethod* exact_target = NULL__null; | ||||
1963 | Value better_receiver = NULL__null; | ||||
1964 | if (UseCHA && DeoptC1 && target->is_loaded() && | ||||
1965 | !(// %%% FIXME: Are both of these relevant? | ||||
1966 | target->is_method_handle_intrinsic() || | ||||
1967 | target->is_compiled_lambda_form()) && | ||||
1968 | !patch_for_appendix) { | ||||
1969 | Value receiver = NULL__null; | ||||
1970 | ciInstanceKlass* receiver_klass = NULL__null; | ||||
1971 | bool type_is_exact = false; | ||||
1972 | // try to find a precise receiver type | ||||
1973 | if (will_link && !target->is_static()) { | ||||
1974 | int index = state()->stack_size() - (target->arg_size_no_receiver() + 1); | ||||
1975 | receiver = state()->stack_at(index); | ||||
1976 | ciType* type = receiver->exact_type(); | ||||
1977 | if (type != NULL__null && type->is_loaded() && | ||||
1978 | type->is_instance_klass() && !type->as_instance_klass()->is_interface()) { | ||||
1979 | receiver_klass = (ciInstanceKlass*) type; | ||||
1980 | type_is_exact = true; | ||||
1981 | } | ||||
1982 | if (type == NULL__null) { | ||||
1983 | type = receiver->declared_type(); | ||||
1984 | if (type != NULL__null && type->is_loaded() && | ||||
1985 | type->is_instance_klass() && !type->as_instance_klass()->is_interface()) { | ||||
1986 | receiver_klass = (ciInstanceKlass*) type; | ||||
1987 | if (receiver_klass->is_leaf_type() && !receiver_klass->is_final()) { | ||||
1988 | // Insert a dependency on this type since | ||||
1989 | // find_monomorphic_target may assume it's already done. | ||||
1990 | dependency_recorder()->assert_leaf_type(receiver_klass); | ||||
1991 | type_is_exact = true; | ||||
1992 | } | ||||
1993 | } | ||||
1994 | } | ||||
1995 | } | ||||
1996 | if (receiver_klass != NULL__null && type_is_exact && | ||||
1997 | receiver_klass->is_loaded() && code != Bytecodes::_invokespecial) { | ||||
1998 | // If we have the exact receiver type we can bind directly to | ||||
1999 | // the method to call. | ||||
2000 | exact_target = target->resolve_invoke(calling_klass, receiver_klass); | ||||
2001 | if (exact_target != NULL__null) { | ||||
2002 | target = exact_target; | ||||
2003 | code = Bytecodes::_invokespecial; | ||||
2004 | } | ||||
2005 | } | ||||
2006 | if (receiver_klass != NULL__null && | ||||
2007 | receiver_klass->is_subtype_of(actual_recv) && | ||||
2008 | actual_recv->is_initialized()) { | ||||
2009 | actual_recv = receiver_klass; | ||||
2010 | } | ||||
2011 | |||||
2012 | if ((code == Bytecodes::_invokevirtual && callee_holder->is_initialized()) || | ||||
2013 | (code == Bytecodes::_invokeinterface && callee_holder->is_initialized() && !actual_recv->is_interface())) { | ||||
2014 | // Use CHA on the receiver to select a more precise method. | ||||
2015 | cha_monomorphic_target = target->find_monomorphic_target(calling_klass, callee_holder, actual_recv); | ||||
2016 | } else if (code == Bytecodes::_invokeinterface && callee_holder->is_loaded() && receiver != NULL__null) { | ||||
2017 | assert(callee_holder->is_interface(), "invokeinterface to non interface?")do { if (!(callee_holder->is_interface())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2017, "assert(" "callee_holder->is_interface()" ") failed" , "invokeinterface to non interface?"); ::breakpoint(); } } while (0); | ||||
2018 | // If there is only one implementor of this interface then we | ||||
2019 | // may be able bind this invoke directly to the implementing | ||||
2020 | // klass but we need both a dependence on the single interface | ||||
2021 | // and on the method we bind to. Additionally since all we know | ||||
2022 | // about the receiver type is the it's supposed to implement the | ||||
2023 | // interface we have to insert a check that it's the class we | ||||
2024 | // expect. Interface types are not checked by the verifier so | ||||
2025 | // they are roughly equivalent to Object. | ||||
2026 | // The number of implementors for declared_interface is less or | ||||
2027 | // equal to the number of implementors for target->holder() so | ||||
2028 | // if number of implementors of target->holder() == 1 then | ||||
2029 | // number of implementors for decl_interface is 0 or 1. If | ||||
2030 | // it's 0 then no class implements decl_interface and there's | ||||
2031 | // no point in inlining. | ||||
2032 | ciInstanceKlass* declared_interface = callee_holder; | ||||
2033 | ciInstanceKlass* singleton = declared_interface->unique_implementor(); | ||||
2034 | if (singleton != NULL__null) { | ||||
2035 | assert(singleton != declared_interface, "not a unique implementor")do { if (!(singleton != declared_interface)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2035, "assert(" "singleton != declared_interface" ") failed" , "not a unique implementor"); ::breakpoint(); } } while (0); | ||||
2036 | cha_monomorphic_target = target->find_monomorphic_target(calling_klass, declared_interface, singleton); | ||||
2037 | if (cha_monomorphic_target != NULL__null) { | ||||
2038 | if (cha_monomorphic_target->holder() != compilation()->env()->Object_klass()) { | ||||
2039 | // If CHA is able to bind this invoke then update the class | ||||
2040 | // to match that class, otherwise klass will refer to the | ||||
2041 | // interface. | ||||
2042 | klass = cha_monomorphic_target->holder(); | ||||
2043 | actual_recv = declared_interface; | ||||
2044 | |||||
2045 | // insert a check it's really the expected class. | ||||
2046 | CheckCast* c = new CheckCast(klass, receiver, copy_state_for_exception()); | ||||
2047 | c->set_incompatible_class_change_check(); | ||||
2048 | c->set_direct_compare(klass->is_final()); | ||||
2049 | // pass the result of the checkcast so that the compiler has | ||||
2050 | // more accurate type info in the inlinee | ||||
2051 | better_receiver = append_split(c); | ||||
2052 | } else { | ||||
2053 | cha_monomorphic_target = NULL__null; // subtype check against Object is useless | ||||
2054 | } | ||||
2055 | } | ||||
2056 | } | ||||
2057 | } | ||||
2058 | } | ||||
2059 | |||||
2060 | if (cha_monomorphic_target != NULL__null) { | ||||
2061 | assert(!target->can_be_statically_bound() || target == cha_monomorphic_target, "")do { if (!(!target->can_be_statically_bound() || target == cha_monomorphic_target)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2061, "assert(" "!target->can_be_statically_bound() || target == cha_monomorphic_target" ") failed", ""); ::breakpoint(); } } while (0); | ||||
2062 | assert(!cha_monomorphic_target->is_abstract(), "")do { if (!(!cha_monomorphic_target->is_abstract())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2062, "assert(" "!cha_monomorphic_target->is_abstract()" ") failed", ""); ::breakpoint(); } } while (0); | ||||
2063 | if (!cha_monomorphic_target->can_be_statically_bound(actual_recv)) { | ||||
2064 | // If we inlined because CHA revealed only a single target method, | ||||
2065 | // then we are dependent on that target method not getting overridden | ||||
2066 | // by dynamic class loading. Be sure to test the "static" receiver | ||||
2067 | // dest_method here, as opposed to the actual receiver, which may | ||||
2068 | // falsely lead us to believe that the receiver is final or private. | ||||
2069 | dependency_recorder()->assert_unique_concrete_method(actual_recv, cha_monomorphic_target, callee_holder, target); | ||||
2070 | } | ||||
2071 | code = Bytecodes::_invokespecial; | ||||
2072 | } | ||||
2073 | |||||
2074 | // check if we could do inlining | ||||
2075 | if (!PatchALot && Inline && target->is_loaded() && callee_holder->is_linked() && !patch_for_appendix) { | ||||
2076 | // callee is known => check if we have static binding | ||||
2077 | if ((code == Bytecodes::_invokestatic && callee_holder->is_initialized()) || // invokestatic involves an initialization barrier on resolved klass | ||||
2078 | code == Bytecodes::_invokespecial || | ||||
2079 | (code == Bytecodes::_invokevirtual && target->is_final_method()) || | ||||
2080 | code == Bytecodes::_invokedynamic) { | ||||
2081 | // static binding => check if callee is ok | ||||
2082 | ciMethod* inline_target = (cha_monomorphic_target != NULL__null) ? cha_monomorphic_target : target; | ||||
2083 | bool holder_known = (cha_monomorphic_target != NULL__null) || (exact_target != NULL__null); | ||||
2084 | bool success = try_inline(inline_target, holder_known, false /* ignore_return */, code, better_receiver); | ||||
2085 | |||||
2086 | CHECK_BAILOUT(){ if (bailed_out()) return; }; | ||||
2087 | clear_inline_bailout(); | ||||
2088 | |||||
2089 | if (success) { | ||||
2090 | // Register dependence if JVMTI has either breakpoint | ||||
2091 | // setting or hotswapping of methods capabilities since they may | ||||
2092 | // cause deoptimization. | ||||
2093 | if (compilation()->env()->jvmti_can_hotswap_or_post_breakpoint()) { | ||||
2094 | dependency_recorder()->assert_evol_method(inline_target); | ||||
2095 | } | ||||
2096 | return; | ||||
2097 | } | ||||
2098 | } else { | ||||
2099 | print_inlining(target, "no static binding", /*success*/ false); | ||||
2100 | } | ||||
2101 | } else { | ||||
2102 | print_inlining(target, "not inlineable", /*success*/ false); | ||||
2103 | } | ||||
2104 | |||||
2105 | // If we attempted an inline which did not succeed because of a | ||||
2106 | // bailout during construction of the callee graph, the entire | ||||
2107 | // compilation has to be aborted. This is fairly rare and currently | ||||
2108 | // seems to only occur for jasm-generated classes which contain | ||||
2109 | // jsr/ret pairs which are not associated with finally clauses and | ||||
2110 | // do not have exception handlers in the containing method, and are | ||||
2111 | // therefore not caught early enough to abort the inlining without | ||||
2112 | // corrupting the graph. (We currently bail out with a non-empty | ||||
2113 | // stack at a ret in these situations.) | ||||
2114 | CHECK_BAILOUT(){ if (bailed_out()) return; }; | ||||
2115 | |||||
2116 | // inlining not successful => standard invoke | ||||
2117 | ValueType* result_type = as_ValueType(declared_signature->return_type()); | ||||
2118 | ValueStack* state_before = copy_state_exhandling(); | ||||
2119 | |||||
2120 | // The bytecode (code) might change in this method so we are checking this very late. | ||||
2121 | const bool has_receiver = | ||||
2122 | code == Bytecodes::_invokespecial || | ||||
2123 | code == Bytecodes::_invokevirtual || | ||||
2124 | code == Bytecodes::_invokeinterface; | ||||
2125 | Values* args = state()->pop_arguments(target->arg_size_no_receiver() + patching_appendix_arg); | ||||
2126 | Value recv = has_receiver ? apop() : NULL__null; | ||||
2127 | |||||
2128 | // A null check is required here (when there is a receiver) for any of the following cases | ||||
2129 | // - invokespecial, always need a null check. | ||||
2130 | // - invokevirtual, when the target is final and loaded. Calls to final targets will become optimized | ||||
2131 | // and require null checking. If the target is loaded a null check is emitted here. | ||||
2132 | // If the target isn't loaded the null check must happen after the call resolution. We achieve that | ||||
2133 | // by using the target methods unverified entry point (see CompiledIC::compute_monomorphic_entry). | ||||
2134 | // (The JVM specification requires that LinkageError must be thrown before a NPE. An unloaded target may | ||||
2135 | // potentially fail, and can't have the null check before the resolution.) | ||||
2136 | // - A call that will be profiled. (But we can't add a null check when the target is unloaded, by the same | ||||
2137 | // reason as above, so calls with a receiver to unloaded targets can't be profiled.) | ||||
2138 | // | ||||
2139 | // Normal invokevirtual will perform the null check during lookup | ||||
2140 | |||||
2141 | bool need_null_check = (code == Bytecodes::_invokespecial) || | ||||
2142 | (target->is_loaded() && (target->is_final_method() || (is_profiling() && profile_calls()))); | ||||
2143 | |||||
2144 | if (need_null_check) { | ||||
2145 | if (recv != NULL__null) { | ||||
2146 | null_check(recv); | ||||
2147 | } | ||||
2148 | |||||
2149 | if (is_profiling()) { | ||||
2150 | // Note that we'd collect profile data in this method if we wanted it. | ||||
2151 | compilation()->set_would_profile(true); | ||||
2152 | |||||
2153 | if (profile_calls()) { | ||||
2154 | assert(cha_monomorphic_target == NULL || exact_target == NULL, "both can not be set")do { if (!(cha_monomorphic_target == __null || exact_target == __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2154, "assert(" "cha_monomorphic_target == __null || exact_target == __null" ") failed", "both can not be set"); ::breakpoint(); } } while (0); | ||||
2155 | ciKlass* target_klass = NULL__null; | ||||
2156 | if (cha_monomorphic_target != NULL__null) { | ||||
2157 | target_klass = cha_monomorphic_target->holder(); | ||||
2158 | } else if (exact_target != NULL__null) { | ||||
2159 | target_klass = exact_target->holder(); | ||||
2160 | } | ||||
2161 | profile_call(target, recv, target_klass, collect_args_for_profiling(args, NULL__null, false), false); | ||||
2162 | } | ||||
2163 | } | ||||
2164 | } | ||||
2165 | |||||
2166 | Invoke* result = new Invoke(code, result_type, recv, args, target, state_before); | ||||
2167 | // push result | ||||
2168 | append_split(result); | ||||
2169 | |||||
2170 | if (result_type != voidType) { | ||||
2171 | push(result_type, round_fp(result)); | ||||
2172 | } | ||||
2173 | if (profile_return() && result_type->is_object_kind()) { | ||||
2174 | profile_return_type(result, target); | ||||
2175 | } | ||||
2176 | } | ||||
2177 | |||||
2178 | |||||
2179 | void GraphBuilder::new_instance(int klass_index) { | ||||
2180 | ValueStack* state_before = copy_state_exhandling(); | ||||
2181 | bool will_link; | ||||
2182 | ciKlass* klass = stream()->get_klass(will_link); | ||||
2183 | assert(klass->is_instance_klass(), "must be an instance klass")do { if (!(klass->is_instance_klass())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2183, "assert(" "klass->is_instance_klass()" ") failed", "must be an instance klass"); ::breakpoint(); } } while (0); | ||||
2184 | NewInstance* new_instance = new NewInstance(klass->as_instance_klass(), state_before, stream()->is_unresolved_klass()); | ||||
2185 | _memory->new_instance(new_instance); | ||||
2186 | apush(append_split(new_instance)); | ||||
2187 | } | ||||
2188 | |||||
2189 | |||||
2190 | void GraphBuilder::new_type_array() { | ||||
2191 | ValueStack* state_before = copy_state_exhandling(); | ||||
2192 | apush(append_split(new NewTypeArray(ipop(), (BasicType)stream()->get_index(), state_before))); | ||||
2193 | } | ||||
2194 | |||||
2195 | |||||
2196 | void GraphBuilder::new_object_array() { | ||||
2197 | bool will_link; | ||||
2198 | ciKlass* klass = stream()->get_klass(will_link); | ||||
2199 | ValueStack* state_before = !klass->is_loaded() || PatchALot ? copy_state_before() : copy_state_exhandling(); | ||||
2200 | NewArray* n = new NewObjectArray(klass, ipop(), state_before); | ||||
2201 | apush(append_split(n)); | ||||
2202 | } | ||||
2203 | |||||
2204 | |||||
2205 | bool GraphBuilder::direct_compare(ciKlass* k) { | ||||
2206 | if (k->is_loaded() && k->is_instance_klass() && !UseSlowPath) { | ||||
2207 | ciInstanceKlass* ik = k->as_instance_klass(); | ||||
2208 | if (ik->is_final()) { | ||||
2209 | return true; | ||||
2210 | } else { | ||||
2211 | if (DeoptC1 && UseCHA && !(ik->has_subklass() || ik->is_interface())) { | ||||
2212 | // test class is leaf class | ||||
2213 | dependency_recorder()->assert_leaf_type(ik); | ||||
2214 | return true; | ||||
2215 | } | ||||
2216 | } | ||||
2217 | } | ||||
2218 | return false; | ||||
2219 | } | ||||
2220 | |||||
2221 | |||||
2222 | void GraphBuilder::check_cast(int klass_index) { | ||||
2223 | bool will_link; | ||||
2224 | ciKlass* klass = stream()->get_klass(will_link); | ||||
2225 | ValueStack* state_before = !klass->is_loaded() || PatchALot ? copy_state_before() : copy_state_for_exception(); | ||||
2226 | CheckCast* c = new CheckCast(klass, apop(), state_before); | ||||
2227 | apush(append_split(c)); | ||||
2228 | c->set_direct_compare(direct_compare(klass)); | ||||
2229 | |||||
2230 | if (is_profiling()) { | ||||
2231 | // Note that we'd collect profile data in this method if we wanted it. | ||||
2232 | compilation()->set_would_profile(true); | ||||
2233 | |||||
2234 | if (profile_checkcasts()) { | ||||
2235 | c->set_profiled_method(method()); | ||||
2236 | c->set_profiled_bci(bci()); | ||||
2237 | c->set_should_profile(true); | ||||
2238 | } | ||||
2239 | } | ||||
2240 | } | ||||
2241 | |||||
2242 | |||||
2243 | void GraphBuilder::instance_of(int klass_index) { | ||||
2244 | bool will_link; | ||||
2245 | ciKlass* klass = stream()->get_klass(will_link); | ||||
2246 | ValueStack* state_before = !klass->is_loaded() || PatchALot ? copy_state_before() : copy_state_exhandling(); | ||||
2247 | InstanceOf* i = new InstanceOf(klass, apop(), state_before); | ||||
2248 | ipush(append_split(i)); | ||||
2249 | i->set_direct_compare(direct_compare(klass)); | ||||
2250 | |||||
2251 | if (is_profiling()) { | ||||
2252 | // Note that we'd collect profile data in this method if we wanted it. | ||||
2253 | compilation()->set_would_profile(true); | ||||
2254 | |||||
2255 | if (profile_checkcasts()) { | ||||
2256 | i->set_profiled_method(method()); | ||||
2257 | i->set_profiled_bci(bci()); | ||||
2258 | i->set_should_profile(true); | ||||
2259 | } | ||||
2260 | } | ||||
2261 | } | ||||
2262 | |||||
2263 | |||||
2264 | void GraphBuilder::monitorenter(Value x, int bci) { | ||||
2265 | // save state before locking in case of deoptimization after a NullPointerException | ||||
2266 | ValueStack* state_before = copy_state_for_exception_with_bci(bci); | ||||
2267 | append_with_bci(new MonitorEnter(x, state()->lock(x), state_before), bci); | ||||
2268 | kill_all(); | ||||
2269 | } | ||||
2270 | |||||
2271 | |||||
2272 | void GraphBuilder::monitorexit(Value x, int bci) { | ||||
2273 | append_with_bci(new MonitorExit(x, state()->unlock()), bci); | ||||
2274 | kill_all(); | ||||
2275 | } | ||||
2276 | |||||
2277 | |||||
2278 | void GraphBuilder::new_multi_array(int dimensions) { | ||||
2279 | bool will_link; | ||||
2280 | ciKlass* klass = stream()->get_klass(will_link); | ||||
2281 | ValueStack* state_before = !klass->is_loaded() || PatchALot ? copy_state_before() : copy_state_exhandling(); | ||||
2282 | |||||
2283 | Values* dims = new Values(dimensions, dimensions, NULL__null); | ||||
2284 | // fill in all dimensions | ||||
2285 | int i = dimensions; | ||||
2286 | while (i-- > 0) dims->at_put(i, ipop()); | ||||
2287 | // create array | ||||
2288 | NewArray* n = new NewMultiArray(klass, dims, state_before); | ||||
2289 | apush(append_split(n)); | ||||
2290 | } | ||||
2291 | |||||
2292 | |||||
2293 | void GraphBuilder::throw_op(int bci) { | ||||
2294 | // We require that the debug info for a Throw be the "state before" | ||||
2295 | // the Throw (i.e., exception oop is still on TOS) | ||||
2296 | ValueStack* state_before = copy_state_before_with_bci(bci); | ||||
2297 | Throw* t = new Throw(apop(), state_before); | ||||
2298 | // operand stack not needed after a throw | ||||
2299 | state()->truncate_stack(0); | ||||
2300 | append_with_bci(t, bci); | ||||
2301 | } | ||||
2302 | |||||
2303 | |||||
2304 | Value GraphBuilder::round_fp(Value fp_value) { | ||||
2305 | if (strict_fp_requires_explicit_rounding) { | ||||
2306 | #ifdef IA32 | ||||
2307 | // no rounding needed if SSE2 is used | ||||
2308 | if (UseSSE < 2) { | ||||
2309 | // Must currently insert rounding node for doubleword values that | ||||
2310 | // are results of expressions (i.e., not loads from memory or | ||||
2311 | // constants) | ||||
2312 | if (fp_value->type()->tag() == doubleTag && | ||||
2313 | fp_value->as_Constant() == NULL__null && | ||||
2314 | fp_value->as_Local() == NULL__null && // method parameters need no rounding | ||||
2315 | fp_value->as_RoundFP() == NULL__null) { | ||||
2316 | return append(new RoundFP(fp_value)); | ||||
2317 | } | ||||
2318 | } | ||||
2319 | #else | ||||
2320 | Unimplemented()do { (*g_assert_poison) = 'X';; report_unimplemented("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2320); ::breakpoint(); } while (0); | ||||
2321 | #endif // IA32 | ||||
2322 | } | ||||
2323 | return fp_value; | ||||
2324 | } | ||||
2325 | |||||
2326 | |||||
2327 | Instruction* GraphBuilder::append_with_bci(Instruction* instr, int bci) { | ||||
2328 | Canonicalizer canon(compilation(), instr, bci); | ||||
2329 | Instruction* i1 = canon.canonical(); | ||||
2330 | if (i1->is_linked() || !i1->can_be_linked()) { | ||||
2331 | // Canonicalizer returned an instruction which was already | ||||
2332 | // appended so simply return it. | ||||
2333 | return i1; | ||||
2334 | } | ||||
2335 | |||||
2336 | if (UseLocalValueNumbering) { | ||||
2337 | // Lookup the instruction in the ValueMap and add it to the map if | ||||
2338 | // it's not found. | ||||
2339 | Instruction* i2 = vmap()->find_insert(i1); | ||||
2340 | if (i2 != i1) { | ||||
2341 | // found an entry in the value map, so just return it. | ||||
2342 | assert(i2->is_linked(), "should already be linked")do { if (!(i2->is_linked())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2342, "assert(" "i2->is_linked()" ") failed", "should already be linked" ); ::breakpoint(); } } while (0); | ||||
2343 | return i2; | ||||
2344 | } | ||||
2345 | ValueNumberingEffects vne(vmap()); | ||||
2346 | i1->visit(&vne); | ||||
2347 | } | ||||
2348 | |||||
2349 | // i1 was not eliminated => append it | ||||
2350 | assert(i1->next() == NULL, "shouldn't already be linked")do { if (!(i1->next() == __null)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2350, "assert(" "i1->next() == __null" ") failed", "shouldn't already be linked" ); ::breakpoint(); } } while (0); | ||||
2351 | _last = _last->set_next(i1, canon.bci()); | ||||
2352 | |||||
2353 | if (++_instruction_count >= InstructionCountCutoff && !bailed_out()) { | ||||
2354 | // set the bailout state but complete normal processing. We | ||||
2355 | // might do a little more work before noticing the bailout so we | ||||
2356 | // want processing to continue normally until it's noticed. | ||||
2357 | bailout("Method and/or inlining is too large"); | ||||
2358 | } | ||||
2359 | |||||
2360 | #ifndef PRODUCT | ||||
2361 | if (PrintIRDuringConstruction) { | ||||
2362 | InstructionPrinter ip; | ||||
2363 | ip.print_line(i1); | ||||
2364 | if (Verbose) { | ||||
2365 | state()->print(); | ||||
2366 | } | ||||
2367 | } | ||||
2368 | #endif | ||||
2369 | |||||
2370 | // save state after modification of operand stack for StateSplit instructions | ||||
2371 | StateSplit* s = i1->as_StateSplit(); | ||||
2372 | if (s != NULL__null) { | ||||
2373 | if (EliminateFieldAccess) { | ||||
2374 | Intrinsic* intrinsic = s->as_Intrinsic(); | ||||
2375 | if (s->as_Invoke() != NULL__null || (intrinsic && !intrinsic->preserves_state())) { | ||||
2376 | _memory->kill(); | ||||
2377 | } | ||||
2378 | } | ||||
2379 | s->set_state(state()->copy(ValueStack::StateAfter, canon.bci())); | ||||
2380 | } | ||||
2381 | |||||
2382 | // set up exception handlers for this instruction if necessary | ||||
2383 | if (i1->can_trap()) { | ||||
2384 | i1->set_exception_handlers(handle_exception(i1)); | ||||
2385 | assert(i1->exception_state() != NULL || !i1->needs_exception_state() || bailed_out(), "handle_exception must set exception state")do { if (!(i1->exception_state() != __null || !i1->needs_exception_state () || bailed_out())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2385, "assert(" "i1->exception_state() != __null || !i1->needs_exception_state() || bailed_out()" ") failed", "handle_exception must set exception state"); :: breakpoint(); } } while (0); | ||||
2386 | } | ||||
2387 | return i1; | ||||
2388 | } | ||||
2389 | |||||
2390 | |||||
2391 | Instruction* GraphBuilder::append(Instruction* instr) { | ||||
2392 | assert(instr->as_StateSplit() == NULL || instr->as_BlockEnd() != NULL, "wrong append used")do { if (!(instr->as_StateSplit() == __null || instr->as_BlockEnd () != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2392, "assert(" "instr->as_StateSplit() == __null || instr->as_BlockEnd() != __null" ") failed", "wrong append used"); ::breakpoint(); } } while ( 0); | ||||
2393 | return append_with_bci(instr, bci()); | ||||
2394 | } | ||||
2395 | |||||
2396 | |||||
2397 | Instruction* GraphBuilder::append_split(StateSplit* instr) { | ||||
2398 | return append_with_bci(instr, bci()); | ||||
2399 | } | ||||
2400 | |||||
2401 | |||||
2402 | void GraphBuilder::null_check(Value value) { | ||||
2403 | if (value->as_NewArray() != NULL__null || value->as_NewInstance() != NULL__null) { | ||||
2404 | return; | ||||
2405 | } else { | ||||
2406 | Constant* con = value->as_Constant(); | ||||
2407 | if (con) { | ||||
2408 | ObjectType* c = con->type()->as_ObjectType(); | ||||
2409 | if (c && c->is_loaded()) { | ||||
2410 | ObjectConstant* oc = c->as_ObjectConstant(); | ||||
2411 | if (!oc || !oc->value()->is_null_object()) { | ||||
2412 | return; | ||||
2413 | } | ||||
2414 | } | ||||
2415 | } | ||||
2416 | } | ||||
2417 | append(new NullCheck(value, copy_state_for_exception())); | ||||
2418 | } | ||||
2419 | |||||
2420 | |||||
2421 | |||||
2422 | XHandlers* GraphBuilder::handle_exception(Instruction* instruction) { | ||||
2423 | if (!has_handler() && (!instruction->needs_exception_state() || instruction->exception_state() != NULL__null)) { | ||||
2424 | assert(instruction->exception_state() == NULLdo { if (!(instruction->exception_state() == __null || instruction ->exception_state()->kind() == ValueStack::EmptyExceptionState || (instruction->exception_state()->kind() == ValueStack ::ExceptionState && _compilation->env()->should_retain_local_variables ()))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2427, "assert(" "instruction->exception_state() == __null || instruction->exception_state()->kind() == ValueStack::EmptyExceptionState || (instruction->exception_state()->kind() == ValueStack::ExceptionState && _compilation->env()->should_retain_local_variables())" ") failed", "exception_state should be of exception kind"); :: breakpoint(); } } while (0) | ||||
2425 | || instruction->exception_state()->kind() == ValueStack::EmptyExceptionStatedo { if (!(instruction->exception_state() == __null || instruction ->exception_state()->kind() == ValueStack::EmptyExceptionState || (instruction->exception_state()->kind() == ValueStack ::ExceptionState && _compilation->env()->should_retain_local_variables ()))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2427, "assert(" "instruction->exception_state() == __null || instruction->exception_state()->kind() == ValueStack::EmptyExceptionState || (instruction->exception_state()->kind() == ValueStack::ExceptionState && _compilation->env()->should_retain_local_variables())" ") failed", "exception_state should be of exception kind"); :: breakpoint(); } } while (0) | ||||
2426 | || (instruction->exception_state()->kind() == ValueStack::ExceptionState && _compilation->env()->should_retain_local_variables()),do { if (!(instruction->exception_state() == __null || instruction ->exception_state()->kind() == ValueStack::EmptyExceptionState || (instruction->exception_state()->kind() == ValueStack ::ExceptionState && _compilation->env()->should_retain_local_variables ()))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2427, "assert(" "instruction->exception_state() == __null || instruction->exception_state()->kind() == ValueStack::EmptyExceptionState || (instruction->exception_state()->kind() == ValueStack::ExceptionState && _compilation->env()->should_retain_local_variables())" ") failed", "exception_state should be of exception kind"); :: breakpoint(); } } while (0) | ||||
2427 | "exception_state should be of exception kind")do { if (!(instruction->exception_state() == __null || instruction ->exception_state()->kind() == ValueStack::EmptyExceptionState || (instruction->exception_state()->kind() == ValueStack ::ExceptionState && _compilation->env()->should_retain_local_variables ()))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2427, "assert(" "instruction->exception_state() == __null || instruction->exception_state()->kind() == ValueStack::EmptyExceptionState || (instruction->exception_state()->kind() == ValueStack::ExceptionState && _compilation->env()->should_retain_local_variables())" ") failed", "exception_state should be of exception kind"); :: breakpoint(); } } while (0); | ||||
2428 | return new XHandlers(); | ||||
2429 | } | ||||
2430 | |||||
2431 | XHandlers* exception_handlers = new XHandlers(); | ||||
2432 | ScopeData* cur_scope_data = scope_data(); | ||||
2433 | ValueStack* cur_state = instruction->state_before(); | ||||
2434 | ValueStack* prev_state = NULL__null; | ||||
2435 | int scope_count = 0; | ||||
2436 | |||||
2437 | assert(cur_state != NULL, "state_before must be set")do { if (!(cur_state != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2437, "assert(" "cur_state != __null" ") failed", "state_before must be set" ); ::breakpoint(); } } while (0); | ||||
2438 | do { | ||||
2439 | int cur_bci = cur_state->bci(); | ||||
2440 | assert(cur_scope_data->scope() == cur_state->scope(), "scopes do not match")do { if (!(cur_scope_data->scope() == cur_state->scope( ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2440, "assert(" "cur_scope_data->scope() == cur_state->scope()" ") failed", "scopes do not match"); ::breakpoint(); } } while (0); | ||||
2441 | assert(cur_bci == SynchronizationEntryBCI || cur_bci == cur_scope_data->stream()->cur_bci(), "invalid bci")do { if (!(cur_bci == SynchronizationEntryBCI || cur_bci == cur_scope_data ->stream()->cur_bci())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2441, "assert(" "cur_bci == SynchronizationEntryBCI || cur_bci == cur_scope_data->stream()->cur_bci()" ") failed", "invalid bci"); ::breakpoint(); } } while (0); | ||||
2442 | |||||
2443 | // join with all potential exception handlers | ||||
2444 | XHandlers* list = cur_scope_data->xhandlers(); | ||||
2445 | const int n = list->length(); | ||||
2446 | for (int i = 0; i < n; i++) { | ||||
2447 | XHandler* h = list->handler_at(i); | ||||
2448 | if (h->covers(cur_bci)) { | ||||
2449 | // h is a potential exception handler => join it | ||||
2450 | compilation()->set_has_exception_handlers(true); | ||||
2451 | |||||
2452 | BlockBegin* entry = h->entry_block(); | ||||
2453 | if (entry == block()) { | ||||
2454 | // It's acceptable for an exception handler to cover itself | ||||
2455 | // but we don't handle that in the parser currently. It's | ||||
2456 | // very rare so we bailout instead of trying to handle it. | ||||
2457 | BAILOUT_("exception handler covers itself", exception_handlers){ bailout("exception handler covers itself"); return exception_handlers ; }; | ||||
2458 | } | ||||
2459 | assert(entry->bci() == h->handler_bci(), "must match")do { if (!(entry->bci() == h->handler_bci())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2459, "assert(" "entry->bci() == h->handler_bci()" ") failed" , "must match"); ::breakpoint(); } } while (0); | ||||
2460 | assert(entry->bci() == -1 || entry == cur_scope_data->block_at(entry->bci()), "blocks must correspond")do { if (!(entry->bci() == -1 || entry == cur_scope_data-> block_at(entry->bci()))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2460, "assert(" "entry->bci() == -1 || entry == cur_scope_data->block_at(entry->bci())" ") failed", "blocks must correspond"); ::breakpoint(); } } while (0); | ||||
2461 | |||||
2462 | // previously this was a BAILOUT, but this is not necessary | ||||
2463 | // now because asynchronous exceptions are not handled this way. | ||||
2464 | assert(entry->state() == NULL || cur_state->total_locks_size() == entry->state()->total_locks_size(), "locks do not match")do { if (!(entry->state() == __null || cur_state->total_locks_size () == entry->state()->total_locks_size())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2464, "assert(" "entry->state() == __null || cur_state->total_locks_size() == entry->state()->total_locks_size()" ") failed", "locks do not match"); ::breakpoint(); } } while (0); | ||||
2465 | |||||
2466 | // xhandler start with an empty expression stack | ||||
2467 | if (cur_state->stack_size() != 0) { | ||||
2468 | cur_state = cur_state->copy(ValueStack::ExceptionState, cur_state->bci()); | ||||
2469 | } | ||||
2470 | if (instruction->exception_state() == NULL__null) { | ||||
2471 | instruction->set_exception_state(cur_state); | ||||
2472 | } | ||||
2473 | |||||
2474 | // Note: Usually this join must work. However, very | ||||
2475 | // complicated jsr-ret structures where we don't ret from | ||||
2476 | // the subroutine can cause the objects on the monitor | ||||
2477 | // stacks to not match because blocks can be parsed twice. | ||||
2478 | // The only test case we've seen so far which exhibits this | ||||
2479 | // problem is caught by the infinite recursion test in | ||||
2480 | // GraphBuilder::jsr() if the join doesn't work. | ||||
2481 | if (!entry->try_merge(cur_state)) { | ||||
2482 | BAILOUT_("error while joining with exception handler, prob. due to complicated jsr/rets", exception_handlers){ bailout("error while joining with exception handler, prob. due to complicated jsr/rets" ); return exception_handlers; }; | ||||
2483 | } | ||||
2484 | |||||
2485 | // add current state for correct handling of phi functions at begin of xhandler | ||||
2486 | int phi_operand = entry->add_exception_state(cur_state); | ||||
2487 | |||||
2488 | // add entry to the list of xhandlers of this block | ||||
2489 | _block->add_exception_handler(entry); | ||||
2490 | |||||
2491 | // add back-edge from xhandler entry to this block | ||||
2492 | if (!entry->is_predecessor(_block)) { | ||||
2493 | entry->add_predecessor(_block); | ||||
2494 | } | ||||
2495 | |||||
2496 | // clone XHandler because phi_operand and scope_count can not be shared | ||||
2497 | XHandler* new_xhandler = new XHandler(h); | ||||
2498 | new_xhandler->set_phi_operand(phi_operand); | ||||
2499 | new_xhandler->set_scope_count(scope_count); | ||||
2500 | exception_handlers->append(new_xhandler); | ||||
2501 | |||||
2502 | // fill in exception handler subgraph lazily | ||||
2503 | assert(!entry->is_set(BlockBegin::was_visited_flag), "entry must not be visited yet")do { if (!(!entry->is_set(BlockBegin::was_visited_flag))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2503, "assert(" "!entry->is_set(BlockBegin::was_visited_flag)" ") failed", "entry must not be visited yet"); ::breakpoint() ; } } while (0); | ||||
2504 | cur_scope_data->add_to_work_list(entry); | ||||
2505 | |||||
2506 | // stop when reaching catchall | ||||
2507 | if (h->catch_type() == 0) { | ||||
2508 | return exception_handlers; | ||||
2509 | } | ||||
2510 | } | ||||
2511 | } | ||||
2512 | |||||
2513 | if (exception_handlers->length() == 0) { | ||||
2514 | // This scope and all callees do not handle exceptions, so the local | ||||
2515 | // variables of this scope are not needed. However, the scope itself is | ||||
2516 | // required for a correct exception stack trace -> clear out the locals. | ||||
2517 | if (_compilation->env()->should_retain_local_variables()) { | ||||
2518 | cur_state = cur_state->copy(ValueStack::ExceptionState, cur_state->bci()); | ||||
2519 | } else { | ||||
2520 | cur_state = cur_state->copy(ValueStack::EmptyExceptionState, cur_state->bci()); | ||||
2521 | } | ||||
2522 | if (prev_state != NULL__null) { | ||||
2523 | prev_state->set_caller_state(cur_state); | ||||
2524 | } | ||||
2525 | if (instruction->exception_state() == NULL__null) { | ||||
2526 | instruction->set_exception_state(cur_state); | ||||
2527 | } | ||||
2528 | } | ||||
2529 | |||||
2530 | // Set up iteration for next time. | ||||
2531 | // If parsing a jsr, do not grab exception handlers from the | ||||
2532 | // parent scopes for this method (already got them, and they | ||||
2533 | // needed to be cloned) | ||||
2534 | |||||
2535 | while (cur_scope_data->parsing_jsr()) { | ||||
2536 | cur_scope_data = cur_scope_data->parent(); | ||||
2537 | } | ||||
2538 | |||||
2539 | assert(cur_scope_data->scope() == cur_state->scope(), "scopes do not match")do { if (!(cur_scope_data->scope() == cur_state->scope( ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2539, "assert(" "cur_scope_data->scope() == cur_state->scope()" ") failed", "scopes do not match"); ::breakpoint(); } } while (0); | ||||
2540 | assert(cur_state->locks_size() == 0 || cur_state->locks_size() == 1, "unlocking must be done in a catchall exception handler")do { if (!(cur_state->locks_size() == 0 || cur_state->locks_size () == 1)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2540, "assert(" "cur_state->locks_size() == 0 || cur_state->locks_size() == 1" ") failed", "unlocking must be done in a catchall exception handler" ); ::breakpoint(); } } while (0); | ||||
2541 | |||||
2542 | prev_state = cur_state; | ||||
2543 | cur_state = cur_state->caller_state(); | ||||
2544 | cur_scope_data = cur_scope_data->parent(); | ||||
2545 | scope_count++; | ||||
2546 | } while (cur_scope_data != NULL__null); | ||||
2547 | |||||
2548 | return exception_handlers; | ||||
2549 | } | ||||
2550 | |||||
2551 | |||||
2552 | // Helper class for simplifying Phis. | ||||
2553 | class PhiSimplifier : public BlockClosure { | ||||
2554 | private: | ||||
2555 | bool _has_substitutions; | ||||
2556 | Value simplify(Value v); | ||||
2557 | |||||
2558 | public: | ||||
2559 | PhiSimplifier(BlockBegin* start) : _has_substitutions(false) { | ||||
2560 | start->iterate_preorder(this); | ||||
2561 | if (_has_substitutions) { | ||||
2562 | SubstitutionResolver sr(start); | ||||
2563 | } | ||||
2564 | } | ||||
2565 | void block_do(BlockBegin* b); | ||||
2566 | bool has_substitutions() const { return _has_substitutions; } | ||||
2567 | }; | ||||
2568 | |||||
2569 | |||||
2570 | Value PhiSimplifier::simplify(Value v) { | ||||
2571 | Phi* phi = v->as_Phi(); | ||||
2572 | |||||
2573 | if (phi == NULL__null) { | ||||
2574 | // no phi function | ||||
2575 | return v; | ||||
2576 | } else if (v->has_subst()) { | ||||
2577 | // already substituted; subst can be phi itself -> simplify | ||||
2578 | return simplify(v->subst()); | ||||
2579 | } else if (phi->is_set(Phi::cannot_simplify)) { | ||||
2580 | // already tried to simplify phi before | ||||
2581 | return phi; | ||||
2582 | } else if (phi->is_set(Phi::visited)) { | ||||
2583 | // break cycles in phi functions | ||||
2584 | return phi; | ||||
2585 | } else if (phi->type()->is_illegal()) { | ||||
2586 | // illegal phi functions are ignored anyway | ||||
2587 | return phi; | ||||
2588 | |||||
2589 | } else { | ||||
2590 | // mark phi function as processed to break cycles in phi functions | ||||
2591 | phi->set(Phi::visited); | ||||
2592 | |||||
2593 | // simplify x = [y, x] and x = [y, y] to y | ||||
2594 | Value subst = NULL__null; | ||||
2595 | int opd_count = phi->operand_count(); | ||||
2596 | for (int i = 0; i < opd_count; i++) { | ||||
2597 | Value opd = phi->operand_at(i); | ||||
2598 | assert(opd != NULL, "Operand must exist!")do { if (!(opd != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2598, "assert(" "opd != __null" ") failed", "Operand must exist!" ); ::breakpoint(); } } while (0); | ||||
2599 | |||||
2600 | if (opd->type()->is_illegal()) { | ||||
2601 | // if one operand is illegal, the entire phi function is illegal | ||||
2602 | phi->make_illegal(); | ||||
2603 | phi->clear(Phi::visited); | ||||
2604 | return phi; | ||||
2605 | } | ||||
2606 | |||||
2607 | Value new_opd = simplify(opd); | ||||
2608 | assert(new_opd != NULL, "Simplified operand must exist!")do { if (!(new_opd != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2608, "assert(" "new_opd != __null" ") failed", "Simplified operand must exist!" ); ::breakpoint(); } } while (0); | ||||
2609 | |||||
2610 | if (new_opd != phi && new_opd != subst) { | ||||
2611 | if (subst == NULL__null) { | ||||
2612 | subst = new_opd; | ||||
2613 | } else { | ||||
2614 | // no simplification possible | ||||
2615 | phi->set(Phi::cannot_simplify); | ||||
2616 | phi->clear(Phi::visited); | ||||
2617 | return phi; | ||||
2618 | } | ||||
2619 | } | ||||
2620 | } | ||||
2621 | |||||
2622 | // sucessfully simplified phi function | ||||
2623 | assert(subst != NULL, "illegal phi function")do { if (!(subst != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2623, "assert(" "subst != __null" ") failed", "illegal phi function" ); ::breakpoint(); } } while (0); | ||||
2624 | _has_substitutions = true; | ||||
2625 | phi->clear(Phi::visited); | ||||
2626 | phi->set_subst(subst); | ||||
2627 | |||||
2628 | #ifndef PRODUCT | ||||
2629 | if (PrintPhiFunctions) { | ||||
2630 | tty->print_cr("simplified phi function %c%d to %c%d (Block B%d)", phi->type()->tchar(), phi->id(), subst->type()->tchar(), subst->id(), phi->block()->block_id()); | ||||
2631 | } | ||||
2632 | #endif | ||||
2633 | |||||
2634 | return subst; | ||||
2635 | } | ||||
2636 | } | ||||
2637 | |||||
2638 | |||||
2639 | void PhiSimplifier::block_do(BlockBegin* b) { | ||||
2640 | for_each_phi_fun(b, phi,{ int cur_index; ValueStack* cur_state = b->state(); Value value; { int temp__2642 = cur_state->stack_size(); for (cur_index = 0; cur_index < temp__2642 && (value = cur_state ->stack_at(cur_index), true); cur_index += value->type( )->size()) { Phi* phi = value->as_Phi(); if (phi != __null && phi->block() == b) { simplify(phi);; } } } { int temp__2642 = cur_state->locals_size(); for (cur_index = 0 ; cur_index < temp__2642 && (value = cur_state-> local_at(cur_index), true); cur_index += (value == __null || value ->type()->is_illegal() ? 1 : value->type()->size( ))) if (value != __null) { Phi* phi = value->as_Phi(); if ( phi != __null && phi->block() == b) { simplify(phi );; } } } } | ||||
2641 | simplify(phi);{ int cur_index; ValueStack* cur_state = b->state(); Value value; { int temp__2642 = cur_state->stack_size(); for (cur_index = 0; cur_index < temp__2642 && (value = cur_state ->stack_at(cur_index), true); cur_index += value->type( )->size()) { Phi* phi = value->as_Phi(); if (phi != __null && phi->block() == b) { simplify(phi);; } } } { int temp__2642 = cur_state->locals_size(); for (cur_index = 0 ; cur_index < temp__2642 && (value = cur_state-> local_at(cur_index), true); cur_index += (value == __null || value ->type()->is_illegal() ? 1 : value->type()->size( ))) if (value != __null) { Phi* phi = value->as_Phi(); if ( phi != __null && phi->block() == b) { simplify(phi );; } } } } | ||||
2642 | ){ int cur_index; ValueStack* cur_state = b->state(); Value value; { int temp__2642 = cur_state->stack_size(); for (cur_index = 0; cur_index < temp__2642 && (value = cur_state ->stack_at(cur_index), true); cur_index += value->type( )->size()) { Phi* phi = value->as_Phi(); if (phi != __null && phi->block() == b) { simplify(phi);; } } } { int temp__2642 = cur_state->locals_size(); for (cur_index = 0 ; cur_index < temp__2642 && (value = cur_state-> local_at(cur_index), true); cur_index += (value == __null || value ->type()->is_illegal() ? 1 : value->type()->size( ))) if (value != __null) { Phi* phi = value->as_Phi(); if ( phi != __null && phi->block() == b) { simplify(phi );; } } } }; | ||||
2643 | |||||
2644 | #ifdef ASSERT1 | ||||
2645 | for_each_phi_fun(b, phi,{ int cur_index; ValueStack* cur_state = b->state(); Value value; { int temp__2647 = cur_state->stack_size(); for (cur_index = 0; cur_index < temp__2647 && (value = cur_state ->stack_at(cur_index), true); cur_index += value->type( )->size()) { Phi* phi = value->as_Phi(); if (phi != __null && phi->block() == b) { do { if (!(phi->operand_count () != 1 || phi->subst() != phi || phi->is_illegal())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2646, "assert(" "phi->operand_count() != 1 || phi->subst() != phi || phi->is_illegal()" ") failed", "missed trivial simplification"); ::breakpoint() ; } } while (0);; } } } { int temp__2647 = cur_state->locals_size (); for (cur_index = 0; cur_index < temp__2647 && ( value = cur_state->local_at(cur_index), true); cur_index += (value == __null || value->type()->is_illegal() ? 1 : value ->type()->size())) if (value != __null) { Phi* phi = value ->as_Phi(); if (phi != __null && phi->block() == b) { do { if (!(phi->operand_count() != 1 || phi->subst () != phi || phi->is_illegal())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2646, "assert(" "phi->operand_count() != 1 || phi->subst() != phi || phi->is_illegal()" ") failed", "missed trivial simplification"); ::breakpoint() ; } } while (0);; } } } } | ||||
2646 | assert(phi->operand_count() != 1 || phi->subst() != phi || phi->is_illegal(), "missed trivial simplification");{ int cur_index; ValueStack* cur_state = b->state(); Value value; { int temp__2647 = cur_state->stack_size(); for (cur_index = 0; cur_index < temp__2647 && (value = cur_state ->stack_at(cur_index), true); cur_index += value->type( )->size()) { Phi* phi = value->as_Phi(); if (phi != __null && phi->block() == b) { do { if (!(phi->operand_count () != 1 || phi->subst() != phi || phi->is_illegal())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2646, "assert(" "phi->operand_count() != 1 || phi->subst() != phi || phi->is_illegal()" ") failed", "missed trivial simplification"); ::breakpoint() ; } } while (0);; } } } { int temp__2647 = cur_state->locals_size (); for (cur_index = 0; cur_index < temp__2647 && ( value = cur_state->local_at(cur_index), true); cur_index += (value == __null || value->type()->is_illegal() ? 1 : value ->type()->size())) if (value != __null) { Phi* phi = value ->as_Phi(); if (phi != __null && phi->block() == b) { do { if (!(phi->operand_count() != 1 || phi->subst () != phi || phi->is_illegal())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2646, "assert(" "phi->operand_count() != 1 || phi->subst() != phi || phi->is_illegal()" ") failed", "missed trivial simplification"); ::breakpoint() ; } } while (0);; } } } } | ||||
2647 | ){ int cur_index; ValueStack* cur_state = b->state(); Value value; { int temp__2647 = cur_state->stack_size(); for (cur_index = 0; cur_index < temp__2647 && (value = cur_state ->stack_at(cur_index), true); cur_index += value->type( )->size()) { Phi* phi = value->as_Phi(); if (phi != __null && phi->block() == b) { do { if (!(phi->operand_count () != 1 || phi->subst() != phi || phi->is_illegal())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2646, "assert(" "phi->operand_count() != 1 || phi->subst() != phi || phi->is_illegal()" ") failed", "missed trivial simplification"); ::breakpoint() ; } } while (0);; } } } { int temp__2647 = cur_state->locals_size (); for (cur_index = 0; cur_index < temp__2647 && ( value = cur_state->local_at(cur_index), true); cur_index += (value == __null || value->type()->is_illegal() ? 1 : value ->type()->size())) if (value != __null) { Phi* phi = value ->as_Phi(); if (phi != __null && phi->block() == b) { do { if (!(phi->operand_count() != 1 || phi->subst () != phi || phi->is_illegal())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2646, "assert(" "phi->operand_count() != 1 || phi->subst() != phi || phi->is_illegal()" ") failed", "missed trivial simplification"); ::breakpoint() ; } } while (0);; } } } }; | ||||
2648 | |||||
2649 | ValueStack* state = b->state()->caller_state(); | ||||
2650 | for_each_state_value(state, value,{ int cur_index; ValueStack* cur_state = state; Value value; for (; cur_state != __null; cur_state = cur_state->caller_state ()) { { int temp__2653 = cur_state->locals_size(); for (cur_index = 0; cur_index < temp__2653 && (value = cur_state ->local_at(cur_index), true); cur_index += (value == __null || value->type()->is_illegal() ? 1 : value->type()-> size())) if (value != __null) { Phi* phi = value->as_Phi() ; do { if (!(phi == __null || phi->block() != b)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2652, "assert(" "phi == __null || phi->block() != b" ") failed" , "must not have phi function to simplify in caller state"); :: breakpoint(); } } while (0);; } } { int temp__2653 = cur_state ->stack_size(); for (cur_index = 0; cur_index < temp__2653 && (value = cur_state->stack_at(cur_index), true) ; cur_index += value->type()->size()) { Phi* phi = value ->as_Phi(); do { if (!(phi == __null || phi->block() != b)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2652, "assert(" "phi == __null || phi->block() != b" ") failed" , "must not have phi function to simplify in caller state"); :: breakpoint(); } } while (0);; } } } } | ||||
2651 | Phi* phi = value->as_Phi();{ int cur_index; ValueStack* cur_state = state; Value value; for (; cur_state != __null; cur_state = cur_state->caller_state ()) { { int temp__2653 = cur_state->locals_size(); for (cur_index = 0; cur_index < temp__2653 && (value = cur_state ->local_at(cur_index), true); cur_index += (value == __null || value->type()->is_illegal() ? 1 : value->type()-> size())) if (value != __null) { Phi* phi = value->as_Phi() ; do { if (!(phi == __null || phi->block() != b)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2652, "assert(" "phi == __null || phi->block() != b" ") failed" , "must not have phi function to simplify in caller state"); :: breakpoint(); } } while (0);; } } { int temp__2653 = cur_state ->stack_size(); for (cur_index = 0; cur_index < temp__2653 && (value = cur_state->stack_at(cur_index), true) ; cur_index += value->type()->size()) { Phi* phi = value ->as_Phi(); do { if (!(phi == __null || phi->block() != b)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2652, "assert(" "phi == __null || phi->block() != b" ") failed" , "must not have phi function to simplify in caller state"); :: breakpoint(); } } while (0);; } } } } | ||||
2652 | assert(phi == NULL || phi->block() != b, "must not have phi function to simplify in caller state");{ int cur_index; ValueStack* cur_state = state; Value value; for (; cur_state != __null; cur_state = cur_state->caller_state ()) { { int temp__2653 = cur_state->locals_size(); for (cur_index = 0; cur_index < temp__2653 && (value = cur_state ->local_at(cur_index), true); cur_index += (value == __null || value->type()->is_illegal() ? 1 : value->type()-> size())) if (value != __null) { Phi* phi = value->as_Phi() ; do { if (!(phi == __null || phi->block() != b)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2652, "assert(" "phi == __null || phi->block() != b" ") failed" , "must not have phi function to simplify in caller state"); :: breakpoint(); } } while (0);; } } { int temp__2653 = cur_state ->stack_size(); for (cur_index = 0; cur_index < temp__2653 && (value = cur_state->stack_at(cur_index), true) ; cur_index += value->type()->size()) { Phi* phi = value ->as_Phi(); do { if (!(phi == __null || phi->block() != b)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2652, "assert(" "phi == __null || phi->block() != b" ") failed" , "must not have phi function to simplify in caller state"); :: breakpoint(); } } while (0);; } } } } | ||||
2653 | ){ int cur_index; ValueStack* cur_state = state; Value value; for (; cur_state != __null; cur_state = cur_state->caller_state ()) { { int temp__2653 = cur_state->locals_size(); for (cur_index = 0; cur_index < temp__2653 && (value = cur_state ->local_at(cur_index), true); cur_index += (value == __null || value->type()->is_illegal() ? 1 : value->type()-> size())) if (value != __null) { Phi* phi = value->as_Phi() ; do { if (!(phi == __null || phi->block() != b)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2652, "assert(" "phi == __null || phi->block() != b" ") failed" , "must not have phi function to simplify in caller state"); :: breakpoint(); } } while (0);; } } { int temp__2653 = cur_state ->stack_size(); for (cur_index = 0; cur_index < temp__2653 && (value = cur_state->stack_at(cur_index), true) ; cur_index += value->type()->size()) { Phi* phi = value ->as_Phi(); do { if (!(phi == __null || phi->block() != b)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2652, "assert(" "phi == __null || phi->block() != b" ") failed" , "must not have phi function to simplify in caller state"); :: breakpoint(); } } while (0);; } } } }; | ||||
2654 | #endif | ||||
2655 | } | ||||
2656 | |||||
2657 | // This method is called after all blocks are filled with HIR instructions | ||||
2658 | // It eliminates all Phi functions of the form x = [y, y] and x = [y, x] | ||||
2659 | void GraphBuilder::eliminate_redundant_phis(BlockBegin* start) { | ||||
2660 | PhiSimplifier simplifier(start); | ||||
2661 | } | ||||
2662 | |||||
2663 | |||||
2664 | void GraphBuilder::connect_to_end(BlockBegin* beg) { | ||||
2665 | // setup iteration | ||||
2666 | kill_all(); | ||||
2667 | _block = beg; | ||||
2668 | _state = beg->state()->copy_for_parsing(); | ||||
2669 | _last = beg; | ||||
2670 | iterate_bytecodes_for_block(beg->bci()); | ||||
2671 | } | ||||
2672 | |||||
2673 | |||||
2674 | BlockEnd* GraphBuilder::iterate_bytecodes_for_block(int bci) { | ||||
2675 | #ifndef PRODUCT | ||||
2676 | if (PrintIRDuringConstruction) { | ||||
| |||||
2677 | tty->cr(); | ||||
2678 | InstructionPrinter ip; | ||||
2679 | ip.print_instr(_block); tty->cr(); | ||||
2680 | ip.print_stack(_block->state()); tty->cr(); | ||||
2681 | ip.print_inline_level(_block); | ||||
2682 | ip.print_head(); | ||||
2683 | tty->print_cr("locals size: %d stack size: %d", state()->locals_size(), state()->stack_size()); | ||||
2684 | } | ||||
2685 | #endif | ||||
2686 | _skip_block = false; | ||||
2687 | assert(state() != NULL, "ValueStack missing!")do { if (!(state() != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2687, "assert(" "state() != __null" ") failed", "ValueStack missing!" ); ::breakpoint(); } } while (0); | ||||
2688 | CompileLog* log = compilation()->log(); | ||||
2689 | ciBytecodeStream s(method()); | ||||
2690 | s.reset_to_bci(bci); | ||||
2691 | int prev_bci = bci; | ||||
2692 | scope_data()->set_stream(&s); | ||||
2693 | // iterate | ||||
2694 | Bytecodes::Code code = Bytecodes::_illegal; | ||||
2695 | bool push_exception = false; | ||||
2696 | |||||
2697 | if (block()->is_set(BlockBegin::exception_entry_flag) && block()->next() == NULL__null) { | ||||
2698 | // first thing in the exception entry block should be the exception object. | ||||
2699 | push_exception = true; | ||||
2700 | } | ||||
2701 | |||||
2702 | bool ignore_return = scope_data()->ignore_return(); | ||||
2703 | |||||
2704 | while (!bailed_out() && last()->as_BlockEnd() == NULL__null && | ||||
2705 | (code = stream()->next()) != ciBytecodeStream::EOBC() && | ||||
2706 | (block_at(s.cur_bci()) == NULL__null || block_at(s.cur_bci()) == block())) { | ||||
2707 | assert(state()->kind() == ValueStack::Parsing, "invalid state kind")do { if (!(state()->kind() == ValueStack::Parsing)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2707, "assert(" "state()->kind() == ValueStack::Parsing" ") failed", "invalid state kind"); ::breakpoint(); } } while (0); | ||||
2708 | |||||
2709 | if (log != NULL__null) | ||||
2710 | log->set_context("bc code='%d' bci='%d'", (int)code, s.cur_bci()); | ||||
2711 | |||||
2712 | // Check for active jsr during OSR compilation | ||||
2713 | if (compilation()->is_osr_compile() | ||||
2714 | && scope()->is_top_scope() | ||||
2715 | && parsing_jsr() | ||||
2716 | && s.cur_bci() == compilation()->osr_bci()) { | ||||
2717 | bailout("OSR not supported while a jsr is active"); | ||||
2718 | } | ||||
2719 | |||||
2720 | if (push_exception
| ||||
2721 | apush(append(new ExceptionObject())); | ||||
2722 | push_exception = false; | ||||
2723 | } | ||||
2724 | |||||
2725 | // handle bytecode | ||||
2726 | switch (code) { | ||||
2727 | case Bytecodes::_nop : /* nothing to do */ break; | ||||
2728 | case Bytecodes::_aconst_null : apush(append(new Constant(objectNull ))); break; | ||||
2729 | case Bytecodes::_iconst_m1 : ipush(append(new Constant(new IntConstant (-1)))); break; | ||||
2730 | case Bytecodes::_iconst_0 : ipush(append(new Constant(intZero ))); break; | ||||
2731 | case Bytecodes::_iconst_1 : ipush(append(new Constant(intOne ))); break; | ||||
2732 | case Bytecodes::_iconst_2 : ipush(append(new Constant(new IntConstant ( 2)))); break; | ||||
2733 | case Bytecodes::_iconst_3 : ipush(append(new Constant(new IntConstant ( 3)))); break; | ||||
2734 | case Bytecodes::_iconst_4 : ipush(append(new Constant(new IntConstant ( 4)))); break; | ||||
2735 | case Bytecodes::_iconst_5 : ipush(append(new Constant(new IntConstant ( 5)))); break; | ||||
2736 | case Bytecodes::_lconst_0 : lpush(append(new Constant(new LongConstant ( 0)))); break; | ||||
2737 | case Bytecodes::_lconst_1 : lpush(append(new Constant(new LongConstant ( 1)))); break; | ||||
2738 | case Bytecodes::_fconst_0 : fpush(append(new Constant(new FloatConstant ( 0)))); break; | ||||
2739 | case Bytecodes::_fconst_1 : fpush(append(new Constant(new FloatConstant ( 1)))); break; | ||||
2740 | case Bytecodes::_fconst_2 : fpush(append(new Constant(new FloatConstant ( 2)))); break; | ||||
2741 | case Bytecodes::_dconst_0 : dpush(append(new Constant(new DoubleConstant( 0)))); break; | ||||
2742 | case Bytecodes::_dconst_1 : dpush(append(new Constant(new DoubleConstant( 1)))); break; | ||||
2743 | case Bytecodes::_bipush : ipush(append(new Constant(new IntConstant(((signed char*)s.cur_bcp())[1])))); break; | ||||
2744 | case Bytecodes::_sipush : ipush(append(new Constant(new IntConstant((short)Bytes::get_Java_u2(s.cur_bcp()+1))))); break; | ||||
2745 | case Bytecodes::_ldc : // fall through | ||||
2746 | case Bytecodes::_ldc_w : // fall through | ||||
2747 | case Bytecodes::_ldc2_w : load_constant(); break; | ||||
2748 | case Bytecodes::_iload : load_local(intType , s.get_index()); break; | ||||
2749 | case Bytecodes::_lload : load_local(longType , s.get_index()); break; | ||||
2750 | case Bytecodes::_fload : load_local(floatType , s.get_index()); break; | ||||
2751 | case Bytecodes::_dload : load_local(doubleType , s.get_index()); break; | ||||
2752 | case Bytecodes::_aload : load_local(instanceType, s.get_index()); break; | ||||
2753 | case Bytecodes::_iload_0 : load_local(intType , 0); break; | ||||
2754 | case Bytecodes::_iload_1 : load_local(intType , 1); break; | ||||
2755 | case Bytecodes::_iload_2 : load_local(intType , 2); break; | ||||
2756 | case Bytecodes::_iload_3 : load_local(intType , 3); break; | ||||
2757 | case Bytecodes::_lload_0 : load_local(longType , 0); break; | ||||
2758 | case Bytecodes::_lload_1 : load_local(longType , 1); break; | ||||
2759 | case Bytecodes::_lload_2 : load_local(longType , 2); break; | ||||
2760 | case Bytecodes::_lload_3 : load_local(longType , 3); break; | ||||
2761 | case Bytecodes::_fload_0 : load_local(floatType , 0); break; | ||||
2762 | case Bytecodes::_fload_1 : load_local(floatType , 1); break; | ||||
2763 | case Bytecodes::_fload_2 : load_local(floatType , 2); break; | ||||
2764 | case Bytecodes::_fload_3 : load_local(floatType , 3); break; | ||||
2765 | case Bytecodes::_dload_0 : load_local(doubleType, 0); break; | ||||
2766 | case Bytecodes::_dload_1 : load_local(doubleType, 1); break; | ||||
2767 | case Bytecodes::_dload_2 : load_local(doubleType, 2); break; | ||||
2768 | case Bytecodes::_dload_3 : load_local(doubleType, 3); break; | ||||
2769 | case Bytecodes::_aload_0 : load_local(objectType, 0); break; | ||||
2770 | case Bytecodes::_aload_1 : load_local(objectType, 1); break; | ||||
2771 | case Bytecodes::_aload_2 : load_local(objectType, 2); break; | ||||
2772 | case Bytecodes::_aload_3 : load_local(objectType, 3); break; | ||||
2773 | case Bytecodes::_iaload : load_indexed(T_INT ); break; | ||||
2774 | case Bytecodes::_laload : load_indexed(T_LONG ); break; | ||||
2775 | case Bytecodes::_faload : load_indexed(T_FLOAT ); break; | ||||
2776 | case Bytecodes::_daload : load_indexed(T_DOUBLE); break; | ||||
2777 | case Bytecodes::_aaload : load_indexed(T_OBJECT); break; | ||||
2778 | case Bytecodes::_baload : load_indexed(T_BYTE ); break; | ||||
2779 | case Bytecodes::_caload : load_indexed(T_CHAR ); break; | ||||
2780 | case Bytecodes::_saload : load_indexed(T_SHORT ); break; | ||||
2781 | case Bytecodes::_istore : store_local(intType , s.get_index()); break; | ||||
2782 | case Bytecodes::_lstore : store_local(longType , s.get_index()); break; | ||||
2783 | case Bytecodes::_fstore : store_local(floatType , s.get_index()); break; | ||||
2784 | case Bytecodes::_dstore : store_local(doubleType, s.get_index()); break; | ||||
2785 | case Bytecodes::_astore : store_local(objectType, s.get_index()); break; | ||||
2786 | case Bytecodes::_istore_0 : store_local(intType , 0); break; | ||||
2787 | case Bytecodes::_istore_1 : store_local(intType , 1); break; | ||||
2788 | case Bytecodes::_istore_2 : store_local(intType , 2); break; | ||||
2789 | case Bytecodes::_istore_3 : store_local(intType , 3); break; | ||||
2790 | case Bytecodes::_lstore_0 : store_local(longType , 0); break; | ||||
2791 | case Bytecodes::_lstore_1 : store_local(longType , 1); break; | ||||
2792 | case Bytecodes::_lstore_2 : store_local(longType , 2); break; | ||||
2793 | case Bytecodes::_lstore_3 : store_local(longType , 3); break; | ||||
2794 | case Bytecodes::_fstore_0 : store_local(floatType , 0); break; | ||||
2795 | case Bytecodes::_fstore_1 : store_local(floatType , 1); break; | ||||
2796 | case Bytecodes::_fstore_2 : store_local(floatType , 2); break; | ||||
2797 | case Bytecodes::_fstore_3 : store_local(floatType , 3); break; | ||||
2798 | case Bytecodes::_dstore_0 : store_local(doubleType, 0); break; | ||||
2799 | case Bytecodes::_dstore_1 : store_local(doubleType, 1); break; | ||||
2800 | case Bytecodes::_dstore_2 : store_local(doubleType, 2); break; | ||||
2801 | case Bytecodes::_dstore_3 : store_local(doubleType, 3); break; | ||||
2802 | case Bytecodes::_astore_0 : store_local(objectType, 0); break; | ||||
2803 | case Bytecodes::_astore_1 : store_local(objectType, 1); break; | ||||
2804 | case Bytecodes::_astore_2 : store_local(objectType, 2); break; | ||||
2805 | case Bytecodes::_astore_3 : store_local(objectType, 3); break; | ||||
2806 | case Bytecodes::_iastore : store_indexed(T_INT ); break; | ||||
2807 | case Bytecodes::_lastore : store_indexed(T_LONG ); break; | ||||
2808 | case Bytecodes::_fastore : store_indexed(T_FLOAT ); break; | ||||
2809 | case Bytecodes::_dastore : store_indexed(T_DOUBLE); break; | ||||
2810 | case Bytecodes::_aastore : store_indexed(T_OBJECT); break; | ||||
2811 | case Bytecodes::_bastore : store_indexed(T_BYTE ); break; | ||||
2812 | case Bytecodes::_castore : store_indexed(T_CHAR ); break; | ||||
2813 | case Bytecodes::_sastore : store_indexed(T_SHORT ); break; | ||||
2814 | case Bytecodes::_pop : // fall through | ||||
2815 | case Bytecodes::_pop2 : // fall through | ||||
2816 | case Bytecodes::_dup : // fall through | ||||
2817 | case Bytecodes::_dup_x1 : // fall through | ||||
2818 | case Bytecodes::_dup_x2 : // fall through | ||||
2819 | case Bytecodes::_dup2 : // fall through | ||||
2820 | case Bytecodes::_dup2_x1 : // fall through | ||||
2821 | case Bytecodes::_dup2_x2 : // fall through | ||||
2822 | case Bytecodes::_swap : stack_op(code); break; | ||||
2823 | case Bytecodes::_iadd : arithmetic_op(intType , code); break; | ||||
2824 | case Bytecodes::_ladd : arithmetic_op(longType , code); break; | ||||
2825 | case Bytecodes::_fadd : arithmetic_op(floatType , code); break; | ||||
2826 | case Bytecodes::_dadd : arithmetic_op(doubleType, code); break; | ||||
2827 | case Bytecodes::_isub : arithmetic_op(intType , code); break; | ||||
2828 | case Bytecodes::_lsub : arithmetic_op(longType , code); break; | ||||
2829 | case Bytecodes::_fsub : arithmetic_op(floatType , code); break; | ||||
2830 | case Bytecodes::_dsub : arithmetic_op(doubleType, code); break; | ||||
2831 | case Bytecodes::_imul : arithmetic_op(intType , code); break; | ||||
2832 | case Bytecodes::_lmul : arithmetic_op(longType , code); break; | ||||
2833 | case Bytecodes::_fmul : arithmetic_op(floatType , code); break; | ||||
2834 | case Bytecodes::_dmul : arithmetic_op(doubleType, code); break; | ||||
2835 | case Bytecodes::_idiv : arithmetic_op(intType , code, copy_state_for_exception()); break; | ||||
2836 | case Bytecodes::_ldiv : arithmetic_op(longType , code, copy_state_for_exception()); break; | ||||
2837 | case Bytecodes::_fdiv : arithmetic_op(floatType , code); break; | ||||
2838 | case Bytecodes::_ddiv : arithmetic_op(doubleType, code); break; | ||||
2839 | case Bytecodes::_irem : arithmetic_op(intType , code, copy_state_for_exception()); break; | ||||
2840 | case Bytecodes::_lrem : arithmetic_op(longType , code, copy_state_for_exception()); break; | ||||
2841 | case Bytecodes::_frem : arithmetic_op(floatType , code); break; | ||||
2842 | case Bytecodes::_drem : arithmetic_op(doubleType, code); break; | ||||
2843 | case Bytecodes::_ineg : negate_op(intType ); break; | ||||
2844 | case Bytecodes::_lneg : negate_op(longType ); break; | ||||
2845 | case Bytecodes::_fneg : negate_op(floatType ); break; | ||||
2846 | case Bytecodes::_dneg : negate_op(doubleType); break; | ||||
2847 | case Bytecodes::_ishl : shift_op(intType , code); break; | ||||
2848 | case Bytecodes::_lshl : shift_op(longType, code); break; | ||||
2849 | case Bytecodes::_ishr : shift_op(intType , code); break; | ||||
2850 | case Bytecodes::_lshr : shift_op(longType, code); break; | ||||
2851 | case Bytecodes::_iushr : shift_op(intType , code); break; | ||||
2852 | case Bytecodes::_lushr : shift_op(longType, code); break; | ||||
2853 | case Bytecodes::_iand : logic_op(intType , code); break; | ||||
2854 | case Bytecodes::_land : logic_op(longType, code); break; | ||||
2855 | case Bytecodes::_ior : logic_op(intType , code); break; | ||||
2856 | case Bytecodes::_lor : logic_op(longType, code); break; | ||||
2857 | case Bytecodes::_ixor : logic_op(intType , code); break; | ||||
2858 | case Bytecodes::_lxor : logic_op(longType, code); break; | ||||
2859 | case Bytecodes::_iinc : increment(); break; | ||||
2860 | case Bytecodes::_i2l : convert(code, T_INT , T_LONG ); break; | ||||
2861 | case Bytecodes::_i2f : convert(code, T_INT , T_FLOAT ); break; | ||||
2862 | case Bytecodes::_i2d : convert(code, T_INT , T_DOUBLE); break; | ||||
2863 | case Bytecodes::_l2i : convert(code, T_LONG , T_INT ); break; | ||||
2864 | case Bytecodes::_l2f : convert(code, T_LONG , T_FLOAT ); break; | ||||
2865 | case Bytecodes::_l2d : convert(code, T_LONG , T_DOUBLE); break; | ||||
2866 | case Bytecodes::_f2i : convert(code, T_FLOAT , T_INT ); break; | ||||
2867 | case Bytecodes::_f2l : convert(code, T_FLOAT , T_LONG ); break; | ||||
2868 | case Bytecodes::_f2d : convert(code, T_FLOAT , T_DOUBLE); break; | ||||
2869 | case Bytecodes::_d2i : convert(code, T_DOUBLE, T_INT ); break; | ||||
2870 | case Bytecodes::_d2l : convert(code, T_DOUBLE, T_LONG ); break; | ||||
2871 | case Bytecodes::_d2f : convert(code, T_DOUBLE, T_FLOAT ); break; | ||||
2872 | case Bytecodes::_i2b : convert(code, T_INT , T_BYTE ); break; | ||||
2873 | case Bytecodes::_i2c : convert(code, T_INT , T_CHAR ); break; | ||||
2874 | case Bytecodes::_i2s : convert(code, T_INT , T_SHORT ); break; | ||||
2875 | case Bytecodes::_lcmp : compare_op(longType , code); break; | ||||
2876 | case Bytecodes::_fcmpl : compare_op(floatType , code); break; | ||||
2877 | case Bytecodes::_fcmpg : compare_op(floatType , code); break; | ||||
2878 | case Bytecodes::_dcmpl : compare_op(doubleType, code); break; | ||||
2879 | case Bytecodes::_dcmpg : compare_op(doubleType, code); break; | ||||
2880 | case Bytecodes::_ifeq : if_zero(intType , If::eql); break; | ||||
2881 | case Bytecodes::_ifne : if_zero(intType , If::neq); break; | ||||
2882 | case Bytecodes::_iflt : if_zero(intType , If::lss); break; | ||||
2883 | case Bytecodes::_ifge : if_zero(intType , If::geq); break; | ||||
2884 | case Bytecodes::_ifgt : if_zero(intType , If::gtr); break; | ||||
2885 | case Bytecodes::_ifle : if_zero(intType , If::leq); break; | ||||
2886 | case Bytecodes::_if_icmpeq : if_same(intType , If::eql); break; | ||||
2887 | case Bytecodes::_if_icmpne : if_same(intType , If::neq); break; | ||||
2888 | case Bytecodes::_if_icmplt : if_same(intType , If::lss); break; | ||||
2889 | case Bytecodes::_if_icmpge : if_same(intType , If::geq); break; | ||||
2890 | case Bytecodes::_if_icmpgt : if_same(intType , If::gtr); break; | ||||
2891 | case Bytecodes::_if_icmple : if_same(intType , If::leq); break; | ||||
2892 | case Bytecodes::_if_acmpeq : if_same(objectType, If::eql); break; | ||||
2893 | case Bytecodes::_if_acmpne : if_same(objectType, If::neq); break; | ||||
2894 | case Bytecodes::_goto : _goto(s.cur_bci(), s.get_dest()); break; | ||||
2895 | case Bytecodes::_jsr : jsr(s.get_dest()); break; | ||||
2896 | case Bytecodes::_ret : ret(s.get_index()); break; | ||||
2897 | case Bytecodes::_tableswitch : table_switch(); break; | ||||
2898 | case Bytecodes::_lookupswitch : lookup_switch(); break; | ||||
2899 | case Bytecodes::_ireturn : method_return(ipop(), ignore_return); break; | ||||
2900 | case Bytecodes::_lreturn : method_return(lpop(), ignore_return); break; | ||||
2901 | case Bytecodes::_freturn : method_return(fpop(), ignore_return); break; | ||||
2902 | case Bytecodes::_dreturn : method_return(dpop(), ignore_return); break; | ||||
2903 | case Bytecodes::_areturn : method_return(apop(), ignore_return); break; | ||||
2904 | case Bytecodes::_return : method_return(NULL__null , ignore_return); break; | ||||
2905 | case Bytecodes::_getstatic : // fall through | ||||
2906 | case Bytecodes::_putstatic : // fall through | ||||
2907 | case Bytecodes::_getfield : // fall through | ||||
2908 | case Bytecodes::_putfield : access_field(code); break; | ||||
2909 | case Bytecodes::_invokevirtual : // fall through | ||||
2910 | case Bytecodes::_invokespecial : // fall through | ||||
2911 | case Bytecodes::_invokestatic : // fall through | ||||
2912 | case Bytecodes::_invokedynamic : // fall through | ||||
2913 | case Bytecodes::_invokeinterface: invoke(code); break; | ||||
2914 | case Bytecodes::_new : new_instance(s.get_index_u2()); break; | ||||
2915 | case Bytecodes::_newarray : new_type_array(); break; | ||||
2916 | case Bytecodes::_anewarray : new_object_array(); break; | ||||
2917 | case Bytecodes::_arraylength : { ValueStack* state_before = copy_state_for_exception(); ipush(append(new ArrayLength(apop(), state_before))); break; } | ||||
2918 | case Bytecodes::_athrow : throw_op(s.cur_bci()); break; | ||||
2919 | case Bytecodes::_checkcast : check_cast(s.get_index_u2()); break; | ||||
2920 | case Bytecodes::_instanceof : instance_of(s.get_index_u2()); break; | ||||
2921 | case Bytecodes::_monitorenter : monitorenter(apop(), s.cur_bci()); break; | ||||
2922 | case Bytecodes::_monitorexit : monitorexit (apop(), s.cur_bci()); break; | ||||
2923 | case Bytecodes::_wide : ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2923); ::breakpoint(); } while (0); break; | ||||
2924 | case Bytecodes::_multianewarray : new_multi_array(s.cur_bcp()[3]); break; | ||||
2925 | case Bytecodes::_ifnull : if_null(objectType, If::eql); break; | ||||
2926 | case Bytecodes::_ifnonnull : if_null(objectType, If::neq); break; | ||||
2927 | case Bytecodes::_goto_w : _goto(s.cur_bci(), s.get_far_dest()); break; | ||||
2928 | case Bytecodes::_jsr_w : jsr(s.get_far_dest()); break; | ||||
2929 | case Bytecodes::_breakpoint : BAILOUT_("concurrent setting of breakpoint", NULL){ bailout("concurrent setting of breakpoint"); return __null; }; | ||||
2930 | default : ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2930); ::breakpoint(); } while (0); break; | ||||
2931 | } | ||||
2932 | |||||
2933 | if (log != NULL__null) | ||||
2934 | log->clear_context(); // skip marker if nothing was printed | ||||
2935 | |||||
2936 | // save current bci to setup Goto at the end | ||||
2937 | prev_bci = s.cur_bci(); | ||||
2938 | |||||
2939 | } | ||||
2940 | CHECK_BAILOUT_(NULL){ if (bailed_out()) return __null; }; | ||||
2941 | // stop processing of this block (see try_inline_full) | ||||
2942 | if (_skip_block) { | ||||
2943 | _skip_block = false; | ||||
2944 | assert(_last && _last->as_BlockEnd(), "")do { if (!(_last && _last->as_BlockEnd())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2944, "assert(" "_last && _last->as_BlockEnd()" ") failed" , ""); ::breakpoint(); } } while (0); | ||||
2945 | return _last->as_BlockEnd(); | ||||
2946 | } | ||||
2947 | // if there are any, check if last instruction is a BlockEnd instruction | ||||
2948 | BlockEnd* end = last()->as_BlockEnd(); | ||||
2949 | if (end == NULL__null) { | ||||
2950 | // all blocks must end with a BlockEnd instruction => add a Goto | ||||
2951 | end = new Goto(block_at(s.cur_bci()), false); | ||||
2952 | append(end); | ||||
2953 | } | ||||
2954 | assert(end == last()->as_BlockEnd(), "inconsistency")do { if (!(end == last()->as_BlockEnd())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2954, "assert(" "end == last()->as_BlockEnd()" ") failed" , "inconsistency"); ::breakpoint(); } } while (0); | ||||
2955 | |||||
2956 | assert(end->state() != NULL, "state must already be present")do { if (!(end->state() != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2956, "assert(" "end->state() != __null" ") failed", "state must already be present" ); ::breakpoint(); } } while (0); | ||||
2957 | assert(end->as_Return() == NULL || end->as_Throw() == NULL || end->state()->stack_size() == 0, "stack not needed for return and throw")do { if (!(end->as_Return() == __null || end->as_Throw( ) == __null || end->state()->stack_size() == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2957, "assert(" "end->as_Return() == __null || end->as_Throw() == __null || end->state()->stack_size() == 0" ") failed", "stack not needed for return and throw"); ::breakpoint (); } } while (0); | ||||
2958 | |||||
2959 | // connect to begin & set state | ||||
2960 | // NOTE that inlining may have changed the block we are parsing | ||||
2961 | block()->set_end(end); | ||||
2962 | // propagate state | ||||
2963 | for (int i = end->number_of_sux() - 1; i >= 0; i--) { | ||||
2964 | BlockBegin* sux = end->sux_at(i); | ||||
2965 | assert(sux->is_predecessor(block()), "predecessor missing")do { if (!(sux->is_predecessor(block()))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 2965, "assert(" "sux->is_predecessor(block())" ") failed" , "predecessor missing"); ::breakpoint(); } } while (0); | ||||
2966 | // be careful, bailout if bytecodes are strange | ||||
2967 | if (!sux->try_merge(end->state())) BAILOUT_("block join failed", NULL){ bailout("block join failed"); return __null; }; | ||||
2968 | scope_data()->add_to_work_list(end->sux_at(i)); | ||||
2969 | } | ||||
2970 | |||||
2971 | scope_data()->set_stream(NULL__null); | ||||
2972 | |||||
2973 | // done | ||||
2974 | return end; | ||||
2975 | } | ||||
2976 | |||||
2977 | |||||
2978 | void GraphBuilder::iterate_all_blocks(bool start_in_current_block_for_inlining) { | ||||
2979 | do { | ||||
2980 | if (start_in_current_block_for_inlining && !bailed_out()) { | ||||
2981 | iterate_bytecodes_for_block(0); | ||||
2982 | start_in_current_block_for_inlining = false; | ||||
2983 | } else { | ||||
2984 | BlockBegin* b; | ||||
2985 | while ((b = scope_data()->remove_from_work_list()) != NULL__null) { | ||||
2986 | if (!b->is_set(BlockBegin::was_visited_flag)) { | ||||
2987 | if (b->is_set(BlockBegin::osr_entry_flag)) { | ||||
2988 | // we're about to parse the osr entry block, so make sure | ||||
2989 | // we setup the OSR edge leading into this block so that | ||||
2990 | // Phis get setup correctly. | ||||
2991 | setup_osr_entry_block(); | ||||
2992 | // this is no longer the osr entry block, so clear it. | ||||
2993 | b->clear(BlockBegin::osr_entry_flag); | ||||
2994 | } | ||||
2995 | b->set(BlockBegin::was_visited_flag); | ||||
2996 | connect_to_end(b); | ||||
2997 | } | ||||
2998 | } | ||||
2999 | } | ||||
3000 | } while (!bailed_out() && !scope_data()->is_work_list_empty()); | ||||
3001 | } | ||||
3002 | |||||
3003 | |||||
3004 | bool GraphBuilder::_can_trap [Bytecodes::number_of_java_codes]; | ||||
3005 | |||||
3006 | void GraphBuilder::initialize() { | ||||
3007 | // the following bytecodes are assumed to potentially | ||||
3008 | // throw exceptions in compiled code - note that e.g. | ||||
3009 | // monitorexit & the return bytecodes do not throw | ||||
3010 | // exceptions since monitor pairing proved that they | ||||
3011 | // succeed (if monitor pairing succeeded) | ||||
3012 | Bytecodes::Code can_trap_list[] = | ||||
3013 | { Bytecodes::_ldc | ||||
3014 | , Bytecodes::_ldc_w | ||||
3015 | , Bytecodes::_ldc2_w | ||||
3016 | , Bytecodes::_iaload | ||||
3017 | , Bytecodes::_laload | ||||
3018 | , Bytecodes::_faload | ||||
3019 | , Bytecodes::_daload | ||||
3020 | , Bytecodes::_aaload | ||||
3021 | , Bytecodes::_baload | ||||
3022 | , Bytecodes::_caload | ||||
3023 | , Bytecodes::_saload | ||||
3024 | , Bytecodes::_iastore | ||||
3025 | , Bytecodes::_lastore | ||||
3026 | , Bytecodes::_fastore | ||||
3027 | , Bytecodes::_dastore | ||||
3028 | , Bytecodes::_aastore | ||||
3029 | , Bytecodes::_bastore | ||||
3030 | , Bytecodes::_castore | ||||
3031 | , Bytecodes::_sastore | ||||
3032 | , Bytecodes::_idiv | ||||
3033 | , Bytecodes::_ldiv | ||||
3034 | , Bytecodes::_irem | ||||
3035 | , Bytecodes::_lrem | ||||
3036 | , Bytecodes::_getstatic | ||||
3037 | , Bytecodes::_putstatic | ||||
3038 | , Bytecodes::_getfield | ||||
3039 | , Bytecodes::_putfield | ||||
3040 | , Bytecodes::_invokevirtual | ||||
3041 | , Bytecodes::_invokespecial | ||||
3042 | , Bytecodes::_invokestatic | ||||
3043 | , Bytecodes::_invokedynamic | ||||
3044 | , Bytecodes::_invokeinterface | ||||
3045 | , Bytecodes::_new | ||||
3046 | , Bytecodes::_newarray | ||||
3047 | , Bytecodes::_anewarray | ||||
3048 | , Bytecodes::_arraylength | ||||
3049 | , Bytecodes::_athrow | ||||
3050 | , Bytecodes::_checkcast | ||||
3051 | , Bytecodes::_instanceof | ||||
3052 | , Bytecodes::_monitorenter | ||||
3053 | , Bytecodes::_multianewarray | ||||
3054 | }; | ||||
3055 | |||||
3056 | // inititialize trap tables | ||||
3057 | for (int i = 0; i < Bytecodes::number_of_java_codes; i++) { | ||||
3058 | _can_trap[i] = false; | ||||
3059 | } | ||||
3060 | // set standard trap info | ||||
3061 | for (uint j = 0; j < ARRAY_SIZE(can_trap_list)sizeof(array_size_impl(can_trap_list)); j++) { | ||||
3062 | _can_trap[can_trap_list[j]] = true; | ||||
3063 | } | ||||
3064 | } | ||||
3065 | |||||
3066 | |||||
3067 | BlockBegin* GraphBuilder::header_block(BlockBegin* entry, BlockBegin::Flag f, ValueStack* state) { | ||||
3068 | assert(entry->is_set(f), "entry/flag mismatch")do { if (!(entry->is_set(f))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3068, "assert(" "entry->is_set(f)" ") failed", "entry/flag mismatch" ); ::breakpoint(); } } while (0); | ||||
3069 | // create header block | ||||
3070 | BlockBegin* h = new BlockBegin(entry->bci()); | ||||
3071 | h->set_depth_first_number(0); | ||||
3072 | |||||
3073 | Value l = h; | ||||
3074 | BlockEnd* g = new Goto(entry, false); | ||||
3075 | l->set_next(g, entry->bci()); | ||||
3076 | h->set_end(g); | ||||
3077 | h->set(f); | ||||
3078 | // setup header block end state | ||||
3079 | ValueStack* s = state->copy(ValueStack::StateAfter, entry->bci()); // can use copy since stack is empty (=> no phis) | ||||
3080 | assert(s->stack_is_empty(), "must have empty stack at entry point")do { if (!(s->stack_is_empty())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3080, "assert(" "s->stack_is_empty()" ") failed", "must have empty stack at entry point" ); ::breakpoint(); } } while (0); | ||||
3081 | g->set_state(s); | ||||
3082 | return h; | ||||
3083 | } | ||||
3084 | |||||
3085 | |||||
3086 | |||||
3087 | BlockBegin* GraphBuilder::setup_start_block(int osr_bci, BlockBegin* std_entry, BlockBegin* osr_entry, ValueStack* state) { | ||||
3088 | BlockBegin* start = new BlockBegin(0); | ||||
3089 | |||||
3090 | // This code eliminates the empty start block at the beginning of | ||||
3091 | // each method. Previously, each method started with the | ||||
3092 | // start-block created below, and this block was followed by the | ||||
3093 | // header block that was always empty. This header block is only | ||||
3094 | // necessary if std_entry is also a backward branch target because | ||||
3095 | // then phi functions may be necessary in the header block. It's | ||||
3096 | // also necessary when profiling so that there's a single block that | ||||
3097 | // can increment the the counters. | ||||
3098 | // In addition, with range check elimination, we may need a valid block | ||||
3099 | // that dominates all the rest to insert range predicates. | ||||
3100 | BlockBegin* new_header_block; | ||||
3101 | if (std_entry->number_of_preds() > 0 || is_profiling() || RangeCheckElimination) { | ||||
3102 | new_header_block = header_block(std_entry, BlockBegin::std_entry_flag, state); | ||||
3103 | } else { | ||||
3104 | new_header_block = std_entry; | ||||
3105 | } | ||||
3106 | |||||
3107 | // setup start block (root for the IR graph) | ||||
3108 | Base* base = | ||||
3109 | new Base( | ||||
3110 | new_header_block, | ||||
3111 | osr_entry | ||||
3112 | ); | ||||
3113 | start->set_next(base, 0); | ||||
3114 | start->set_end(base); | ||||
3115 | // create & setup state for start block | ||||
3116 | start->set_state(state->copy(ValueStack::StateAfter, std_entry->bci())); | ||||
3117 | base->set_state(state->copy(ValueStack::StateAfter, std_entry->bci())); | ||||
3118 | |||||
3119 | if (base->std_entry()->state() == NULL__null) { | ||||
3120 | // setup states for header blocks | ||||
3121 | base->std_entry()->merge(state); | ||||
3122 | } | ||||
3123 | |||||
3124 | assert(base->std_entry()->state() != NULL, "")do { if (!(base->std_entry()->state() != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3124, "assert(" "base->std_entry()->state() != __null" ") failed", ""); ::breakpoint(); } } while (0); | ||||
3125 | return start; | ||||
3126 | } | ||||
3127 | |||||
3128 | |||||
3129 | void GraphBuilder::setup_osr_entry_block() { | ||||
3130 | assert(compilation()->is_osr_compile(), "only for osrs")do { if (!(compilation()->is_osr_compile())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3130, "assert(" "compilation()->is_osr_compile()" ") failed" , "only for osrs"); ::breakpoint(); } } while (0); | ||||
3131 | |||||
3132 | int osr_bci = compilation()->osr_bci(); | ||||
3133 | ciBytecodeStream s(method()); | ||||
3134 | s.reset_to_bci(osr_bci); | ||||
3135 | s.next(); | ||||
3136 | scope_data()->set_stream(&s); | ||||
3137 | |||||
3138 | // create a new block to be the osr setup code | ||||
3139 | _osr_entry = new BlockBegin(osr_bci); | ||||
3140 | _osr_entry->set(BlockBegin::osr_entry_flag); | ||||
3141 | _osr_entry->set_depth_first_number(0); | ||||
3142 | BlockBegin* target = bci2block()->at(osr_bci); | ||||
3143 | assert(target != NULL && target->is_set(BlockBegin::osr_entry_flag), "must be there")do { if (!(target != __null && target->is_set(BlockBegin ::osr_entry_flag))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3143, "assert(" "target != __null && target->is_set(BlockBegin::osr_entry_flag)" ") failed", "must be there"); ::breakpoint(); } } while (0); | ||||
3144 | // the osr entry has no values for locals | ||||
3145 | ValueStack* state = target->state()->copy(); | ||||
3146 | _osr_entry->set_state(state); | ||||
3147 | |||||
3148 | kill_all(); | ||||
3149 | _block = _osr_entry; | ||||
3150 | _state = _osr_entry->state()->copy(); | ||||
3151 | assert(_state->bci() == osr_bci, "mismatch")do { if (!(_state->bci() == osr_bci)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3151, "assert(" "_state->bci() == osr_bci" ") failed", "mismatch" ); ::breakpoint(); } } while (0); | ||||
3152 | _last = _osr_entry; | ||||
3153 | Value e = append(new OsrEntry()); | ||||
3154 | e->set_needs_null_check(false); | ||||
3155 | |||||
3156 | // OSR buffer is | ||||
3157 | // | ||||
3158 | // locals[nlocals-1..0] | ||||
3159 | // monitors[number_of_locks-1..0] | ||||
3160 | // | ||||
3161 | // locals is a direct copy of the interpreter frame so in the osr buffer | ||||
3162 | // so first slot in the local array is the last local from the interpreter | ||||
3163 | // and last slot is local[0] (receiver) from the interpreter | ||||
3164 | // | ||||
3165 | // Similarly with locks. The first lock slot in the osr buffer is the nth lock | ||||
3166 | // from the interpreter frame, the nth lock slot in the osr buffer is 0th lock | ||||
3167 | // in the interpreter frame (the method lock if a sync method) | ||||
3168 | |||||
3169 | // Initialize monitors in the compiled activation. | ||||
3170 | |||||
3171 | int index; | ||||
3172 | Value local; | ||||
3173 | |||||
3174 | // find all the locals that the interpreter thinks contain live oops | ||||
3175 | const ResourceBitMap live_oops = method()->live_local_oops_at_bci(osr_bci); | ||||
3176 | |||||
3177 | // compute the offset into the locals so that we can treat the buffer | ||||
3178 | // as if the locals were still in the interpreter frame | ||||
3179 | int locals_offset = BytesPerWord * (method()->max_locals() - 1); | ||||
3180 | for_each_local_value(state, index, local)int temp__3180 = state->locals_size(); for (index = 0; index < temp__3180 && (local = state->local_at(index ), true); index += (local == __null || local->type()->is_illegal () ? 1 : local->type()->size())) if (local != __null) { | ||||
3181 | int offset = locals_offset - (index + local->type()->size() - 1) * BytesPerWord; | ||||
3182 | Value get; | ||||
3183 | if (local->type()->is_object_kind() && !live_oops.at(index)) { | ||||
3184 | // The interpreter thinks this local is dead but the compiler | ||||
3185 | // doesn't so pretend that the interpreter passed in null. | ||||
3186 | get = append(new Constant(objectNull)); | ||||
3187 | } else { | ||||
3188 | Value off_val = append(new Constant(new IntConstant(offset))); | ||||
3189 | get = append(new UnsafeGet(as_BasicType(local->type()), e, | ||||
3190 | off_val, | ||||
3191 | false/*is_volatile*/, | ||||
3192 | true/*is_raw*/)); | ||||
3193 | } | ||||
3194 | _state->store_local(index, get); | ||||
3195 | } | ||||
3196 | |||||
3197 | // the storage for the OSR buffer is freed manually in the LIRGenerator. | ||||
3198 | |||||
3199 | assert(state->caller_state() == NULL, "should be top scope")do { if (!(state->caller_state() == __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3199, "assert(" "state->caller_state() == __null" ") failed" , "should be top scope"); ::breakpoint(); } } while (0); | ||||
3200 | state->clear_locals(); | ||||
3201 | Goto* g = new Goto(target, false); | ||||
3202 | append(g); | ||||
3203 | _osr_entry->set_end(g); | ||||
3204 | target->merge(_osr_entry->end()->state()); | ||||
3205 | |||||
3206 | scope_data()->set_stream(NULL__null); | ||||
3207 | } | ||||
3208 | |||||
3209 | |||||
3210 | ValueStack* GraphBuilder::state_at_entry() { | ||||
3211 | ValueStack* state = new ValueStack(scope(), NULL__null); | ||||
3212 | |||||
3213 | // Set up locals for receiver | ||||
3214 | int idx = 0; | ||||
3215 | if (!method()->is_static()) { | ||||
3216 | // we should always see the receiver | ||||
3217 | state->store_local(idx, new Local(method()->holder(), objectType, idx, true)); | ||||
3218 | idx = 1; | ||||
3219 | } | ||||
3220 | |||||
3221 | // Set up locals for incoming arguments | ||||
3222 | ciSignature* sig = method()->signature(); | ||||
3223 | for (int i = 0; i < sig->count(); i++) { | ||||
3224 | ciType* type = sig->type_at(i); | ||||
3225 | BasicType basic_type = type->basic_type(); | ||||
3226 | // don't allow T_ARRAY to propagate into locals types | ||||
3227 | if (is_reference_type(basic_type)) basic_type = T_OBJECT; | ||||
3228 | ValueType* vt = as_ValueType(basic_type); | ||||
3229 | state->store_local(idx, new Local(type, vt, idx, false)); | ||||
3230 | idx += type->size(); | ||||
3231 | } | ||||
3232 | |||||
3233 | // lock synchronized method | ||||
3234 | if (method()->is_synchronized()) { | ||||
3235 | state->lock(NULL__null); | ||||
3236 | } | ||||
3237 | |||||
3238 | return state; | ||||
3239 | } | ||||
3240 | |||||
3241 | |||||
3242 | GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope) | ||||
3243 | : _scope_data(NULL__null) | ||||
3244 | , _compilation(compilation) | ||||
3245 | , _memory(new MemoryBuffer()) | ||||
3246 | , _inline_bailout_msg(NULL__null) | ||||
3247 | , _instruction_count(0) | ||||
3248 | , _osr_entry(NULL__null) | ||||
3249 | { | ||||
3250 | int osr_bci = compilation->osr_bci(); | ||||
3251 | |||||
3252 | // determine entry points and bci2block mapping | ||||
3253 | BlockListBuilder blm(compilation, scope, osr_bci); | ||||
3254 | CHECK_BAILOUT(){ if (bailed_out()) return; }; | ||||
3255 | |||||
3256 | BlockList* bci2block = blm.bci2block(); | ||||
3257 | BlockBegin* start_block = bci2block->at(0); | ||||
3258 | |||||
3259 | push_root_scope(scope, bci2block, start_block); | ||||
3260 | |||||
3261 | // setup state for std entry | ||||
3262 | _initial_state = state_at_entry(); | ||||
3263 | start_block->merge(_initial_state); | ||||
3264 | |||||
3265 | // End nulls still exist here | ||||
3266 | |||||
3267 | // complete graph | ||||
3268 | _vmap = new ValueMap(); | ||||
3269 | switch (scope->method()->intrinsic_id()) { | ||||
3270 | case vmIntrinsics::_dabs : // fall through | ||||
3271 | case vmIntrinsics::_dsqrt : // fall through | ||||
3272 | case vmIntrinsics::_dsqrt_strict : // fall through | ||||
3273 | case vmIntrinsics::_dsin : // fall through | ||||
3274 | case vmIntrinsics::_dcos : // fall through | ||||
3275 | case vmIntrinsics::_dtan : // fall through | ||||
3276 | case vmIntrinsics::_dlog : // fall through | ||||
3277 | case vmIntrinsics::_dlog10 : // fall through | ||||
3278 | case vmIntrinsics::_dexp : // fall through | ||||
3279 | case vmIntrinsics::_dpow : // fall through | ||||
3280 | { | ||||
3281 | // Compiles where the root method is an intrinsic need a special | ||||
3282 | // compilation environment because the bytecodes for the method | ||||
3283 | // shouldn't be parsed during the compilation, only the special | ||||
3284 | // Intrinsic node should be emitted. If this isn't done the the | ||||
3285 | // code for the inlined version will be different than the root | ||||
3286 | // compiled version which could lead to monotonicity problems on | ||||
3287 | // intel. | ||||
3288 | if (CheckIntrinsics && !scope->method()->intrinsic_candidate()) { | ||||
3289 | BAILOUT("failed to inline intrinsic, method not annotated"){ bailout("failed to inline intrinsic, method not annotated") ; return; }; | ||||
3290 | } | ||||
3291 | |||||
3292 | // Set up a stream so that appending instructions works properly. | ||||
3293 | ciBytecodeStream s(scope->method()); | ||||
3294 | s.reset_to_bci(0); | ||||
3295 | scope_data()->set_stream(&s); | ||||
3296 | s.next(); | ||||
3297 | |||||
3298 | // setup the initial block state | ||||
3299 | _block = start_block; | ||||
3300 | _state = start_block->state()->copy_for_parsing(); | ||||
3301 | _last = start_block; | ||||
3302 | load_local(doubleType, 0); | ||||
3303 | if (scope->method()->intrinsic_id() == vmIntrinsics::_dpow) { | ||||
3304 | load_local(doubleType, 2); | ||||
3305 | } | ||||
3306 | |||||
3307 | // Emit the intrinsic node. | ||||
3308 | bool result = try_inline_intrinsics(scope->method()); | ||||
3309 | if (!result) BAILOUT("failed to inline intrinsic"){ bailout("failed to inline intrinsic"); return; }; | ||||
3310 | method_return(dpop()); | ||||
3311 | |||||
3312 | // connect the begin and end blocks and we're all done. | ||||
3313 | BlockEnd* end = last()->as_BlockEnd(); | ||||
3314 | block()->set_end(end); | ||||
3315 | break; | ||||
3316 | } | ||||
3317 | |||||
3318 | case vmIntrinsics::_Reference_get: | ||||
3319 | { | ||||
3320 | { | ||||
3321 | // With java.lang.ref.reference.get() we must go through the | ||||
3322 | // intrinsic - when G1 is enabled - even when get() is the root | ||||
3323 | // method of the compile so that, if necessary, the value in | ||||
3324 | // the referent field of the reference object gets recorded by | ||||
3325 | // the pre-barrier code. | ||||
3326 | // Specifically, if G1 is enabled, the value in the referent | ||||
3327 | // field is recorded by the G1 SATB pre barrier. This will | ||||
3328 | // result in the referent being marked live and the reference | ||||
3329 | // object removed from the list of discovered references during | ||||
3330 | // reference processing. | ||||
3331 | if (CheckIntrinsics && !scope->method()->intrinsic_candidate()) { | ||||
3332 | BAILOUT("failed to inline intrinsic, method not annotated"){ bailout("failed to inline intrinsic, method not annotated") ; return; }; | ||||
3333 | } | ||||
3334 | |||||
3335 | // Also we need intrinsic to prevent commoning reads from this field | ||||
3336 | // across safepoint since GC can change its value. | ||||
3337 | |||||
3338 | // Set up a stream so that appending instructions works properly. | ||||
3339 | ciBytecodeStream s(scope->method()); | ||||
3340 | s.reset_to_bci(0); | ||||
3341 | scope_data()->set_stream(&s); | ||||
3342 | s.next(); | ||||
3343 | |||||
3344 | // setup the initial block state | ||||
3345 | _block = start_block; | ||||
3346 | _state = start_block->state()->copy_for_parsing(); | ||||
3347 | _last = start_block; | ||||
3348 | load_local(objectType, 0); | ||||
3349 | |||||
3350 | // Emit the intrinsic node. | ||||
3351 | bool result = try_inline_intrinsics(scope->method()); | ||||
3352 | if (!result) BAILOUT("failed to inline intrinsic"){ bailout("failed to inline intrinsic"); return; }; | ||||
3353 | method_return(apop()); | ||||
3354 | |||||
3355 | // connect the begin and end blocks and we're all done. | ||||
3356 | BlockEnd* end = last()->as_BlockEnd(); | ||||
3357 | block()->set_end(end); | ||||
3358 | break; | ||||
3359 | } | ||||
3360 | // Otherwise, fall thru | ||||
3361 | } | ||||
3362 | |||||
3363 | default: | ||||
3364 | scope_data()->add_to_work_list(start_block); | ||||
3365 | iterate_all_blocks(); | ||||
3366 | break; | ||||
3367 | } | ||||
3368 | CHECK_BAILOUT(){ if (bailed_out()) return; }; | ||||
3369 | |||||
3370 | # ifdef ASSERT1 | ||||
3371 | //All blocks reachable from start_block have _end != NULL | ||||
3372 | { | ||||
3373 | BlockList processed; | ||||
3374 | BlockList to_go; | ||||
3375 | to_go.append(start_block); | ||||
3376 | while(to_go.length() > 0) { | ||||
3377 | BlockBegin* current = to_go.pop(); | ||||
3378 | assert(current != NULL, "Should not happen.")do { if (!(current != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3378, "assert(" "current != __null" ") failed", "Should not happen." ); ::breakpoint(); } } while (0); | ||||
3379 | assert(current->end() != NULL, "All blocks reachable from start_block should have end() != NULL.")do { if (!(current->end() != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3379, "assert(" "current->end() != __null" ") failed", "All blocks reachable from start_block should have end() != NULL." ); ::breakpoint(); } } while (0); | ||||
3380 | processed.append(current); | ||||
3381 | for(int i = 0; i < current->number_of_sux(); i++) { | ||||
3382 | BlockBegin* s = current->sux_at(i); | ||||
3383 | if (!processed.contains(s)) { | ||||
3384 | to_go.append(s); | ||||
3385 | } | ||||
3386 | } | ||||
3387 | } | ||||
3388 | } | ||||
3389 | #endif // ASSERT | ||||
3390 | |||||
3391 | _start = setup_start_block(osr_bci, start_block, _osr_entry, _initial_state); | ||||
3392 | |||||
3393 | eliminate_redundant_phis(_start); | ||||
3394 | |||||
3395 | NOT_PRODUCT(if (PrintValueNumbering && Verbose) print_stats())if (PrintValueNumbering && Verbose) print_stats(); | ||||
3396 | // for osr compile, bailout if some requirements are not fulfilled | ||||
3397 | if (osr_bci != -1) { | ||||
3398 | BlockBegin* osr_block = blm.bci2block()->at(osr_bci); | ||||
3399 | if (!osr_block->is_set(BlockBegin::was_visited_flag)) { | ||||
3400 | BAILOUT("osr entry must have been visited for osr compile"){ bailout("osr entry must have been visited for osr compile") ; return; }; | ||||
3401 | } | ||||
3402 | |||||
3403 | // check if osr entry point has empty stack - we cannot handle non-empty stacks at osr entry points | ||||
3404 | if (!osr_block->state()->stack_is_empty()) { | ||||
3405 | BAILOUT("stack not empty at OSR entry point"){ bailout("stack not empty at OSR entry point"); return; }; | ||||
3406 | } | ||||
3407 | } | ||||
3408 | #ifndef PRODUCT | ||||
3409 | if (PrintCompilation && Verbose) tty->print_cr("Created %d Instructions", _instruction_count); | ||||
3410 | #endif | ||||
3411 | } | ||||
3412 | |||||
3413 | |||||
3414 | ValueStack* GraphBuilder::copy_state_before() { | ||||
3415 | return copy_state_before_with_bci(bci()); | ||||
3416 | } | ||||
3417 | |||||
3418 | ValueStack* GraphBuilder::copy_state_exhandling() { | ||||
3419 | return copy_state_exhandling_with_bci(bci()); | ||||
3420 | } | ||||
3421 | |||||
3422 | ValueStack* GraphBuilder::copy_state_for_exception() { | ||||
3423 | return copy_state_for_exception_with_bci(bci()); | ||||
3424 | } | ||||
3425 | |||||
3426 | ValueStack* GraphBuilder::copy_state_before_with_bci(int bci) { | ||||
3427 | return state()->copy(ValueStack::StateBefore, bci); | ||||
3428 | } | ||||
3429 | |||||
3430 | ValueStack* GraphBuilder::copy_state_exhandling_with_bci(int bci) { | ||||
3431 | if (!has_handler()) return NULL__null; | ||||
3432 | return state()->copy(ValueStack::StateBefore, bci); | ||||
3433 | } | ||||
3434 | |||||
3435 | ValueStack* GraphBuilder::copy_state_for_exception_with_bci(int bci) { | ||||
3436 | ValueStack* s = copy_state_exhandling_with_bci(bci); | ||||
3437 | if (s == NULL__null) { | ||||
3438 | if (_compilation->env()->should_retain_local_variables()) { | ||||
3439 | s = state()->copy(ValueStack::ExceptionState, bci); | ||||
3440 | } else { | ||||
3441 | s = state()->copy(ValueStack::EmptyExceptionState, bci); | ||||
3442 | } | ||||
3443 | } | ||||
3444 | return s; | ||||
3445 | } | ||||
3446 | |||||
3447 | int GraphBuilder::recursive_inline_level(ciMethod* cur_callee) const { | ||||
3448 | int recur_level = 0; | ||||
3449 | for (IRScope* s = scope(); s != NULL__null; s = s->caller()) { | ||||
3450 | if (s->method() == cur_callee) { | ||||
3451 | ++recur_level; | ||||
3452 | } | ||||
3453 | } | ||||
3454 | return recur_level; | ||||
3455 | } | ||||
3456 | |||||
3457 | |||||
3458 | bool GraphBuilder::try_inline(ciMethod* callee, bool holder_known, bool ignore_return, Bytecodes::Code bc, Value receiver) { | ||||
3459 | const char* msg = NULL__null; | ||||
3460 | |||||
3461 | // clear out any existing inline bailout condition | ||||
3462 | clear_inline_bailout(); | ||||
3463 | |||||
3464 | // exclude methods we don't want to inline | ||||
3465 | msg = should_not_inline(callee); | ||||
3466 | if (msg != NULL__null) { | ||||
3467 | print_inlining(callee, msg, /*success*/ false); | ||||
3468 | return false; | ||||
3469 | } | ||||
3470 | |||||
3471 | // method handle invokes | ||||
3472 | if (callee->is_method_handle_intrinsic()) { | ||||
3473 | if (try_method_handle_inline(callee, ignore_return)) { | ||||
3474 | if (callee->has_reserved_stack_access()) { | ||||
3475 | compilation()->set_has_reserved_stack_access(true); | ||||
3476 | } | ||||
3477 | return true; | ||||
3478 | } | ||||
3479 | return false; | ||||
3480 | } | ||||
3481 | |||||
3482 | // handle intrinsics | ||||
3483 | if (callee->intrinsic_id() != vmIntrinsics::_none && | ||||
3484 | callee->check_intrinsic_candidate()) { | ||||
3485 | if (try_inline_intrinsics(callee, ignore_return)) { | ||||
3486 | print_inlining(callee, "intrinsic"); | ||||
3487 | if (callee->has_reserved_stack_access()) { | ||||
3488 | compilation()->set_has_reserved_stack_access(true); | ||||
3489 | } | ||||
3490 | return true; | ||||
3491 | } | ||||
3492 | // try normal inlining | ||||
3493 | } | ||||
3494 | |||||
3495 | // certain methods cannot be parsed at all | ||||
3496 | msg = check_can_parse(callee); | ||||
3497 | if (msg != NULL__null) { | ||||
3498 | print_inlining(callee, msg, /*success*/ false); | ||||
3499 | return false; | ||||
3500 | } | ||||
3501 | |||||
3502 | // If bytecode not set use the current one. | ||||
3503 | if (bc == Bytecodes::_illegal) { | ||||
3504 | bc = code(); | ||||
3505 | } | ||||
3506 | if (try_inline_full(callee, holder_known, ignore_return, bc, receiver)) { | ||||
3507 | if (callee->has_reserved_stack_access()) { | ||||
3508 | compilation()->set_has_reserved_stack_access(true); | ||||
3509 | } | ||||
3510 | return true; | ||||
3511 | } | ||||
3512 | |||||
3513 | // Entire compilation could fail during try_inline_full call. | ||||
3514 | // In that case printing inlining decision info is useless. | ||||
3515 | if (!bailed_out()) | ||||
3516 | print_inlining(callee, _inline_bailout_msg, /*success*/ false); | ||||
3517 | |||||
3518 | return false; | ||||
3519 | } | ||||
3520 | |||||
3521 | |||||
3522 | const char* GraphBuilder::check_can_parse(ciMethod* callee) const { | ||||
3523 | // Certain methods cannot be parsed at all: | ||||
3524 | if ( callee->is_native()) return "native method"; | ||||
3525 | if ( callee->is_abstract()) return "abstract method"; | ||||
3526 | if (!callee->can_be_parsed()) return "cannot be parsed"; | ||||
3527 | return NULL__null; | ||||
3528 | } | ||||
3529 | |||||
3530 | // negative filter: should callee NOT be inlined? returns NULL, ok to inline, or rejection msg | ||||
3531 | const char* GraphBuilder::should_not_inline(ciMethod* callee) const { | ||||
3532 | if ( compilation()->directive()->should_not_inline(callee)) return "disallowed by CompileCommand"; | ||||
3533 | if ( callee->dont_inline()) return "don't inline by annotation"; | ||||
3534 | return NULL__null; | ||||
3535 | } | ||||
3536 | |||||
3537 | void GraphBuilder::build_graph_for_intrinsic(ciMethod* callee, bool ignore_return) { | ||||
3538 | vmIntrinsics::ID id = callee->intrinsic_id(); | ||||
3539 | assert(id != vmIntrinsics::_none, "must be a VM intrinsic")do { if (!(id != vmIntrinsics::_none)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3539, "assert(" "id != vmIntrinsics::_none" ") failed", "must be a VM intrinsic" ); ::breakpoint(); } } while (0); | ||||
3540 | |||||
3541 | // Some intrinsics need special IR nodes. | ||||
3542 | switch(id) { | ||||
3543 | case vmIntrinsics::_getReference : append_unsafe_get(callee, T_OBJECT, false); return; | ||||
3544 | case vmIntrinsics::_getBoolean : append_unsafe_get(callee, T_BOOLEAN, false); return; | ||||
3545 | case vmIntrinsics::_getByte : append_unsafe_get(callee, T_BYTE, false); return; | ||||
3546 | case vmIntrinsics::_getShort : append_unsafe_get(callee, T_SHORT, false); return; | ||||
3547 | case vmIntrinsics::_getChar : append_unsafe_get(callee, T_CHAR, false); return; | ||||
3548 | case vmIntrinsics::_getInt : append_unsafe_get(callee, T_INT, false); return; | ||||
3549 | case vmIntrinsics::_getLong : append_unsafe_get(callee, T_LONG, false); return; | ||||
3550 | case vmIntrinsics::_getFloat : append_unsafe_get(callee, T_FLOAT, false); return; | ||||
3551 | case vmIntrinsics::_getDouble : append_unsafe_get(callee, T_DOUBLE, false); return; | ||||
3552 | case vmIntrinsics::_putReference : append_unsafe_put(callee, T_OBJECT, false); return; | ||||
3553 | case vmIntrinsics::_putBoolean : append_unsafe_put(callee, T_BOOLEAN, false); return; | ||||
3554 | case vmIntrinsics::_putByte : append_unsafe_put(callee, T_BYTE, false); return; | ||||
3555 | case vmIntrinsics::_putShort : append_unsafe_put(callee, T_SHORT, false); return; | ||||
3556 | case vmIntrinsics::_putChar : append_unsafe_put(callee, T_CHAR, false); return; | ||||
3557 | case vmIntrinsics::_putInt : append_unsafe_put(callee, T_INT, false); return; | ||||
3558 | case vmIntrinsics::_putLong : append_unsafe_put(callee, T_LONG, false); return; | ||||
3559 | case vmIntrinsics::_putFloat : append_unsafe_put(callee, T_FLOAT, false); return; | ||||
3560 | case vmIntrinsics::_putDouble : append_unsafe_put(callee, T_DOUBLE, false); return; | ||||
3561 | case vmIntrinsics::_getShortUnaligned : append_unsafe_get(callee, T_SHORT, false); return; | ||||
3562 | case vmIntrinsics::_getCharUnaligned : append_unsafe_get(callee, T_CHAR, false); return; | ||||
3563 | case vmIntrinsics::_getIntUnaligned : append_unsafe_get(callee, T_INT, false); return; | ||||
3564 | case vmIntrinsics::_getLongUnaligned : append_unsafe_get(callee, T_LONG, false); return; | ||||
3565 | case vmIntrinsics::_putShortUnaligned : append_unsafe_put(callee, T_SHORT, false); return; | ||||
3566 | case vmIntrinsics::_putCharUnaligned : append_unsafe_put(callee, T_CHAR, false); return; | ||||
3567 | case vmIntrinsics::_putIntUnaligned : append_unsafe_put(callee, T_INT, false); return; | ||||
3568 | case vmIntrinsics::_putLongUnaligned : append_unsafe_put(callee, T_LONG, false); return; | ||||
3569 | case vmIntrinsics::_getReferenceVolatile : append_unsafe_get(callee, T_OBJECT, true); return; | ||||
3570 | case vmIntrinsics::_getBooleanVolatile : append_unsafe_get(callee, T_BOOLEAN, true); return; | ||||
3571 | case vmIntrinsics::_getByteVolatile : append_unsafe_get(callee, T_BYTE, true); return; | ||||
3572 | case vmIntrinsics::_getShortVolatile : append_unsafe_get(callee, T_SHORT, true); return; | ||||
3573 | case vmIntrinsics::_getCharVolatile : append_unsafe_get(callee, T_CHAR, true); return; | ||||
3574 | case vmIntrinsics::_getIntVolatile : append_unsafe_get(callee, T_INT, true); return; | ||||
3575 | case vmIntrinsics::_getLongVolatile : append_unsafe_get(callee, T_LONG, true); return; | ||||
3576 | case vmIntrinsics::_getFloatVolatile : append_unsafe_get(callee, T_FLOAT, true); return; | ||||
3577 | case vmIntrinsics::_getDoubleVolatile : append_unsafe_get(callee, T_DOUBLE, true); return; | ||||
3578 | case vmIntrinsics::_putReferenceVolatile : append_unsafe_put(callee, T_OBJECT, true); return; | ||||
3579 | case vmIntrinsics::_putBooleanVolatile : append_unsafe_put(callee, T_BOOLEAN, true); return; | ||||
3580 | case vmIntrinsics::_putByteVolatile : append_unsafe_put(callee, T_BYTE, true); return; | ||||
3581 | case vmIntrinsics::_putShortVolatile : append_unsafe_put(callee, T_SHORT, true); return; | ||||
3582 | case vmIntrinsics::_putCharVolatile : append_unsafe_put(callee, T_CHAR, true); return; | ||||
3583 | case vmIntrinsics::_putIntVolatile : append_unsafe_put(callee, T_INT, true); return; | ||||
3584 | case vmIntrinsics::_putLongVolatile : append_unsafe_put(callee, T_LONG, true); return; | ||||
3585 | case vmIntrinsics::_putFloatVolatile : append_unsafe_put(callee, T_FLOAT, true); return; | ||||
3586 | case vmIntrinsics::_putDoubleVolatile : append_unsafe_put(callee, T_DOUBLE, true); return; | ||||
3587 | case vmIntrinsics::_compareAndSetLong: | ||||
3588 | case vmIntrinsics::_compareAndSetInt: | ||||
3589 | case vmIntrinsics::_compareAndSetReference : append_unsafe_CAS(callee); return; | ||||
3590 | case vmIntrinsics::_getAndAddInt: | ||||
3591 | case vmIntrinsics::_getAndAddLong : append_unsafe_get_and_set(callee, true); return; | ||||
3592 | case vmIntrinsics::_getAndSetInt : | ||||
3593 | case vmIntrinsics::_getAndSetLong : | ||||
3594 | case vmIntrinsics::_getAndSetReference : append_unsafe_get_and_set(callee, false); return; | ||||
3595 | case vmIntrinsics::_getCharStringU : append_char_access(callee, false); return; | ||||
3596 | case vmIntrinsics::_putCharStringU : append_char_access(callee, true); return; | ||||
3597 | default: | ||||
3598 | break; | ||||
3599 | } | ||||
3600 | |||||
3601 | // create intrinsic node | ||||
3602 | const bool has_receiver = !callee->is_static(); | ||||
3603 | ValueType* result_type = as_ValueType(callee->return_type()); | ||||
3604 | ValueStack* state_before = copy_state_for_exception(); | ||||
3605 | |||||
3606 | Values* args = state()->pop_arguments(callee->arg_size()); | ||||
3607 | |||||
3608 | if (is_profiling()) { | ||||
3609 | // Don't profile in the special case where the root method | ||||
3610 | // is the intrinsic | ||||
3611 | if (callee != method()) { | ||||
3612 | // Note that we'd collect profile data in this method if we wanted it. | ||||
3613 | compilation()->set_would_profile(true); | ||||
3614 | if (profile_calls()) { | ||||
3615 | Value recv = NULL__null; | ||||
3616 | if (has_receiver) { | ||||
3617 | recv = args->at(0); | ||||
3618 | null_check(recv); | ||||
3619 | } | ||||
3620 | profile_call(callee, recv, NULL__null, collect_args_for_profiling(args, callee, true), true); | ||||
3621 | } | ||||
3622 | } | ||||
3623 | } | ||||
3624 | |||||
3625 | Intrinsic* result = new Intrinsic(result_type, callee->intrinsic_id(), | ||||
3626 | args, has_receiver, state_before, | ||||
3627 | vmIntrinsics::preserves_state(id), | ||||
3628 | vmIntrinsics::can_trap(id)); | ||||
3629 | // append instruction & push result | ||||
3630 | Value value = append_split(result); | ||||
3631 | if (result_type != voidType && !ignore_return) { | ||||
3632 | push(result_type, value); | ||||
3633 | } | ||||
3634 | |||||
3635 | if (callee != method() && profile_return() && result_type->is_object_kind()) { | ||||
3636 | profile_return_type(result, callee); | ||||
3637 | } | ||||
3638 | } | ||||
3639 | |||||
3640 | bool GraphBuilder::try_inline_intrinsics(ciMethod* callee, bool ignore_return) { | ||||
3641 | // For calling is_intrinsic_available we need to transition to | ||||
3642 | // the '_thread_in_vm' state because is_intrinsic_available() | ||||
3643 | // accesses critical VM-internal data. | ||||
3644 | bool is_available = false; | ||||
3645 | { | ||||
3646 | VM_ENTRY_MARKCompilerThread* thread=CompilerThread::current(); ThreadInVMfromNative __tiv(thread); HandleMarkCleaner __hm(thread); JavaThread* __the_thread__ = thread; VMNativeEntryWrapper __vew;; | ||||
3647 | methodHandle mh(THREAD__the_thread__, callee->get_Method()); | ||||
3648 | is_available = _compilation->compiler()->is_intrinsic_available(mh, _compilation->directive()); | ||||
3649 | } | ||||
3650 | |||||
3651 | if (!is_available) { | ||||
3652 | if (!InlineNatives) { | ||||
3653 | // Return false and also set message that the inlining of | ||||
3654 | // intrinsics has been disabled in general. | ||||
3655 | INLINE_BAILOUT("intrinsic method inlining disabled"){ inline_bailout("intrinsic method inlining disabled"); return false; }; | ||||
3656 | } else { | ||||
3657 | return false; | ||||
3658 | } | ||||
3659 | } | ||||
3660 | build_graph_for_intrinsic(callee, ignore_return); | ||||
3661 | return true; | ||||
3662 | } | ||||
3663 | |||||
3664 | |||||
3665 | bool GraphBuilder::try_inline_jsr(int jsr_dest_bci) { | ||||
3666 | // Introduce a new callee continuation point - all Ret instructions | ||||
3667 | // will be replaced with Gotos to this point. | ||||
3668 | BlockBegin* cont = block_at(next_bci()); | ||||
3669 | assert(cont != NULL, "continuation must exist (BlockListBuilder starts a new block after a jsr")do { if (!(cont != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3669, "assert(" "cont != __null" ") failed", "continuation must exist (BlockListBuilder starts a new block after a jsr" ); ::breakpoint(); } } while (0); | ||||
3670 | |||||
3671 | // Note: can not assign state to continuation yet, as we have to | ||||
3672 | // pick up the state from the Ret instructions. | ||||
3673 | |||||
3674 | // Push callee scope | ||||
3675 | push_scope_for_jsr(cont, jsr_dest_bci); | ||||
3676 | |||||
3677 | // Temporarily set up bytecode stream so we can append instructions | ||||
3678 | // (only using the bci of this stream) | ||||
3679 | scope_data()->set_stream(scope_data()->parent()->stream()); | ||||
3680 | |||||
3681 | BlockBegin* jsr_start_block = block_at(jsr_dest_bci); | ||||
3682 | assert(jsr_start_block != NULL, "jsr start block must exist")do { if (!(jsr_start_block != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3682, "assert(" "jsr_start_block != __null" ") failed", "jsr start block must exist" ); ::breakpoint(); } } while (0); | ||||
3683 | assert(!jsr_start_block->is_set(BlockBegin::was_visited_flag), "should not have visited jsr yet")do { if (!(!jsr_start_block->is_set(BlockBegin::was_visited_flag ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3683, "assert(" "!jsr_start_block->is_set(BlockBegin::was_visited_flag)" ") failed", "should not have visited jsr yet"); ::breakpoint (); } } while (0); | ||||
3684 | Goto* goto_sub = new Goto(jsr_start_block, false); | ||||
3685 | // Must copy state to avoid wrong sharing when parsing bytecodes | ||||
3686 | assert(jsr_start_block->state() == NULL, "should have fresh jsr starting block")do { if (!(jsr_start_block->state() == __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3686, "assert(" "jsr_start_block->state() == __null" ") failed" , "should have fresh jsr starting block"); ::breakpoint(); } } while (0); | ||||
3687 | jsr_start_block->set_state(copy_state_before_with_bci(jsr_dest_bci)); | ||||
3688 | append(goto_sub); | ||||
3689 | _block->set_end(goto_sub); | ||||
3690 | _last = _block = jsr_start_block; | ||||
3691 | |||||
3692 | // Clear out bytecode stream | ||||
3693 | scope_data()->set_stream(NULL__null); | ||||
3694 | |||||
3695 | scope_data()->add_to_work_list(jsr_start_block); | ||||
3696 | |||||
3697 | // Ready to resume parsing in subroutine | ||||
3698 | iterate_all_blocks(); | ||||
3699 | |||||
3700 | // If we bailed out during parsing, return immediately (this is bad news) | ||||
3701 | CHECK_BAILOUT_(false){ if (bailed_out()) return false; }; | ||||
3702 | |||||
3703 | // Detect whether the continuation can actually be reached. If not, | ||||
3704 | // it has not had state set by the join() operations in | ||||
3705 | // iterate_bytecodes_for_block()/ret() and we should not touch the | ||||
3706 | // iteration state. The calling activation of | ||||
3707 | // iterate_bytecodes_for_block will then complete normally. | ||||
3708 | if (cont->state() != NULL__null) { | ||||
3709 | if (!cont->is_set(BlockBegin::was_visited_flag)) { | ||||
3710 | // add continuation to work list instead of parsing it immediately | ||||
3711 | scope_data()->parent()->add_to_work_list(cont); | ||||
3712 | } | ||||
3713 | } | ||||
3714 | |||||
3715 | assert(jsr_continuation() == cont, "continuation must not have changed")do { if (!(jsr_continuation() == cont)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3715, "assert(" "jsr_continuation() == cont" ") failed", "continuation must not have changed" ); ::breakpoint(); } } while (0); | ||||
3716 | assert(!jsr_continuation()->is_set(BlockBegin::was_visited_flag) ||do { if (!(!jsr_continuation()->is_set(BlockBegin::was_visited_flag ) || jsr_continuation()->is_set(BlockBegin::parser_loop_header_flag ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3718, "assert(" "!jsr_continuation()->is_set(BlockBegin::was_visited_flag) || jsr_continuation()->is_set(BlockBegin::parser_loop_header_flag)" ") failed", "continuation can only be visited in case of backward branches" ); ::breakpoint(); } } while (0) | ||||
3717 | jsr_continuation()->is_set(BlockBegin::parser_loop_header_flag),do { if (!(!jsr_continuation()->is_set(BlockBegin::was_visited_flag ) || jsr_continuation()->is_set(BlockBegin::parser_loop_header_flag ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3718, "assert(" "!jsr_continuation()->is_set(BlockBegin::was_visited_flag) || jsr_continuation()->is_set(BlockBegin::parser_loop_header_flag)" ") failed", "continuation can only be visited in case of backward branches" ); ::breakpoint(); } } while (0) | ||||
3718 | "continuation can only be visited in case of backward branches")do { if (!(!jsr_continuation()->is_set(BlockBegin::was_visited_flag ) || jsr_continuation()->is_set(BlockBegin::parser_loop_header_flag ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3718, "assert(" "!jsr_continuation()->is_set(BlockBegin::was_visited_flag) || jsr_continuation()->is_set(BlockBegin::parser_loop_header_flag)" ") failed", "continuation can only be visited in case of backward branches" ); ::breakpoint(); } } while (0); | ||||
3719 | assert(_last && _last->as_BlockEnd(), "block must have end")do { if (!(_last && _last->as_BlockEnd())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3719, "assert(" "_last && _last->as_BlockEnd()" ") failed" , "block must have end"); ::breakpoint(); } } while (0); | ||||
3720 | |||||
3721 | // continuation is in work list, so end iteration of current block | ||||
3722 | _skip_block = true; | ||||
3723 | pop_scope_for_jsr(); | ||||
3724 | |||||
3725 | return true; | ||||
3726 | } | ||||
3727 | |||||
3728 | |||||
3729 | // Inline the entry of a synchronized method as a monitor enter and | ||||
3730 | // register the exception handler which releases the monitor if an | ||||
3731 | // exception is thrown within the callee. Note that the monitor enter | ||||
3732 | // cannot throw an exception itself, because the receiver is | ||||
3733 | // guaranteed to be non-null by the explicit null check at the | ||||
3734 | // beginning of inlining. | ||||
3735 | void GraphBuilder::inline_sync_entry(Value lock, BlockBegin* sync_handler) { | ||||
3736 | assert(lock != NULL && sync_handler != NULL, "lock or handler missing")do { if (!(lock != __null && sync_handler != __null)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3736, "assert(" "lock != __null && sync_handler != __null" ") failed", "lock or handler missing"); ::breakpoint(); } } while (0); | ||||
3737 | |||||
3738 | monitorenter(lock, SynchronizationEntryBCI); | ||||
3739 | assert(_last->as_MonitorEnter() != NULL, "monitor enter expected")do { if (!(_last->as_MonitorEnter() != __null)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3739, "assert(" "_last->as_MonitorEnter() != __null" ") failed" , "monitor enter expected"); ::breakpoint(); } } while (0); | ||||
3740 | _last->set_needs_null_check(false); | ||||
3741 | |||||
3742 | sync_handler->set(BlockBegin::exception_entry_flag); | ||||
3743 | sync_handler->set(BlockBegin::is_on_work_list_flag); | ||||
3744 | |||||
3745 | ciExceptionHandler* desc = new ciExceptionHandler(method()->holder(), 0, method()->code_size(), -1, 0); | ||||
3746 | XHandler* h = new XHandler(desc); | ||||
3747 | h->set_entry_block(sync_handler); | ||||
3748 | scope_data()->xhandlers()->append(h); | ||||
3749 | scope_data()->set_has_handler(); | ||||
3750 | } | ||||
3751 | |||||
3752 | |||||
3753 | // If an exception is thrown and not handled within an inlined | ||||
3754 | // synchronized method, the monitor must be released before the | ||||
3755 | // exception is rethrown in the outer scope. Generate the appropriate | ||||
3756 | // instructions here. | ||||
3757 | void GraphBuilder::fill_sync_handler(Value lock, BlockBegin* sync_handler, bool default_handler) { | ||||
3758 | BlockBegin* orig_block = _block; | ||||
3759 | ValueStack* orig_state = _state; | ||||
3760 | Instruction* orig_last = _last; | ||||
3761 | _last = _block = sync_handler; | ||||
3762 | _state = sync_handler->state()->copy(); | ||||
3763 | |||||
3764 | assert(sync_handler != NULL, "handler missing")do { if (!(sync_handler != __null)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3764, "assert(" "sync_handler != __null" ") failed", "handler missing" ); ::breakpoint(); } } while (0); | ||||
3765 | assert(!sync_handler->is_set(BlockBegin::was_visited_flag), "is visited here")do { if (!(!sync_handler->is_set(BlockBegin::was_visited_flag ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3765, "assert(" "!sync_handler->is_set(BlockBegin::was_visited_flag)" ") failed", "is visited here"); ::breakpoint(); } } while (0 ); | ||||
3766 | |||||
3767 | assert(lock != NULL || default_handler, "lock or handler missing")do { if (!(lock != __null || default_handler)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3767, "assert(" "lock != __null || default_handler" ") failed" , "lock or handler missing"); ::breakpoint(); } } while (0); | ||||
3768 | |||||
3769 | XHandler* h = scope_data()->xhandlers()->remove_last(); | ||||
3770 | assert(h->entry_block() == sync_handler, "corrupt list of handlers")do { if (!(h->entry_block() == sync_handler)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3770, "assert(" "h->entry_block() == sync_handler" ") failed" , "corrupt list of handlers"); ::breakpoint(); } } while (0); | ||||
3771 | |||||
3772 | block()->set(BlockBegin::was_visited_flag); | ||||
3773 | Value exception = append_with_bci(new ExceptionObject(), SynchronizationEntryBCI); | ||||
3774 | assert(exception->is_pinned(), "must be")do { if (!(exception->is_pinned())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3774, "assert(" "exception->is_pinned()" ") failed", "must be" ); ::breakpoint(); } } while (0); | ||||
3775 | |||||
3776 | int bci = SynchronizationEntryBCI; | ||||
3777 | if (compilation()->env()->dtrace_method_probes()) { | ||||
3778 | // Report exit from inline methods. We don't have a stream here | ||||
3779 | // so pass an explicit bci of SynchronizationEntryBCI. | ||||
3780 | Values* args = new Values(1); | ||||
3781 | args->push(append_with_bci(new Constant(new MethodConstant(method())), bci)); | ||||
3782 | append_with_bci(new RuntimeCall(voidType, "dtrace_method_exit", CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_exit)((address)((address_word)(SharedRuntime::dtrace_method_exit)) ), args), bci); | ||||
3783 | } | ||||
3784 | |||||
3785 | if (lock) { | ||||
3786 | assert(state()->locks_size() > 0 && state()->lock_at(state()->locks_size() - 1) == lock, "lock is missing")do { if (!(state()->locks_size() > 0 && state() ->lock_at(state()->locks_size() - 1) == lock)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3786, "assert(" "state()->locks_size() > 0 && state()->lock_at(state()->locks_size() - 1) == lock" ") failed", "lock is missing"); ::breakpoint(); } } while (0 ); | ||||
3787 | if (!lock->is_linked()) { | ||||
3788 | lock = append_with_bci(lock, bci); | ||||
3789 | } | ||||
3790 | |||||
3791 | // exit the monitor in the context of the synchronized method | ||||
3792 | monitorexit(lock, bci); | ||||
3793 | |||||
3794 | // exit the context of the synchronized method | ||||
3795 | if (!default_handler) { | ||||
3796 | pop_scope(); | ||||
3797 | bci = _state->caller_state()->bci(); | ||||
3798 | _state = _state->caller_state()->copy_for_parsing(); | ||||
3799 | } | ||||
3800 | } | ||||
3801 | |||||
3802 | // perform the throw as if at the the call site | ||||
3803 | apush(exception); | ||||
3804 | throw_op(bci); | ||||
3805 | |||||
3806 | BlockEnd* end = last()->as_BlockEnd(); | ||||
3807 | block()->set_end(end); | ||||
3808 | |||||
3809 | _block = orig_block; | ||||
3810 | _state = orig_state; | ||||
3811 | _last = orig_last; | ||||
3812 | } | ||||
3813 | |||||
3814 | |||||
3815 | bool GraphBuilder::try_inline_full(ciMethod* callee, bool holder_known, bool ignore_return, Bytecodes::Code bc, Value receiver) { | ||||
3816 | assert(!callee->is_native(), "callee must not be native")do { if (!(!callee->is_native())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3816, "assert(" "!callee->is_native()" ") failed", "callee must not be native" ); ::breakpoint(); } } while (0); | ||||
3817 | if (CompilationPolicy::should_not_inline(compilation()->env(), callee)) { | ||||
3818 | INLINE_BAILOUT("inlining prohibited by policy"){ inline_bailout("inlining prohibited by policy"); return false ; }; | ||||
3819 | } | ||||
3820 | // first perform tests of things it's not possible to inline | ||||
3821 | if (callee->has_exception_handlers() && | ||||
3822 | !InlineMethodsWithExceptionHandlers) INLINE_BAILOUT("callee has exception handlers"){ inline_bailout("callee has exception handlers"); return false ; }; | ||||
3823 | if (callee->is_synchronized() && | ||||
3824 | !InlineSynchronizedMethods ) INLINE_BAILOUT("callee is synchronized"){ inline_bailout("callee is synchronized"); return false; }; | ||||
3825 | if (!callee->holder()->is_linked()) INLINE_BAILOUT("callee's klass not linked yet"){ inline_bailout("callee's klass not linked yet"); return false ; }; | ||||
3826 | if (bc == Bytecodes::_invokestatic && | ||||
3827 | !callee->holder()->is_initialized()) INLINE_BAILOUT("callee's klass not initialized yet"){ inline_bailout("callee's klass not initialized yet"); return false; }; | ||||
3828 | if (!callee->has_balanced_monitors()) INLINE_BAILOUT("callee's monitors do not match"){ inline_bailout("callee's monitors do not match"); return false ; }; | ||||
3829 | |||||
3830 | // Proper inlining of methods with jsrs requires a little more work. | ||||
3831 | if (callee->has_jsrs() ) INLINE_BAILOUT("jsrs not handled properly by inliner yet"){ inline_bailout("jsrs not handled properly by inliner yet"); return false; }; | ||||
3832 | |||||
3833 | if (is_profiling() && !callee->ensure_method_data()) { | ||||
3834 | INLINE_BAILOUT("mdo allocation failed"){ inline_bailout("mdo allocation failed"); return false; }; | ||||
3835 | } | ||||
3836 | |||||
3837 | const bool is_invokedynamic = (bc == Bytecodes::_invokedynamic); | ||||
3838 | const bool has_receiver = (bc != Bytecodes::_invokestatic && !is_invokedynamic); | ||||
3839 | |||||
3840 | const int args_base = state()->stack_size() - callee->arg_size(); | ||||
3841 | assert(args_base >= 0, "stack underflow during inlining")do { if (!(args_base >= 0)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3841, "assert(" "args_base >= 0" ") failed", "stack underflow during inlining" ); ::breakpoint(); } } while (0); | ||||
3842 | |||||
3843 | Value recv = NULL__null; | ||||
3844 | if (has_receiver) { | ||||
3845 | assert(!callee->is_static(), "callee must not be static")do { if (!(!callee->is_static())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3845, "assert(" "!callee->is_static()" ") failed", "callee must not be static" ); ::breakpoint(); } } while (0); | ||||
3846 | assert(callee->arg_size() > 0, "must have at least a receiver")do { if (!(callee->arg_size() > 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3846, "assert(" "callee->arg_size() > 0" ") failed", "must have at least a receiver" ); ::breakpoint(); } } while (0); | ||||
3847 | |||||
3848 | recv = state()->stack_at(args_base); | ||||
3849 | if (recv->is_null_obj()) { | ||||
3850 | INLINE_BAILOUT("receiver is always null"){ inline_bailout("receiver is always null"); return false; }; | ||||
3851 | } | ||||
3852 | } | ||||
3853 | |||||
3854 | // now perform tests that are based on flag settings | ||||
3855 | bool inlinee_by_directive = compilation()->directive()->should_inline(callee); | ||||
3856 | if (callee->force_inline() || inlinee_by_directive) { | ||||
3857 | if (inline_level() > MaxForceInlineLevel ) INLINE_BAILOUT("MaxForceInlineLevel"){ inline_bailout("MaxForceInlineLevel"); return false; }; | ||||
3858 | if (recursive_inline_level(callee) > C1MaxRecursiveInlineLevel) INLINE_BAILOUT("recursive inlining too deep"){ inline_bailout("recursive inlining too deep"); return false ; }; | ||||
3859 | |||||
3860 | const char* msg = ""; | ||||
3861 | if (callee->force_inline()) msg = "force inline by annotation"; | ||||
3862 | if (inlinee_by_directive) msg = "force inline by CompileCommand"; | ||||
3863 | print_inlining(callee, msg); | ||||
3864 | } else { | ||||
3865 | // use heuristic controls on inlining | ||||
3866 | if (inline_level() > C1MaxInlineLevel ) INLINE_BAILOUT("inlining too deep"){ inline_bailout("inlining too deep"); return false; }; | ||||
3867 | int callee_recursive_level = recursive_inline_level(callee); | ||||
3868 | if (callee_recursive_level > C1MaxRecursiveInlineLevel ) INLINE_BAILOUT("recursive inlining too deep"){ inline_bailout("recursive inlining too deep"); return false ; }; | ||||
3869 | if (callee->code_size_for_inlining() > max_inline_size() ) INLINE_BAILOUT("callee is too large"){ inline_bailout("callee is too large"); return false; }; | ||||
3870 | // Additional condition to limit stack usage for non-recursive calls. | ||||
3871 | if ((callee_recursive_level == 0) && | ||||
3872 | (callee->max_stack() + callee->max_locals() - callee->size_of_parameters() > C1InlineStackLimit)) { | ||||
3873 | INLINE_BAILOUT("callee uses too much stack"){ inline_bailout("callee uses too much stack"); return false; }; | ||||
3874 | } | ||||
3875 | |||||
3876 | // don't inline throwable methods unless the inlining tree is rooted in a throwable class | ||||
3877 | if (callee->name() == ciSymbols::object_initializer_name() && | ||||
3878 | callee->holder()->is_subclass_of(ciEnv::current()->Throwable_klass())) { | ||||
3879 | // Throwable constructor call | ||||
3880 | IRScope* top = scope(); | ||||
3881 | while (top->caller() != NULL__null) { | ||||
3882 | top = top->caller(); | ||||
3883 | } | ||||
3884 | if (!top->method()->holder()->is_subclass_of(ciEnv::current()->Throwable_klass())) { | ||||
3885 | INLINE_BAILOUT("don't inline Throwable constructors"){ inline_bailout("don't inline Throwable constructors"); return false; }; | ||||
3886 | } | ||||
3887 | } | ||||
3888 | |||||
3889 | if (compilation()->env()->num_inlined_bytecodes() > DesiredMethodLimit) { | ||||
3890 | INLINE_BAILOUT("total inlining greater than DesiredMethodLimit"){ inline_bailout("total inlining greater than DesiredMethodLimit" ); return false; }; | ||||
3891 | } | ||||
3892 | // printing | ||||
3893 | print_inlining(callee, "inline", /*success*/ true); | ||||
3894 | } | ||||
3895 | |||||
3896 | assert(bc != Bytecodes::_invokestatic || callee->holder()->is_initialized(), "required")do { if (!(bc != Bytecodes::_invokestatic || callee->holder ()->is_initialized())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3896, "assert(" "bc != Bytecodes::_invokestatic || callee->holder()->is_initialized()" ") failed", "required"); ::breakpoint(); } } while (0); | ||||
3897 | |||||
3898 | // NOTE: Bailouts from this point on, which occur at the | ||||
3899 | // GraphBuilder level, do not cause bailout just of the inlining but | ||||
3900 | // in fact of the entire compilation. | ||||
3901 | |||||
3902 | BlockBegin* orig_block = block(); | ||||
3903 | |||||
3904 | // Insert null check if necessary | ||||
3905 | if (has_receiver) { | ||||
3906 | // note: null check must happen even if first instruction of callee does | ||||
3907 | // an implicit null check since the callee is in a different scope | ||||
3908 | // and we must make sure exception handling does the right thing | ||||
3909 | null_check(recv); | ||||
3910 | } | ||||
3911 | |||||
3912 | if (is_profiling()) { | ||||
3913 | // Note that we'd collect profile data in this method if we wanted it. | ||||
3914 | // this may be redundant here... | ||||
3915 | compilation()->set_would_profile(true); | ||||
3916 | |||||
3917 | if (profile_calls()) { | ||||
3918 | int start = 0; | ||||
3919 | Values* obj_args = args_list_for_profiling(callee, start, has_receiver); | ||||
3920 | if (obj_args != NULL__null) { | ||||
3921 | int s = obj_args->max_length(); | ||||
3922 | // if called through method handle invoke, some arguments may have been popped | ||||
3923 | for (int i = args_base+start, j = 0; j < obj_args->max_length() && i < state()->stack_size(); ) { | ||||
3924 | Value v = state()->stack_at_inc(i); | ||||
3925 | if (v->type()->is_object_kind()) { | ||||
3926 | obj_args->push(v); | ||||
3927 | j++; | ||||
3928 | } | ||||
3929 | } | ||||
3930 | check_args_for_profiling(obj_args, s); | ||||
3931 | } | ||||
3932 | profile_call(callee, recv, holder_known ? callee->holder() : NULL__null, obj_args, true); | ||||
3933 | } | ||||
3934 | } | ||||
3935 | |||||
3936 | // Introduce a new callee continuation point - if the callee has | ||||
3937 | // more than one return instruction or the return does not allow | ||||
3938 | // fall-through of control flow, all return instructions of the | ||||
3939 | // callee will need to be replaced by Goto's pointing to this | ||||
3940 | // continuation point. | ||||
3941 | BlockBegin* cont = block_at(next_bci()); | ||||
3942 | bool continuation_existed = true; | ||||
3943 | if (cont == NULL__null) { | ||||
3944 | cont = new BlockBegin(next_bci()); | ||||
3945 | // low number so that continuation gets parsed as early as possible | ||||
3946 | cont->set_depth_first_number(0); | ||||
3947 | if (PrintInitialBlockList) { | ||||
3948 | tty->print_cr("CFG: created block %d (bci %d) as continuation for inline at bci %d", | ||||
3949 | cont->block_id(), cont->bci(), bci()); | ||||
3950 | } | ||||
3951 | continuation_existed = false; | ||||
3952 | } | ||||
3953 | // Record number of predecessors of continuation block before | ||||
3954 | // inlining, to detect if inlined method has edges to its | ||||
3955 | // continuation after inlining. | ||||
3956 | int continuation_preds = cont->number_of_preds(); | ||||
3957 | |||||
3958 | // Push callee scope | ||||
3959 | push_scope(callee, cont); | ||||
3960 | |||||
3961 | // the BlockListBuilder for the callee could have bailed out | ||||
3962 | if (bailed_out()) | ||||
3963 | return false; | ||||
3964 | |||||
3965 | // Temporarily set up bytecode stream so we can append instructions | ||||
3966 | // (only using the bci of this stream) | ||||
3967 | scope_data()->set_stream(scope_data()->parent()->stream()); | ||||
3968 | |||||
3969 | // Pass parameters into callee state: add assignments | ||||
3970 | // note: this will also ensure that all arguments are computed before being passed | ||||
3971 | ValueStack* callee_state = state(); | ||||
3972 | ValueStack* caller_state = state()->caller_state(); | ||||
3973 | for (int i = args_base; i < caller_state->stack_size(); ) { | ||||
3974 | const int arg_no = i - args_base; | ||||
3975 | Value arg = caller_state->stack_at_inc(i); | ||||
3976 | store_local(callee_state, arg, arg_no); | ||||
3977 | } | ||||
3978 | |||||
3979 | // Remove args from stack. | ||||
3980 | // Note that we preserve locals state in case we can use it later | ||||
3981 | // (see use of pop_scope() below) | ||||
3982 | caller_state->truncate_stack(args_base); | ||||
3983 | assert(callee_state->stack_size() == 0, "callee stack must be empty")do { if (!(callee_state->stack_size() == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 3983, "assert(" "callee_state->stack_size() == 0" ") failed" , "callee stack must be empty"); ::breakpoint(); } } while (0 ); | ||||
3984 | |||||
3985 | Value lock = NULL__null; | ||||
3986 | BlockBegin* sync_handler = NULL__null; | ||||
3987 | |||||
3988 | // Inline the locking of the receiver if the callee is synchronized | ||||
3989 | if (callee->is_synchronized()) { | ||||
3990 | lock = callee->is_static() ? append(new Constant(new InstanceConstant(callee->holder()->java_mirror()))) | ||||
3991 | : state()->local_at(0); | ||||
3992 | sync_handler = new BlockBegin(SynchronizationEntryBCI); | ||||
3993 | inline_sync_entry(lock, sync_handler); | ||||
3994 | } | ||||
3995 | |||||
3996 | if (compilation()->env()->dtrace_method_probes()) { | ||||
3997 | Values* args = new Values(1); | ||||
3998 | args->push(append(new Constant(new MethodConstant(method())))); | ||||
3999 | append(new RuntimeCall(voidType, "dtrace_method_entry", CAST_FROM_FN_PTR(address, SharedRuntime::dtrace_method_entry)((address)((address_word)(SharedRuntime::dtrace_method_entry) )), args)); | ||||
4000 | } | ||||
4001 | |||||
4002 | if (profile_inlined_calls()) { | ||||
4003 | profile_invocation(callee, copy_state_before_with_bci(SynchronizationEntryBCI)); | ||||
4004 | } | ||||
4005 | |||||
4006 | BlockBegin* callee_start_block = block_at(0); | ||||
4007 | if (callee_start_block != NULL__null) { | ||||
4008 | assert(callee_start_block->is_set(BlockBegin::parser_loop_header_flag), "must be loop header")do { if (!(callee_start_block->is_set(BlockBegin::parser_loop_header_flag ))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4008, "assert(" "callee_start_block->is_set(BlockBegin::parser_loop_header_flag)" ") failed", "must be loop header"); ::breakpoint(); } } while (0); | ||||
4009 | Goto* goto_callee = new Goto(callee_start_block, false); | ||||
4010 | // The state for this goto is in the scope of the callee, so use | ||||
4011 | // the entry bci for the callee instead of the call site bci. | ||||
4012 | append_with_bci(goto_callee, 0); | ||||
4013 | _block->set_end(goto_callee); | ||||
4014 | callee_start_block->merge(callee_state); | ||||
4015 | |||||
4016 | _last = _block = callee_start_block; | ||||
4017 | |||||
4018 | scope_data()->add_to_work_list(callee_start_block); | ||||
4019 | } | ||||
4020 | |||||
4021 | // Clear out bytecode stream | ||||
4022 | scope_data()->set_stream(NULL__null); | ||||
4023 | scope_data()->set_ignore_return(ignore_return); | ||||
4024 | |||||
4025 | CompileLog* log = compilation()->log(); | ||||
4026 | if (log != NULL__null) log->head("parse method='%d'", log->identify(callee)); | ||||
4027 | |||||
4028 | // Ready to resume parsing in callee (either in the same block we | ||||
4029 | // were in before or in the callee's start block) | ||||
4030 | iterate_all_blocks(callee_start_block == NULL__null); | ||||
4031 | |||||
4032 | if (log != NULL__null) log->done("parse"); | ||||
4033 | |||||
4034 | // If we bailed out during parsing, return immediately (this is bad news) | ||||
4035 | if (bailed_out()) | ||||
4036 | return false; | ||||
4037 | |||||
4038 | // iterate_all_blocks theoretically traverses in random order; in | ||||
4039 | // practice, we have only traversed the continuation if we are | ||||
4040 | // inlining into a subroutine | ||||
4041 | assert(continuation_existed ||do { if (!(continuation_existed || !continuation()->is_set (BlockBegin::was_visited_flag))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4043, "assert(" "continuation_existed || !continuation()->is_set(BlockBegin::was_visited_flag)" ") failed", "continuation should not have been parsed yet if we created it" ); ::breakpoint(); } } while (0) | ||||
4042 | !continuation()->is_set(BlockBegin::was_visited_flag),do { if (!(continuation_existed || !continuation()->is_set (BlockBegin::was_visited_flag))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4043, "assert(" "continuation_existed || !continuation()->is_set(BlockBegin::was_visited_flag)" ") failed", "continuation should not have been parsed yet if we created it" ); ::breakpoint(); } } while (0) | ||||
4043 | "continuation should not have been parsed yet if we created it")do { if (!(continuation_existed || !continuation()->is_set (BlockBegin::was_visited_flag))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4043, "assert(" "continuation_existed || !continuation()->is_set(BlockBegin::was_visited_flag)" ") failed", "continuation should not have been parsed yet if we created it" ); ::breakpoint(); } } while (0); | ||||
4044 | |||||
4045 | // At this point we are almost ready to return and resume parsing of | ||||
4046 | // the caller back in the GraphBuilder. The only thing we want to do | ||||
4047 | // first is an optimization: during parsing of the callee we | ||||
4048 | // generated at least one Goto to the continuation block. If we | ||||
4049 | // generated exactly one, and if the inlined method spanned exactly | ||||
4050 | // one block (and we didn't have to Goto its entry), then we snip | ||||
4051 | // off the Goto to the continuation, allowing control to fall | ||||
4052 | // through back into the caller block and effectively performing | ||||
4053 | // block merging. This allows load elimination and CSE to take place | ||||
4054 | // across multiple callee scopes if they are relatively simple, and | ||||
4055 | // is currently essential to making inlining profitable. | ||||
4056 | if (num_returns() == 1 | ||||
4057 | && block() == orig_block | ||||
4058 | && block() == inline_cleanup_block()) { | ||||
4059 | _last = inline_cleanup_return_prev(); | ||||
4060 | _state = inline_cleanup_state(); | ||||
4061 | } else if (continuation_preds == cont->number_of_preds()) { | ||||
4062 | // Inlining caused that the instructions after the invoke in the | ||||
4063 | // caller are not reachable any more. So skip filling this block | ||||
4064 | // with instructions! | ||||
4065 | assert(cont == continuation(), "")do { if (!(cont == continuation())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4065, "assert(" "cont == continuation()" ") failed", ""); :: breakpoint(); } } while (0); | ||||
4066 | assert(_last && _last->as_BlockEnd(), "")do { if (!(_last && _last->as_BlockEnd())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4066, "assert(" "_last && _last->as_BlockEnd()" ") failed" , ""); ::breakpoint(); } } while (0); | ||||
4067 | _skip_block = true; | ||||
4068 | } else { | ||||
4069 | // Resume parsing in continuation block unless it was already parsed. | ||||
4070 | // Note that if we don't change _last here, iteration in | ||||
4071 | // iterate_bytecodes_for_block will stop when we return. | ||||
4072 | if (!continuation()->is_set(BlockBegin::was_visited_flag)) { | ||||
4073 | // add continuation to work list instead of parsing it immediately | ||||
4074 | assert(_last && _last->as_BlockEnd(), "")do { if (!(_last && _last->as_BlockEnd())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4074, "assert(" "_last && _last->as_BlockEnd()" ") failed" , ""); ::breakpoint(); } } while (0); | ||||
4075 | scope_data()->parent()->add_to_work_list(continuation()); | ||||
4076 | _skip_block = true; | ||||
4077 | } | ||||
4078 | } | ||||
4079 | |||||
4080 | // Fill the exception handler for synchronized methods with instructions | ||||
4081 | if (callee->is_synchronized() && sync_handler->state() != NULL__null) { | ||||
4082 | fill_sync_handler(lock, sync_handler); | ||||
4083 | } else { | ||||
4084 | pop_scope(); | ||||
4085 | } | ||||
4086 | |||||
4087 | compilation()->notice_inlined_method(callee); | ||||
4088 | |||||
4089 | return true; | ||||
4090 | } | ||||
4091 | |||||
4092 | |||||
4093 | bool GraphBuilder::try_method_handle_inline(ciMethod* callee, bool ignore_return) { | ||||
4094 | ValueStack* state_before = copy_state_before(); | ||||
4095 | vmIntrinsics::ID iid = callee->intrinsic_id(); | ||||
4096 | switch (iid) { | ||||
4097 | case vmIntrinsics::_invokeBasic: | ||||
4098 | { | ||||
4099 | // get MethodHandle receiver | ||||
4100 | const int args_base = state()->stack_size() - callee->arg_size(); | ||||
4101 | ValueType* type = state()->stack_at(args_base)->type(); | ||||
4102 | if (type->is_constant()) { | ||||
4103 | ciMethod* target = type->as_ObjectType()->constant_value()->as_method_handle()->get_vmtarget(); | ||||
4104 | // We don't do CHA here so only inline static and statically bindable methods. | ||||
4105 | if (target->is_static() || target->can_be_statically_bound()) { | ||||
4106 | if (ciMethod::is_consistent_info(callee, target)) { | ||||
4107 | Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual; | ||||
4108 | ignore_return = ignore_return || (callee->return_type()->is_void() && !target->return_type()->is_void()); | ||||
4109 | if (try_inline(target, /*holder_known*/ !callee->is_static(), ignore_return, bc)) { | ||||
4110 | return true; | ||||
4111 | } | ||||
4112 | } else { | ||||
4113 | print_inlining(target, "signatures mismatch", /*success*/ false); | ||||
4114 | } | ||||
4115 | } else { | ||||
4116 | print_inlining(target, "not static or statically bindable", /*success*/ false); | ||||
4117 | } | ||||
4118 | } else { | ||||
4119 | print_inlining(callee, "receiver not constant", /*success*/ false); | ||||
4120 | } | ||||
4121 | } | ||||
4122 | break; | ||||
4123 | |||||
4124 | case vmIntrinsics::_linkToVirtual: | ||||
4125 | case vmIntrinsics::_linkToStatic: | ||||
4126 | case vmIntrinsics::_linkToSpecial: | ||||
4127 | case vmIntrinsics::_linkToInterface: | ||||
4128 | { | ||||
4129 | // pop MemberName argument | ||||
4130 | const int args_base = state()->stack_size() - callee->arg_size(); | ||||
4131 | ValueType* type = apop()->type(); | ||||
4132 | if (type->is_constant()) { | ||||
4133 | ciMethod* target = type->as_ObjectType()->constant_value()->as_member_name()->get_vmtarget(); | ||||
4134 | ignore_return = ignore_return || (callee->return_type()->is_void() && !target->return_type()->is_void()); | ||||
4135 | // If the target is another method handle invoke, try to recursively get | ||||
4136 | // a better target. | ||||
4137 | if (target->is_method_handle_intrinsic()) { | ||||
4138 | if (try_method_handle_inline(target, ignore_return)) { | ||||
4139 | return true; | ||||
4140 | } | ||||
4141 | } else if (!ciMethod::is_consistent_info(callee, target)) { | ||||
4142 | print_inlining(target, "signatures mismatch", /*success*/ false); | ||||
4143 | } else { | ||||
4144 | ciSignature* signature = target->signature(); | ||||
4145 | const int receiver_skip = target->is_static() ? 0 : 1; | ||||
4146 | // Cast receiver to its type. | ||||
4147 | if (!target->is_static()) { | ||||
4148 | ciKlass* tk = signature->accessing_klass(); | ||||
4149 | Value obj = state()->stack_at(args_base); | ||||
4150 | if (obj->exact_type() == NULL__null && | ||||
4151 | obj->declared_type() != tk && tk != compilation()->env()->Object_klass()) { | ||||
4152 | TypeCast* c = new TypeCast(tk, obj, state_before); | ||||
4153 | append(c); | ||||
4154 | state()->stack_at_put(args_base, c); | ||||
4155 | } | ||||
4156 | } | ||||
4157 | // Cast reference arguments to its type. | ||||
4158 | for (int i = 0, j = 0; i < signature->count(); i++) { | ||||
4159 | ciType* t = signature->type_at(i); | ||||
4160 | if (t->is_klass()) { | ||||
4161 | ciKlass* tk = t->as_klass(); | ||||
4162 | Value obj = state()->stack_at(args_base + receiver_skip + j); | ||||
4163 | if (obj->exact_type() == NULL__null && | ||||
4164 | obj->declared_type() != tk && tk != compilation()->env()->Object_klass()) { | ||||
4165 | TypeCast* c = new TypeCast(t, obj, state_before); | ||||
4166 | append(c); | ||||
4167 | state()->stack_at_put(args_base + receiver_skip + j, c); | ||||
4168 | } | ||||
4169 | } | ||||
4170 | j += t->size(); // long and double take two slots | ||||
4171 | } | ||||
4172 | // We don't do CHA here so only inline static and statically bindable methods. | ||||
4173 | if (target->is_static() || target->can_be_statically_bound()) { | ||||
4174 | Bytecodes::Code bc = target->is_static() ? Bytecodes::_invokestatic : Bytecodes::_invokevirtual; | ||||
4175 | if (try_inline(target, /*holder_known*/ !callee->is_static(), ignore_return, bc)) { | ||||
4176 | return true; | ||||
4177 | } | ||||
4178 | } else { | ||||
4179 | print_inlining(target, "not static or statically bindable", /*success*/ false); | ||||
4180 | } | ||||
4181 | } | ||||
4182 | } else { | ||||
4183 | print_inlining(callee, "MemberName not constant", /*success*/ false); | ||||
4184 | } | ||||
4185 | } | ||||
4186 | break; | ||||
4187 | |||||
4188 | case vmIntrinsics::_linkToNative: | ||||
4189 | break; // TODO: NYI | ||||
4190 | |||||
4191 | default: | ||||
4192 | fatal("unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid), vmIntrinsics::name_at(iid))do { (*g_assert_poison) = 'X';; report_fatal(INTERNAL_ERROR, "/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4192, "unexpected intrinsic %d: %s", vmIntrinsics::as_int(iid ), vmIntrinsics::name_at(iid)); ::breakpoint(); } while (0); | ||||
4193 | break; | ||||
4194 | } | ||||
4195 | set_state(state_before->copy_for_parsing()); | ||||
4196 | return false; | ||||
4197 | } | ||||
4198 | |||||
4199 | |||||
4200 | void GraphBuilder::inline_bailout(const char* msg) { | ||||
4201 | assert(msg != NULL, "inline bailout msg must exist")do { if (!(msg != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4201, "assert(" "msg != __null" ") failed", "inline bailout msg must exist" ); ::breakpoint(); } } while (0); | ||||
4202 | _inline_bailout_msg = msg; | ||||
4203 | } | ||||
4204 | |||||
4205 | |||||
4206 | void GraphBuilder::clear_inline_bailout() { | ||||
4207 | _inline_bailout_msg = NULL__null; | ||||
4208 | } | ||||
4209 | |||||
4210 | |||||
4211 | void GraphBuilder::push_root_scope(IRScope* scope, BlockList* bci2block, BlockBegin* start) { | ||||
4212 | ScopeData* data = new ScopeData(NULL__null); | ||||
4213 | data->set_scope(scope); | ||||
4214 | data->set_bci2block(bci2block); | ||||
4215 | _scope_data = data; | ||||
4216 | _block = start; | ||||
4217 | } | ||||
4218 | |||||
4219 | |||||
4220 | void GraphBuilder::push_scope(ciMethod* callee, BlockBegin* continuation) { | ||||
4221 | IRScope* callee_scope = new IRScope(compilation(), scope(), bci(), callee, -1, false); | ||||
4222 | scope()->add_callee(callee_scope); | ||||
4223 | |||||
4224 | BlockListBuilder blb(compilation(), callee_scope, -1); | ||||
4225 | CHECK_BAILOUT(){ if (bailed_out()) return; }; | ||||
4226 | |||||
4227 | if (!blb.bci2block()->at(0)->is_set(BlockBegin::parser_loop_header_flag)) { | ||||
4228 | // this scope can be inlined directly into the caller so remove | ||||
4229 | // the block at bci 0. | ||||
4230 | blb.bci2block()->at_put(0, NULL__null); | ||||
4231 | } | ||||
4232 | |||||
4233 | set_state(new ValueStack(callee_scope, state()->copy(ValueStack::CallerState, bci()))); | ||||
4234 | |||||
4235 | ScopeData* data = new ScopeData(scope_data()); | ||||
4236 | data->set_scope(callee_scope); | ||||
4237 | data->set_bci2block(blb.bci2block()); | ||||
4238 | data->set_continuation(continuation); | ||||
4239 | _scope_data = data; | ||||
4240 | } | ||||
4241 | |||||
4242 | |||||
4243 | void GraphBuilder::push_scope_for_jsr(BlockBegin* jsr_continuation, int jsr_dest_bci) { | ||||
4244 | ScopeData* data = new ScopeData(scope_data()); | ||||
4245 | data->set_parsing_jsr(); | ||||
4246 | data->set_jsr_entry_bci(jsr_dest_bci); | ||||
4247 | data->set_jsr_return_address_local(-1); | ||||
4248 | // Must clone bci2block list as we will be mutating it in order to | ||||
4249 | // properly clone all blocks in jsr region as well as exception | ||||
4250 | // handlers containing rets | ||||
4251 | BlockList* new_bci2block = new BlockList(bci2block()->length()); | ||||
4252 | new_bci2block->appendAll(bci2block()); | ||||
4253 | data->set_bci2block(new_bci2block); | ||||
4254 | data->set_scope(scope()); | ||||
4255 | data->setup_jsr_xhandlers(); | ||||
4256 | data->set_continuation(continuation()); | ||||
4257 | data->set_jsr_continuation(jsr_continuation); | ||||
4258 | _scope_data = data; | ||||
4259 | } | ||||
4260 | |||||
4261 | |||||
4262 | void GraphBuilder::pop_scope() { | ||||
4263 | int number_of_locks = scope()->number_of_locks(); | ||||
4264 | _scope_data = scope_data()->parent(); | ||||
4265 | // accumulate minimum number of monitor slots to be reserved | ||||
4266 | scope()->set_min_number_of_locks(number_of_locks); | ||||
4267 | } | ||||
4268 | |||||
4269 | |||||
4270 | void GraphBuilder::pop_scope_for_jsr() { | ||||
4271 | _scope_data = scope_data()->parent(); | ||||
4272 | } | ||||
4273 | |||||
4274 | void GraphBuilder::append_unsafe_get(ciMethod* callee, BasicType t, bool is_volatile) { | ||||
4275 | Values* args = state()->pop_arguments(callee->arg_size()); | ||||
4276 | null_check(args->at(0)); | ||||
4277 | Instruction* offset = args->at(2); | ||||
4278 | #ifndef _LP641 | ||||
4279 | offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); | ||||
4280 | #endif | ||||
4281 | Instruction* op = append(new UnsafeGet(t, args->at(1), offset, is_volatile)); | ||||
4282 | push(op->type(), op); | ||||
4283 | compilation()->set_has_unsafe_access(true); | ||||
4284 | } | ||||
4285 | |||||
4286 | |||||
4287 | void GraphBuilder::append_unsafe_put(ciMethod* callee, BasicType t, bool is_volatile) { | ||||
4288 | Values* args = state()->pop_arguments(callee->arg_size()); | ||||
4289 | null_check(args->at(0)); | ||||
4290 | Instruction* offset = args->at(2); | ||||
4291 | #ifndef _LP641 | ||||
4292 | offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); | ||||
4293 | #endif | ||||
4294 | Value val = args->at(3); | ||||
4295 | if (t == T_BOOLEAN) { | ||||
4296 | Value mask = append(new Constant(new IntConstant(1))); | ||||
4297 | val = append(new LogicOp(Bytecodes::_iand, val, mask)); | ||||
4298 | } | ||||
4299 | Instruction* op = append(new UnsafePut(t, args->at(1), offset, val, is_volatile)); | ||||
4300 | compilation()->set_has_unsafe_access(true); | ||||
4301 | kill_all(); | ||||
4302 | } | ||||
4303 | |||||
4304 | void GraphBuilder::append_unsafe_CAS(ciMethod* callee) { | ||||
4305 | ValueStack* state_before = copy_state_for_exception(); | ||||
4306 | ValueType* result_type = as_ValueType(callee->return_type()); | ||||
4307 | assert(result_type->is_int(), "int result")do { if (!(result_type->is_int())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4307, "assert(" "result_type->is_int()" ") failed", "int result" ); ::breakpoint(); } } while (0); | ||||
4308 | Values* args = state()->pop_arguments(callee->arg_size()); | ||||
4309 | |||||
4310 | // Pop off some args to specially handle, then push back | ||||
4311 | Value newval = args->pop(); | ||||
4312 | Value cmpval = args->pop(); | ||||
4313 | Value offset = args->pop(); | ||||
4314 | Value src = args->pop(); | ||||
4315 | Value unsafe_obj = args->pop(); | ||||
4316 | |||||
4317 | // Separately handle the unsafe arg. It is not needed for code | ||||
4318 | // generation, but must be null checked | ||||
4319 | null_check(unsafe_obj); | ||||
4320 | |||||
4321 | #ifndef _LP641 | ||||
4322 | offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); | ||||
4323 | #endif | ||||
4324 | |||||
4325 | args->push(src); | ||||
4326 | args->push(offset); | ||||
4327 | args->push(cmpval); | ||||
4328 | args->push(newval); | ||||
4329 | |||||
4330 | // An unsafe CAS can alias with other field accesses, but we don't | ||||
4331 | // know which ones so mark the state as no preserved. This will | ||||
4332 | // cause CSE to invalidate memory across it. | ||||
4333 | bool preserves_state = false; | ||||
4334 | Intrinsic* result = new Intrinsic(result_type, callee->intrinsic_id(), args, false, state_before, preserves_state); | ||||
4335 | append_split(result); | ||||
4336 | push(result_type, result); | ||||
4337 | compilation()->set_has_unsafe_access(true); | ||||
4338 | } | ||||
4339 | |||||
4340 | void GraphBuilder::append_char_access(ciMethod* callee, bool is_store) { | ||||
4341 | // This intrinsic accesses byte[] array as char[] array. Computing the offsets | ||||
4342 | // correctly requires matched array shapes. | ||||
4343 | assert (arrayOopDesc::base_offset_in_bytes(T_CHAR) == arrayOopDesc::base_offset_in_bytes(T_BYTE),do { if (!(arrayOopDesc::base_offset_in_bytes(T_CHAR) == arrayOopDesc ::base_offset_in_bytes(T_BYTE))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4344, "assert(" "arrayOopDesc::base_offset_in_bytes(T_CHAR) == arrayOopDesc::base_offset_in_bytes(T_BYTE)" ") failed", "sanity: byte[] and char[] bases agree"); ::breakpoint (); } } while (0) | ||||
4344 | "sanity: byte[] and char[] bases agree")do { if (!(arrayOopDesc::base_offset_in_bytes(T_CHAR) == arrayOopDesc ::base_offset_in_bytes(T_BYTE))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4344, "assert(" "arrayOopDesc::base_offset_in_bytes(T_CHAR) == arrayOopDesc::base_offset_in_bytes(T_BYTE)" ") failed", "sanity: byte[] and char[] bases agree"); ::breakpoint (); } } while (0); | ||||
4345 | assert (type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE)*2,do { if (!(type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE) *2)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4346, "assert(" "type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE)*2" ") failed", "sanity: byte[] and char[] scales agree"); ::breakpoint (); } } while (0) | ||||
4346 | "sanity: byte[] and char[] scales agree")do { if (!(type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE) *2)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4346, "assert(" "type2aelembytes(T_CHAR) == type2aelembytes(T_BYTE)*2" ") failed", "sanity: byte[] and char[] scales agree"); ::breakpoint (); } } while (0); | ||||
4347 | |||||
4348 | ValueStack* state_before = copy_state_indexed_access(); | ||||
4349 | compilation()->set_has_access_indexed(true); | ||||
4350 | Values* args = state()->pop_arguments(callee->arg_size()); | ||||
4351 | Value array = args->at(0); | ||||
4352 | Value index = args->at(1); | ||||
4353 | if (is_store) { | ||||
4354 | Value value = args->at(2); | ||||
4355 | Instruction* store = append(new StoreIndexed(array, index, NULL__null, T_CHAR, value, state_before, false, true)); | ||||
4356 | store->set_flag(Instruction::NeedsRangeCheckFlag, false); | ||||
4357 | _memory->store_value(value); | ||||
4358 | } else { | ||||
4359 | Instruction* load = append(new LoadIndexed(array, index, NULL__null, T_CHAR, state_before, true)); | ||||
4360 | load->set_flag(Instruction::NeedsRangeCheckFlag, false); | ||||
4361 | push(load->type(), load); | ||||
4362 | } | ||||
4363 | } | ||||
4364 | |||||
4365 | void GraphBuilder::print_inlining(ciMethod* callee, const char* msg, bool success) { | ||||
4366 | CompileLog* log = compilation()->log(); | ||||
4367 | if (log != NULL__null) { | ||||
4368 | assert(msg != NULL, "inlining msg should not be null!")do { if (!(msg != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4368, "assert(" "msg != __null" ") failed", "inlining msg should not be null!" ); ::breakpoint(); } } while (0); | ||||
4369 | if (success) { | ||||
4370 | log->inline_success(msg); | ||||
4371 | } else { | ||||
4372 | log->inline_fail(msg); | ||||
4373 | } | ||||
4374 | } | ||||
4375 | EventCompilerInlining event; | ||||
4376 | if (event.should_commit()) { | ||||
4377 | CompilerEvent::InlineEvent::post(event, compilation()->env()->task()->compile_id(), method()->get_Method(), callee, success, msg, bci()); | ||||
4378 | } | ||||
4379 | |||||
4380 | CompileTask::print_inlining_ul(callee, scope()->level(), bci(), msg); | ||||
4381 | |||||
4382 | if (!compilation()->directive()->PrintInliningOption) { | ||||
4383 | return; | ||||
4384 | } | ||||
4385 | CompileTask::print_inlining_tty(callee, scope()->level(), bci(), msg); | ||||
4386 | if (success && CIPrintMethodCodes) { | ||||
4387 | callee->print_codes(); | ||||
4388 | } | ||||
4389 | } | ||||
4390 | |||||
4391 | void GraphBuilder::append_unsafe_get_and_set(ciMethod* callee, bool is_add) { | ||||
4392 | Values* args = state()->pop_arguments(callee->arg_size()); | ||||
4393 | BasicType t = callee->return_type()->basic_type(); | ||||
4394 | null_check(args->at(0)); | ||||
4395 | Instruction* offset = args->at(2); | ||||
4396 | #ifndef _LP641 | ||||
4397 | offset = append(new Convert(Bytecodes::_l2i, offset, as_ValueType(T_INT))); | ||||
4398 | #endif | ||||
4399 | Instruction* op = append(new UnsafeGetAndSet(t, args->at(1), offset, args->at(3), is_add)); | ||||
4400 | compilation()->set_has_unsafe_access(true); | ||||
4401 | kill_all(); | ||||
4402 | push(op->type(), op); | ||||
4403 | } | ||||
4404 | |||||
4405 | #ifndef PRODUCT | ||||
4406 | void GraphBuilder::print_stats() { | ||||
4407 | vmap()->print(); | ||||
4408 | } | ||||
4409 | #endif // PRODUCT | ||||
4410 | |||||
4411 | void GraphBuilder::profile_call(ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) { | ||||
4412 | assert(known_holder == NULL || (known_holder->is_instance_klass() &&do { if (!(known_holder == __null || (known_holder->is_instance_klass () && (!known_holder->is_interface() || ((ciInstanceKlass *)known_holder)->has_nonstatic_concrete_methods())))) { (* g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4414, "assert(" "known_holder == __null || (known_holder->is_instance_klass() && (!known_holder->is_interface() || ((ciInstanceKlass*)known_holder)->has_nonstatic_concrete_methods()))" ") failed", "should be non-static concrete method"); ::breakpoint (); } } while (0) | ||||
4413 | (!known_holder->is_interface() ||do { if (!(known_holder == __null || (known_holder->is_instance_klass () && (!known_holder->is_interface() || ((ciInstanceKlass *)known_holder)->has_nonstatic_concrete_methods())))) { (* g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4414, "assert(" "known_holder == __null || (known_holder->is_instance_klass() && (!known_holder->is_interface() || ((ciInstanceKlass*)known_holder)->has_nonstatic_concrete_methods()))" ") failed", "should be non-static concrete method"); ::breakpoint (); } } while (0) | ||||
4414 | ((ciInstanceKlass*)known_holder)->has_nonstatic_concrete_methods())), "should be non-static concrete method")do { if (!(known_holder == __null || (known_holder->is_instance_klass () && (!known_holder->is_interface() || ((ciInstanceKlass *)known_holder)->has_nonstatic_concrete_methods())))) { (* g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4414, "assert(" "known_holder == __null || (known_holder->is_instance_klass() && (!known_holder->is_interface() || ((ciInstanceKlass*)known_holder)->has_nonstatic_concrete_methods()))" ") failed", "should be non-static concrete method"); ::breakpoint (); } } while (0); | ||||
4415 | if (known_holder != NULL__null) { | ||||
4416 | if (known_holder->exact_klass() == NULL__null) { | ||||
4417 | known_holder = compilation()->cha_exact_type(known_holder); | ||||
4418 | } | ||||
4419 | } | ||||
4420 | |||||
4421 | append(new ProfileCall(method(), bci(), callee, recv, known_holder, obj_args, inlined)); | ||||
4422 | } | ||||
4423 | |||||
4424 | void GraphBuilder::profile_return_type(Value ret, ciMethod* callee, ciMethod* m, int invoke_bci) { | ||||
4425 | assert((m == NULL) == (invoke_bci < 0), "invalid method and invalid bci together")do { if (!((m == __null) == (invoke_bci < 0))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_GraphBuilder.cpp" , 4425, "assert(" "(m == __null) == (invoke_bci < 0)" ") failed" , "invalid method and invalid bci together"); ::breakpoint(); } } while (0); | ||||
4426 | if (m == NULL__null) { | ||||
4427 | m = method(); | ||||
4428 | } | ||||
4429 | if (invoke_bci < 0) { | ||||
4430 | invoke_bci = bci(); | ||||
4431 | } | ||||
4432 | ciMethodData* md = m->method_data_or_null(); | ||||
4433 | ciProfileData* data = md->bci_to_data(invoke_bci); | ||||
4434 | if (data != NULL__null && (data->is_CallTypeData() || data->is_VirtualCallTypeData())) { | ||||
4435 | bool has_return = data->is_CallTypeData() ? ((ciCallTypeData*)data)->has_return() : ((ciVirtualCallTypeData*)data)->has_return(); | ||||
4436 | if (has_return) { | ||||
4437 | append(new ProfileReturnType(m , invoke_bci, callee, ret)); | ||||
4438 | } | ||||
4439 | } | ||||
4440 | } | ||||
4441 | |||||
4442 | void GraphBuilder::profile_invocation(ciMethod* callee, ValueStack* state) { | ||||
4443 | append(new ProfileInvoke(callee, state)); | ||||
4444 | } |
1 | /* | |||
2 | * Copyright (c) 1999, 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 | #ifndef SHARE_C1_C1_INSTRUCTION_HPP | |||
26 | #define SHARE_C1_C1_INSTRUCTION_HPP | |||
27 | ||||
28 | #include "c1/c1_Compilation.hpp" | |||
29 | #include "c1/c1_LIR.hpp" | |||
30 | #include "c1/c1_ValueType.hpp" | |||
31 | #include "ci/ciField.hpp" | |||
32 | ||||
33 | // Predefined classes | |||
34 | class ciField; | |||
35 | class ValueStack; | |||
36 | class InstructionPrinter; | |||
37 | class IRScope; | |||
38 | ||||
39 | ||||
40 | // Instruction class hierarchy | |||
41 | // | |||
42 | // All leaf classes in the class hierarchy are concrete classes | |||
43 | // (i.e., are instantiated). All other classes are abstract and | |||
44 | // serve factoring. | |||
45 | ||||
46 | class Instruction; | |||
47 | class Phi; | |||
48 | class Local; | |||
49 | class Constant; | |||
50 | class AccessField; | |||
51 | class LoadField; | |||
52 | class StoreField; | |||
53 | class AccessArray; | |||
54 | class ArrayLength; | |||
55 | class AccessIndexed; | |||
56 | class LoadIndexed; | |||
57 | class StoreIndexed; | |||
58 | class NegateOp; | |||
59 | class Op2; | |||
60 | class ArithmeticOp; | |||
61 | class ShiftOp; | |||
62 | class LogicOp; | |||
63 | class CompareOp; | |||
64 | class IfOp; | |||
65 | class Convert; | |||
66 | class NullCheck; | |||
67 | class TypeCast; | |||
68 | class OsrEntry; | |||
69 | class ExceptionObject; | |||
70 | class StateSplit; | |||
71 | class Invoke; | |||
72 | class NewInstance; | |||
73 | class NewArray; | |||
74 | class NewTypeArray; | |||
75 | class NewObjectArray; | |||
76 | class NewMultiArray; | |||
77 | class TypeCheck; | |||
78 | class CheckCast; | |||
79 | class InstanceOf; | |||
80 | class AccessMonitor; | |||
81 | class MonitorEnter; | |||
82 | class MonitorExit; | |||
83 | class Intrinsic; | |||
84 | class BlockBegin; | |||
85 | class BlockEnd; | |||
86 | class Goto; | |||
87 | class If; | |||
88 | class Switch; | |||
89 | class TableSwitch; | |||
90 | class LookupSwitch; | |||
91 | class Return; | |||
92 | class Throw; | |||
93 | class Base; | |||
94 | class RoundFP; | |||
95 | class UnsafeOp; | |||
96 | class UnsafeGet; | |||
97 | class UnsafePut; | |||
98 | class UnsafeGetAndSet; | |||
99 | class ProfileCall; | |||
100 | class ProfileReturnType; | |||
101 | class ProfileInvoke; | |||
102 | class RuntimeCall; | |||
103 | class MemBar; | |||
104 | class RangeCheckPredicate; | |||
105 | #ifdef ASSERT1 | |||
106 | class Assert; | |||
107 | #endif | |||
108 | ||||
109 | // A Value is a reference to the instruction creating the value | |||
110 | typedef Instruction* Value; | |||
111 | typedef GrowableArray<Value> Values; | |||
112 | typedef GrowableArray<ValueStack*> ValueStackStack; | |||
113 | ||||
114 | // BlockClosure is the base class for block traversal/iteration. | |||
115 | ||||
116 | class BlockClosure: public CompilationResourceObj { | |||
117 | public: | |||
118 | virtual void block_do(BlockBegin* block) = 0; | |||
119 | }; | |||
120 | ||||
121 | ||||
122 | // A simple closure class for visiting the values of an Instruction | |||
123 | class ValueVisitor: public StackObj { | |||
124 | public: | |||
125 | virtual void visit(Value* v) = 0; | |||
126 | }; | |||
127 | ||||
128 | ||||
129 | // Some array and list classes | |||
130 | typedef GrowableArray<BlockBegin*> BlockBeginArray; | |||
131 | ||||
132 | class BlockList: public GrowableArray<BlockBegin*> { | |||
133 | public: | |||
134 | BlockList(): GrowableArray<BlockBegin*>() {} | |||
135 | BlockList(const int size): GrowableArray<BlockBegin*>(size) {} | |||
136 | BlockList(const int size, BlockBegin* init): GrowableArray<BlockBegin*>(size, size, init) {} | |||
137 | ||||
138 | void iterate_forward(BlockClosure* closure); | |||
139 | void iterate_backward(BlockClosure* closure); | |||
140 | void values_do(ValueVisitor* f); | |||
141 | void print(bool cfg_only = false, bool live_only = false) PRODUCT_RETURN; | |||
142 | }; | |||
143 | ||||
144 | ||||
145 | // InstructionVisitors provide type-based dispatch for instructions. | |||
146 | // For each concrete Instruction class X, a virtual function do_X is | |||
147 | // provided. Functionality that needs to be implemented for all classes | |||
148 | // (e.g., printing, code generation) is factored out into a specialised | |||
149 | // visitor instead of added to the Instruction classes itself. | |||
150 | ||||
151 | class InstructionVisitor: public StackObj { | |||
152 | public: | |||
153 | virtual void do_Phi (Phi* x) = 0; | |||
154 | virtual void do_Local (Local* x) = 0; | |||
155 | virtual void do_Constant (Constant* x) = 0; | |||
156 | virtual void do_LoadField (LoadField* x) = 0; | |||
157 | virtual void do_StoreField (StoreField* x) = 0; | |||
158 | virtual void do_ArrayLength (ArrayLength* x) = 0; | |||
159 | virtual void do_LoadIndexed (LoadIndexed* x) = 0; | |||
160 | virtual void do_StoreIndexed (StoreIndexed* x) = 0; | |||
161 | virtual void do_NegateOp (NegateOp* x) = 0; | |||
162 | virtual void do_ArithmeticOp (ArithmeticOp* x) = 0; | |||
163 | virtual void do_ShiftOp (ShiftOp* x) = 0; | |||
164 | virtual void do_LogicOp (LogicOp* x) = 0; | |||
165 | virtual void do_CompareOp (CompareOp* x) = 0; | |||
166 | virtual void do_IfOp (IfOp* x) = 0; | |||
167 | virtual void do_Convert (Convert* x) = 0; | |||
168 | virtual void do_NullCheck (NullCheck* x) = 0; | |||
169 | virtual void do_TypeCast (TypeCast* x) = 0; | |||
170 | virtual void do_Invoke (Invoke* x) = 0; | |||
171 | virtual void do_NewInstance (NewInstance* x) = 0; | |||
172 | virtual void do_NewTypeArray (NewTypeArray* x) = 0; | |||
173 | virtual void do_NewObjectArray (NewObjectArray* x) = 0; | |||
174 | virtual void do_NewMultiArray (NewMultiArray* x) = 0; | |||
175 | virtual void do_CheckCast (CheckCast* x) = 0; | |||
176 | virtual void do_InstanceOf (InstanceOf* x) = 0; | |||
177 | virtual void do_MonitorEnter (MonitorEnter* x) = 0; | |||
178 | virtual void do_MonitorExit (MonitorExit* x) = 0; | |||
179 | virtual void do_Intrinsic (Intrinsic* x) = 0; | |||
180 | virtual void do_BlockBegin (BlockBegin* x) = 0; | |||
181 | virtual void do_Goto (Goto* x) = 0; | |||
182 | virtual void do_If (If* x) = 0; | |||
183 | virtual void do_TableSwitch (TableSwitch* x) = 0; | |||
184 | virtual void do_LookupSwitch (LookupSwitch* x) = 0; | |||
185 | virtual void do_Return (Return* x) = 0; | |||
186 | virtual void do_Throw (Throw* x) = 0; | |||
187 | virtual void do_Base (Base* x) = 0; | |||
188 | virtual void do_OsrEntry (OsrEntry* x) = 0; | |||
189 | virtual void do_ExceptionObject(ExceptionObject* x) = 0; | |||
190 | virtual void do_RoundFP (RoundFP* x) = 0; | |||
191 | virtual void do_UnsafeGet (UnsafeGet* x) = 0; | |||
192 | virtual void do_UnsafePut (UnsafePut* x) = 0; | |||
193 | virtual void do_UnsafeGetAndSet(UnsafeGetAndSet* x) = 0; | |||
194 | virtual void do_ProfileCall (ProfileCall* x) = 0; | |||
195 | virtual void do_ProfileReturnType (ProfileReturnType* x) = 0; | |||
196 | virtual void do_ProfileInvoke (ProfileInvoke* x) = 0; | |||
197 | virtual void do_RuntimeCall (RuntimeCall* x) = 0; | |||
198 | virtual void do_MemBar (MemBar* x) = 0; | |||
199 | virtual void do_RangeCheckPredicate(RangeCheckPredicate* x) = 0; | |||
200 | #ifdef ASSERT1 | |||
201 | virtual void do_Assert (Assert* x) = 0; | |||
202 | #endif | |||
203 | }; | |||
204 | ||||
205 | ||||
206 | // Hashing support | |||
207 | // | |||
208 | // Note: This hash functions affect the performance | |||
209 | // of ValueMap - make changes carefully! | |||
210 | ||||
211 | #define HASH1(x1 )((intx)(x1)) ((intx)(x1)) | |||
212 | #define HASH2(x1, x2 )((((intx)(x1)) << 7) ^ ((intx)(x2))) ((HASH1(x1 )((intx)(x1)) << 7) ^ HASH1(x2)((intx)(x2))) | |||
213 | #define HASH3(x1, x2, x3 )((((((intx)(x1)) << 7) ^ ((intx)(x2))) << 7) ^ (( intx)(x3))) ((HASH2(x1, x2 )((((intx)(x1)) << 7) ^ ((intx)(x2))) << 7) ^ HASH1(x3)((intx)(x3))) | |||
214 | #define HASH4(x1, x2, x3, x4)((((((((intx)(x1)) << 7) ^ ((intx)(x2))) << 7) ^ ( (intx)(x3))) << 7) ^ ((intx)(x4))) ((HASH3(x1, x2, x3)((((((intx)(x1)) << 7) ^ ((intx)(x2))) << 7) ^ (( intx)(x3))) << 7) ^ HASH1(x4)((intx)(x4))) | |||
215 | ||||
216 | ||||
217 | // The following macros are used to implement instruction-specific hashing. | |||
218 | // By default, each instruction implements hash() and is_equal(Value), used | |||
219 | // for value numbering/common subexpression elimination. The default imple- | |||
220 | // mentation disables value numbering. Each instruction which can be value- | |||
221 | // numbered, should define corresponding hash() and is_equal(Value) functions | |||
222 | // via the macros below. The f arguments specify all the values/op codes, etc. | |||
223 | // that need to be identical for two instructions to be identical. | |||
224 | // | |||
225 | // Note: The default implementation of hash() returns 0 in order to indicate | |||
226 | // that the instruction should not be considered for value numbering. | |||
227 | // The currently used hash functions do not guarantee that never a 0 | |||
228 | // is produced. While this is still correct, it may be a performance | |||
229 | // bug (no value numbering for that node). However, this situation is | |||
230 | // so unlikely, that we are not going to handle it specially. | |||
231 | ||||
232 | #define HASHING1(class_name, enabled, f1)virtual intx hash() const { return (enabled) ? ((((intx)(name ())) << 7) ^ ((intx)(f1))) : 0; } virtual bool is_equal (Value v) const { if (!(enabled) ) return false; class_name* _v = v->as_class_name(); if (_v == __null ) return false; if (f1 != _v->f1) return false; return true; } \ | |||
233 | virtual intx hash() const { \ | |||
234 | return (enabled) ? HASH2(name(), f1)((((intx)(name())) << 7) ^ ((intx)(f1))) : 0; \ | |||
235 | } \ | |||
236 | virtual bool is_equal(Value v) const { \ | |||
237 | if (!(enabled) ) return false; \ | |||
238 | class_name* _v = v->as_##class_name(); \ | |||
239 | if (_v == NULL__null ) return false; \ | |||
240 | if (f1 != _v->f1) return false; \ | |||
241 | return true; \ | |||
242 | } \ | |||
243 | ||||
244 | ||||
245 | #define HASHING2(class_name, enabled, f1, f2)virtual intx hash() const { return (enabled) ? ((((((intx)(name ())) << 7) ^ ((intx)(f1))) << 7) ^ ((intx)(f2))) : 0; } virtual bool is_equal(Value v) const { if (!(enabled) ) return false; class_name* _v = v->as_class_name(); if (_v == __null ) return false; if (f1 != _v->f1) return false; if (f2 != _v->f2) return false; return true; } \ | |||
246 | virtual intx hash() const { \ | |||
247 | return (enabled) ? HASH3(name(), f1, f2)((((((intx)(name())) << 7) ^ ((intx)(f1))) << 7) ^ ((intx)(f2))) : 0; \ | |||
248 | } \ | |||
249 | virtual bool is_equal(Value v) const { \ | |||
250 | if (!(enabled) ) return false; \ | |||
251 | class_name* _v = v->as_##class_name(); \ | |||
252 | if (_v == NULL__null ) return false; \ | |||
253 | if (f1 != _v->f1) return false; \ | |||
254 | if (f2 != _v->f2) return false; \ | |||
255 | return true; \ | |||
256 | } \ | |||
257 | ||||
258 | ||||
259 | #define HASHING3(class_name, enabled, f1, f2, f3)virtual intx hash() const { return (enabled) ? ((((((((intx)( name())) << 7) ^ ((intx)(f1))) << 7) ^ ((intx)(f2 ))) << 7) ^ ((intx)(f3))) : 0; } virtual bool is_equal( Value v) const { if (!(enabled) ) return false; class_name* _v = v->as_class_name(); if (_v == __null ) return false; if (f1 != _v->f1) return false; if (f2 != _v->f2) return false ; if (f3 != _v->f3) return false; return true; } \ | |||
260 | virtual intx hash() const { \ | |||
261 | return (enabled) ? HASH4(name(), f1, f2, f3)((((((((intx)(name())) << 7) ^ ((intx)(f1))) << 7 ) ^ ((intx)(f2))) << 7) ^ ((intx)(f3))) : 0; \ | |||
262 | } \ | |||
263 | virtual bool is_equal(Value v) const { \ | |||
264 | if (!(enabled) ) return false; \ | |||
265 | class_name* _v = v->as_##class_name(); \ | |||
266 | if (_v == NULL__null ) return false; \ | |||
267 | if (f1 != _v->f1) return false; \ | |||
268 | if (f2 != _v->f2) return false; \ | |||
269 | if (f3 != _v->f3) return false; \ | |||
270 | return true; \ | |||
271 | } \ | |||
272 | ||||
273 | ||||
274 | // The mother of all instructions... | |||
275 | ||||
276 | class Instruction: public CompilationResourceObj { | |||
277 | private: | |||
278 | int _id; // the unique instruction id | |||
279 | #ifndef PRODUCT | |||
280 | int _printable_bci; // the bci of the instruction for printing | |||
281 | #endif | |||
282 | int _use_count; // the number of instructions refering to this value (w/o prev/next); only roots can have use count = 0 or > 1 | |||
283 | int _pin_state; // set of PinReason describing the reason for pinning | |||
284 | ValueType* _type; // the instruction value type | |||
285 | Instruction* _next; // the next instruction if any (NULL for BlockEnd instructions) | |||
286 | Instruction* _subst; // the substitution instruction if any | |||
287 | LIR_Opr _operand; // LIR specific information | |||
288 | unsigned int _flags; // Flag bits | |||
289 | ||||
290 | ValueStack* _state_before; // Copy of state with input operands still on stack (or NULL) | |||
291 | ValueStack* _exception_state; // Copy of state for exception handling | |||
292 | XHandlers* _exception_handlers; // Flat list of exception handlers covering this instruction | |||
293 | ||||
294 | friend class UseCountComputer; | |||
295 | ||||
296 | void update_exception_state(ValueStack* state); | |||
297 | ||||
298 | protected: | |||
299 | BlockBegin* _block; // Block that contains this instruction | |||
300 | ||||
301 | void set_type(ValueType* type) { | |||
302 | assert(type != NULL, "type must exist")do { if (!(type != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 302, "assert(" "type != __null" ") failed", "type must exist" ); ::breakpoint(); } } while (0); | |||
303 | _type = type; | |||
304 | } | |||
305 | ||||
306 | // Helper class to keep track of which arguments need a null check | |||
307 | class ArgsNonNullState { | |||
308 | private: | |||
309 | int _nonnull_state; // mask identifying which args are nonnull | |||
310 | public: | |||
311 | ArgsNonNullState() | |||
312 | : _nonnull_state(AllBits) {} | |||
313 | ||||
314 | // Does argument number i needs a null check? | |||
315 | bool arg_needs_null_check(int i) const { | |||
316 | // No data is kept for arguments starting at position 33 so | |||
317 | // conservatively assume that they need a null check. | |||
318 | if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { | |||
319 | return is_set_nth_bit(_nonnull_state, i); | |||
320 | } | |||
321 | return true; | |||
322 | } | |||
323 | ||||
324 | // Set whether argument number i needs a null check or not | |||
325 | void set_arg_needs_null_check(int i, bool check) { | |||
326 | if (i >= 0 && i < (int)sizeof(_nonnull_state) * BitsPerByte) { | |||
327 | if (check) { | |||
328 | _nonnull_state |= nth_bit(i)(((i) >= BitsPerWord) ? 0 : (OneBit << (i))); | |||
329 | } else { | |||
330 | _nonnull_state &= ~(nth_bit(i)(((i) >= BitsPerWord) ? 0 : (OneBit << (i)))); | |||
331 | } | |||
332 | } | |||
333 | } | |||
334 | }; | |||
335 | ||||
336 | public: | |||
337 | void* operator new(size_t size) throw() { | |||
338 | Compilation* c = Compilation::current(); | |||
339 | void* res = c->arena()->Amalloc(size); | |||
340 | return res; | |||
341 | } | |||
342 | ||||
343 | static const int no_bci = -99; | |||
344 | ||||
345 | enum InstructionFlag { | |||
346 | NeedsNullCheckFlag = 0, | |||
347 | CanTrapFlag, | |||
348 | DirectCompareFlag, | |||
349 | IsEliminatedFlag, | |||
350 | IsSafepointFlag, | |||
351 | IsStaticFlag, | |||
352 | NeedsStoreCheckFlag, | |||
353 | NeedsWriteBarrierFlag, | |||
354 | PreservesStateFlag, | |||
355 | TargetIsFinalFlag, | |||
356 | TargetIsLoadedFlag, | |||
357 | UnorderedIsTrueFlag, | |||
358 | NeedsPatchingFlag, | |||
359 | ThrowIncompatibleClassChangeErrorFlag, | |||
360 | InvokeSpecialReceiverCheckFlag, | |||
361 | ProfileMDOFlag, | |||
362 | IsLinkedInBlockFlag, | |||
363 | NeedsRangeCheckFlag, | |||
364 | InWorkListFlag, | |||
365 | DeoptimizeOnException, | |||
366 | InstructionLastFlag | |||
367 | }; | |||
368 | ||||
369 | public: | |||
370 | bool check_flag(InstructionFlag id) const { return (_flags & (1 << id)) != 0; } | |||
371 | void set_flag(InstructionFlag id, bool f) { _flags = f ? (_flags | (1 << id)) : (_flags & ~(1 << id)); }; | |||
372 | ||||
373 | // 'globally' used condition values | |||
374 | enum Condition { | |||
375 | eql, neq, lss, leq, gtr, geq, aeq, beq | |||
376 | }; | |||
377 | ||||
378 | // Instructions may be pinned for many reasons and under certain conditions | |||
379 | // with enough knowledge it's possible to safely unpin them. | |||
380 | enum PinReason { | |||
381 | PinUnknown = 1 << 0 | |||
382 | , PinExplicitNullCheck = 1 << 3 | |||
383 | , PinStackForStateSplit= 1 << 12 | |||
384 | , PinStateSplitConstructor= 1 << 13 | |||
385 | , PinGlobalValueNumbering= 1 << 14 | |||
386 | }; | |||
387 | ||||
388 | static Condition mirror(Condition cond); | |||
389 | static Condition negate(Condition cond); | |||
390 | ||||
391 | // initialization | |||
392 | static int number_of_instructions() { | |||
393 | return Compilation::current()->number_of_instructions(); | |||
394 | } | |||
395 | ||||
396 | // creation | |||
397 | Instruction(ValueType* type, ValueStack* state_before = NULL__null, bool type_is_constant = false) | |||
398 | : _id(Compilation::current()->get_next_id()), | |||
399 | #ifndef PRODUCT | |||
400 | _printable_bci(-99), | |||
401 | #endif | |||
402 | _use_count(0) | |||
403 | , _pin_state(0) | |||
404 | , _type(type) | |||
405 | , _next(NULL__null) | |||
406 | , _subst(NULL__null) | |||
407 | , _operand(LIR_OprFact::illegalOpr) | |||
408 | , _flags(0) | |||
409 | , _state_before(state_before) | |||
410 | , _exception_handlers(NULL__null) | |||
411 | , _block(NULL__null) | |||
412 | { | |||
413 | check_state(state_before); | |||
414 | assert(type != NULL && (!type->is_constant() || type_is_constant), "type must exist")do { if (!(type != __null && (!type->is_constant() || type_is_constant))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 414, "assert(" "type != __null && (!type->is_constant() || type_is_constant)" ") failed", "type must exist"); ::breakpoint(); } } while (0 ); | |||
415 | update_exception_state(_state_before); | |||
416 | } | |||
417 | ||||
418 | // accessors | |||
419 | int id() const { return _id; } | |||
420 | #ifndef PRODUCT | |||
421 | bool has_printable_bci() const { return _printable_bci != -99; } | |||
422 | int printable_bci() const { assert(has_printable_bci(), "_printable_bci should have been set")do { if (!(has_printable_bci())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 422, "assert(" "has_printable_bci()" ") failed", "_printable_bci should have been set" ); ::breakpoint(); } } while (0); return _printable_bci; } | |||
423 | void set_printable_bci(int bci) { _printable_bci = bci; } | |||
424 | #endif | |||
425 | int dominator_depth(); | |||
426 | int use_count() const { return _use_count; } | |||
427 | int pin_state() const { return _pin_state; } | |||
428 | bool is_pinned() const { return _pin_state != 0 || PinAllInstructions; } | |||
429 | ValueType* type() const { return _type; } | |||
430 | BlockBegin *block() const { return _block; } | |||
431 | Instruction* prev(); // use carefully, expensive operation | |||
432 | Instruction* next() const { return _next; } | |||
433 | bool has_subst() const { return _subst != NULL__null; } | |||
434 | Instruction* subst() { return _subst == NULL__null ? this : _subst->subst(); } | |||
435 | LIR_Opr operand() const { return _operand; } | |||
436 | ||||
437 | void set_needs_null_check(bool f) { set_flag(NeedsNullCheckFlag, f); } | |||
438 | bool needs_null_check() const { return check_flag(NeedsNullCheckFlag); } | |||
439 | bool is_linked() const { return check_flag(IsLinkedInBlockFlag); } | |||
440 | bool can_be_linked() { return as_Local() == NULL__null && as_Phi() == NULL__null; } | |||
441 | ||||
442 | bool is_null_obj() { return as_Constant() != NULL__null && type()->as_ObjectType()->constant_value()->is_null_object(); } | |||
443 | ||||
444 | bool has_uses() const { return use_count() > 0; } | |||
445 | ValueStack* state_before() const { return _state_before; } | |||
446 | ValueStack* exception_state() const { return _exception_state; } | |||
447 | virtual bool needs_exception_state() const { return true; } | |||
448 | XHandlers* exception_handlers() const { return _exception_handlers; } | |||
449 | ||||
450 | // manipulation | |||
451 | void pin(PinReason reason) { _pin_state |= reason; } | |||
452 | void pin() { _pin_state |= PinUnknown; } | |||
453 | // DANGEROUS: only used by EliminateStores | |||
454 | void unpin(PinReason reason) { assert((reason & PinUnknown) == 0, "can't unpin unknown state")do { if (!((reason & PinUnknown) == 0)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 454, "assert(" "(reason & PinUnknown) == 0" ") failed", "can't unpin unknown state"); ::breakpoint(); } } while (0); _pin_state &= ~reason; } | |||
455 | ||||
456 | Instruction* set_next(Instruction* next) { | |||
457 | assert(next->has_printable_bci(), "_printable_bci should have been set")do { if (!(next->has_printable_bci())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 457, "assert(" "next->has_printable_bci()" ") failed", "_printable_bci should have been set" ); ::breakpoint(); } } while (0); | |||
458 | assert(next != NULL, "must not be NULL")do { if (!(next != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 458, "assert(" "next != __null" ") failed", "must not be NULL" ); ::breakpoint(); } } while (0); | |||
459 | assert(as_BlockEnd() == NULL, "BlockEnd instructions must have no next")do { if (!(as_BlockEnd() == __null)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 459, "assert(" "as_BlockEnd() == __null" ") failed", "BlockEnd instructions must have no next" ); ::breakpoint(); } } while (0); | |||
460 | assert(next->can_be_linked(), "shouldn't link these instructions into list")do { if (!(next->can_be_linked())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 460, "assert(" "next->can_be_linked()" ") failed", "shouldn't link these instructions into list" ); ::breakpoint(); } } while (0); | |||
461 | ||||
462 | BlockBegin *block = this->block(); | |||
463 | next->_block = block; | |||
464 | ||||
465 | next->set_flag(Instruction::IsLinkedInBlockFlag, true); | |||
466 | _next = next; | |||
467 | return next; | |||
468 | } | |||
469 | ||||
470 | Instruction* set_next(Instruction* next, int bci) { | |||
471 | #ifndef PRODUCT | |||
472 | next->set_printable_bci(bci); | |||
473 | #endif | |||
474 | return set_next(next); | |||
475 | } | |||
476 | ||||
477 | // when blocks are merged | |||
478 | void fixup_block_pointers() { | |||
479 | Instruction *cur = next()->next(); // next()'s block is set in set_next | |||
480 | while (cur && cur->_block != block()) { | |||
481 | cur->_block = block(); | |||
482 | cur = cur->next(); | |||
483 | } | |||
484 | } | |||
485 | ||||
486 | Instruction *insert_after(Instruction *i) { | |||
487 | Instruction* n = _next; | |||
488 | set_next(i); | |||
489 | i->set_next(n); | |||
490 | return _next; | |||
491 | } | |||
492 | ||||
493 | Instruction *insert_after_same_bci(Instruction *i) { | |||
494 | #ifndef PRODUCT | |||
495 | i->set_printable_bci(printable_bci()); | |||
496 | #endif | |||
497 | return insert_after(i); | |||
498 | } | |||
499 | ||||
500 | void set_subst(Instruction* subst) { | |||
501 | assert(subst == NULL ||do { if (!(subst == __null || type()->base() == subst-> type()->base() || subst->type()->base() == illegalType )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 503, "assert(" "subst == __null || type()->base() == subst->type()->base() || subst->type()->base() == illegalType" ") failed", "type can't change"); ::breakpoint(); } } while ( 0) | |||
502 | type()->base() == subst->type()->base() ||do { if (!(subst == __null || type()->base() == subst-> type()->base() || subst->type()->base() == illegalType )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 503, "assert(" "subst == __null || type()->base() == subst->type()->base() || subst->type()->base() == illegalType" ") failed", "type can't change"); ::breakpoint(); } } while ( 0) | |||
503 | subst->type()->base() == illegalType, "type can't change")do { if (!(subst == __null || type()->base() == subst-> type()->base() || subst->type()->base() == illegalType )) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 503, "assert(" "subst == __null || type()->base() == subst->type()->base() || subst->type()->base() == illegalType" ") failed", "type can't change"); ::breakpoint(); } } while ( 0); | |||
504 | _subst = subst; | |||
505 | } | |||
506 | void set_exception_handlers(XHandlers *xhandlers) { _exception_handlers = xhandlers; } | |||
507 | void set_exception_state(ValueStack* s) { check_state(s); _exception_state = s; } | |||
508 | void set_state_before(ValueStack* s) { check_state(s); _state_before = s; } | |||
509 | ||||
510 | // machine-specifics | |||
511 | void set_operand(LIR_Opr operand) { assert(operand != LIR_OprFact::illegalOpr, "operand must exist")do { if (!(operand != LIR_OprFact::illegalOpr)) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 511, "assert(" "operand != LIR_OprFact::illegalOpr" ") failed" , "operand must exist"); ::breakpoint(); } } while (0); _operand = operand; } | |||
512 | void clear_operand() { _operand = LIR_OprFact::illegalOpr; } | |||
513 | ||||
514 | // generic | |||
515 | virtual Instruction* as_Instruction() { return this; } // to satisfy HASHING1 macro | |||
516 | virtual Phi* as_Phi() { return NULL__null; } | |||
517 | virtual Local* as_Local() { return NULL__null; } | |||
518 | virtual Constant* as_Constant() { return NULL__null; } | |||
519 | virtual AccessField* as_AccessField() { return NULL__null; } | |||
520 | virtual LoadField* as_LoadField() { return NULL__null; } | |||
521 | virtual StoreField* as_StoreField() { return NULL__null; } | |||
522 | virtual AccessArray* as_AccessArray() { return NULL__null; } | |||
523 | virtual ArrayLength* as_ArrayLength() { return NULL__null; } | |||
524 | virtual AccessIndexed* as_AccessIndexed() { return NULL__null; } | |||
525 | virtual LoadIndexed* as_LoadIndexed() { return NULL__null; } | |||
526 | virtual StoreIndexed* as_StoreIndexed() { return NULL__null; } | |||
527 | virtual NegateOp* as_NegateOp() { return NULL__null; } | |||
528 | virtual Op2* as_Op2() { return NULL__null; } | |||
529 | virtual ArithmeticOp* as_ArithmeticOp() { return NULL__null; } | |||
530 | virtual ShiftOp* as_ShiftOp() { return NULL__null; } | |||
531 | virtual LogicOp* as_LogicOp() { return NULL__null; } | |||
532 | virtual CompareOp* as_CompareOp() { return NULL__null; } | |||
533 | virtual IfOp* as_IfOp() { return NULL__null; } | |||
534 | virtual Convert* as_Convert() { return NULL__null; } | |||
535 | virtual NullCheck* as_NullCheck() { return NULL__null; } | |||
536 | virtual OsrEntry* as_OsrEntry() { return NULL__null; } | |||
537 | virtual StateSplit* as_StateSplit() { return NULL__null; } | |||
538 | virtual Invoke* as_Invoke() { return NULL__null; } | |||
539 | virtual NewInstance* as_NewInstance() { return NULL__null; } | |||
540 | virtual NewArray* as_NewArray() { return NULL__null; } | |||
541 | virtual NewTypeArray* as_NewTypeArray() { return NULL__null; } | |||
542 | virtual NewObjectArray* as_NewObjectArray() { return NULL__null; } | |||
543 | virtual NewMultiArray* as_NewMultiArray() { return NULL__null; } | |||
544 | virtual TypeCheck* as_TypeCheck() { return NULL__null; } | |||
545 | virtual CheckCast* as_CheckCast() { return NULL__null; } | |||
546 | virtual InstanceOf* as_InstanceOf() { return NULL__null; } | |||
547 | virtual TypeCast* as_TypeCast() { return NULL__null; } | |||
548 | virtual AccessMonitor* as_AccessMonitor() { return NULL__null; } | |||
549 | virtual MonitorEnter* as_MonitorEnter() { return NULL__null; } | |||
550 | virtual MonitorExit* as_MonitorExit() { return NULL__null; } | |||
551 | virtual Intrinsic* as_Intrinsic() { return NULL__null; } | |||
552 | virtual BlockBegin* as_BlockBegin() { return NULL__null; } | |||
553 | virtual BlockEnd* as_BlockEnd() { return NULL__null; } | |||
554 | virtual Goto* as_Goto() { return NULL__null; } | |||
555 | virtual If* as_If() { return NULL__null; } | |||
556 | virtual TableSwitch* as_TableSwitch() { return NULL__null; } | |||
557 | virtual LookupSwitch* as_LookupSwitch() { return NULL__null; } | |||
558 | virtual Return* as_Return() { return NULL__null; } | |||
559 | virtual Throw* as_Throw() { return NULL__null; } | |||
560 | virtual Base* as_Base() { return NULL__null; } | |||
561 | virtual RoundFP* as_RoundFP() { return NULL__null; } | |||
562 | virtual ExceptionObject* as_ExceptionObject() { return NULL__null; } | |||
563 | virtual UnsafeOp* as_UnsafeOp() { return NULL__null; } | |||
564 | virtual ProfileInvoke* as_ProfileInvoke() { return NULL__null; } | |||
565 | virtual RangeCheckPredicate* as_RangeCheckPredicate() { return NULL__null; } | |||
566 | ||||
567 | #ifdef ASSERT1 | |||
568 | virtual Assert* as_Assert() { return NULL__null; } | |||
569 | #endif | |||
570 | ||||
571 | virtual void visit(InstructionVisitor* v) = 0; | |||
572 | ||||
573 | virtual bool can_trap() const { return false; } | |||
574 | ||||
575 | virtual void input_values_do(ValueVisitor* f) = 0; | |||
576 | virtual void state_values_do(ValueVisitor* f); | |||
577 | virtual void other_values_do(ValueVisitor* f) { /* usually no other - override on demand */ } | |||
578 | void values_do(ValueVisitor* f) { input_values_do(f); state_values_do(f); other_values_do(f); } | |||
579 | ||||
580 | virtual ciType* exact_type() const; | |||
581 | virtual ciType* declared_type() const { return NULL__null; } | |||
582 | ||||
583 | // hashing | |||
584 | virtual const char* name() const = 0; | |||
585 | HASHING1(Instruction, false, id())virtual intx hash() const { return (false) ? ((((intx)(name() )) << 7) ^ ((intx)(id()))) : 0; } virtual bool is_equal (Value v) const { if (!(false) ) return false; Instruction* _v = v->as_Instruction(); if (_v == __null ) return false; if (id() != _v->id()) return false; return true; } // hashing disabled by default | |||
586 | ||||
587 | // debugging | |||
588 | static void check_state(ValueStack* state) PRODUCT_RETURN; | |||
589 | void print() PRODUCT_RETURN; | |||
590 | void print_line() PRODUCT_RETURN; | |||
591 | void print(InstructionPrinter& ip) PRODUCT_RETURN; | |||
592 | }; | |||
593 | ||||
594 | ||||
595 | // The following macros are used to define base (i.e., non-leaf) | |||
596 | // and leaf instruction classes. They define class-name related | |||
597 | // generic functionality in one place. | |||
598 | ||||
599 | #define BASE(class_name, super_class_name)class class_name: public super_class_name { public: virtual class_name * as_class_name() { return this; } \ | |||
600 | class class_name: public super_class_name { \ | |||
601 | public: \ | |||
602 | virtual class_name* as_##class_name() { return this; } \ | |||
603 | ||||
604 | ||||
605 | #define LEAF(class_name, super_class_name)class class_name: public super_class_name { public: virtual class_name * as_class_name() { return this; } public: virtual const char * name() const { return "class_name"; } virtual void visit(InstructionVisitor * v) { v->do_class_name(this); } \ | |||
606 | BASE(class_name, super_class_name)class class_name: public super_class_name { public: virtual class_name * as_class_name() { return this; } \ | |||
607 | public: \ | |||
608 | virtual const char* name() const { return #class_name; } \ | |||
609 | virtual void visit(InstructionVisitor* v) { v->do_##class_name(this); } \ | |||
610 | ||||
611 | ||||
612 | // Debugging support | |||
613 | ||||
614 | ||||
615 | #ifdef ASSERT1 | |||
616 | class AssertValues: public ValueVisitor { | |||
617 | void visit(Value* x) { assert((*x) != NULL, "value must exist")do { if (!((*x) != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 617, "assert(" "(*x) != __null" ") failed", "value must exist" ); ::breakpoint(); } } while (0); } | |||
618 | }; | |||
619 | #define ASSERT_VALUES { AssertValues assert_value; values_do(&assert_value); } | |||
620 | #else | |||
621 | #define ASSERT_VALUES | |||
622 | #endif // ASSERT | |||
623 | ||||
624 | ||||
625 | // A Phi is a phi function in the sense of SSA form. It stands for | |||
626 | // the value of a local variable at the beginning of a join block. | |||
627 | // A Phi consists of n operands, one for every incoming branch. | |||
628 | ||||
629 | LEAF(Phi, Instruction)class Phi: public Instruction { public: virtual Phi* as_Phi() { return this; } public: virtual const char* name() const { return "Phi"; } virtual void visit(InstructionVisitor* v) { v->do_Phi (this); } | |||
630 | private: | |||
631 | int _pf_flags; // the flags of the phi function | |||
632 | int _index; // to value on operand stack (index < 0) or to local | |||
633 | public: | |||
634 | // creation | |||
635 | Phi(ValueType* type, BlockBegin* b, int index) | |||
636 | : Instruction(type->base()) | |||
637 | , _pf_flags(0) | |||
638 | , _index(index) | |||
639 | { | |||
640 | _block = b; | |||
641 | NOT_PRODUCT(set_printable_bci(Value(b)->printable_bci()))set_printable_bci(Value(b)->printable_bci()); | |||
642 | if (type->is_illegal()) { | |||
643 | make_illegal(); | |||
644 | } | |||
645 | } | |||
646 | ||||
647 | // flags | |||
648 | enum Flag { | |||
649 | no_flag = 0, | |||
650 | visited = 1 << 0, | |||
651 | cannot_simplify = 1 << 1 | |||
652 | }; | |||
653 | ||||
654 | // accessors | |||
655 | bool is_local() const { return _index >= 0; } | |||
656 | bool is_on_stack() const { return !is_local(); } | |||
657 | int local_index() const { assert(is_local(), "")do { if (!(is_local())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 657, "assert(" "is_local()" ") failed", ""); ::breakpoint() ; } } while (0); return _index; } | |||
658 | int stack_index() const { assert(is_on_stack(), "")do { if (!(is_on_stack())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 658, "assert(" "is_on_stack()" ") failed", ""); ::breakpoint (); } } while (0); return -(_index+1); } | |||
659 | ||||
660 | Value operand_at(int i) const; | |||
661 | int operand_count() const; | |||
662 | ||||
663 | void set(Flag f) { _pf_flags |= f; } | |||
664 | void clear(Flag f) { _pf_flags &= ~f; } | |||
665 | bool is_set(Flag f) const { return (_pf_flags & f) != 0; } | |||
666 | ||||
667 | // Invalidates phis corresponding to merges of locals of two different types | |||
668 | // (these should never be referenced, otherwise the bytecodes are illegal) | |||
669 | void make_illegal() { | |||
670 | set(cannot_simplify); | |||
671 | set_type(illegalType); | |||
672 | } | |||
673 | ||||
674 | bool is_illegal() const { | |||
675 | return type()->is_illegal(); | |||
676 | } | |||
677 | ||||
678 | // generic | |||
679 | virtual void input_values_do(ValueVisitor* f) { | |||
680 | } | |||
681 | }; | |||
682 | ||||
683 | ||||
684 | // A local is a placeholder for an incoming argument to a function call. | |||
685 | LEAF(Local, Instruction)class Local: public Instruction { public: virtual Local* as_Local () { return this; } public: virtual const char* name() const { return "Local"; } virtual void visit(InstructionVisitor* v) { v->do_Local(this); } | |||
686 | private: | |||
687 | int _java_index; // the local index within the method to which the local belongs | |||
688 | bool _is_receiver; // if local variable holds the receiver: "this" for non-static methods | |||
689 | ciType* _declared_type; | |||
690 | public: | |||
691 | // creation | |||
692 | Local(ciType* declared, ValueType* type, int index, bool receiver) | |||
693 | : Instruction(type) | |||
694 | , _java_index(index) | |||
695 | , _is_receiver(receiver) | |||
696 | , _declared_type(declared) | |||
697 | { | |||
698 | NOT_PRODUCT(set_printable_bci(-1))set_printable_bci(-1); | |||
699 | } | |||
700 | ||||
701 | // accessors | |||
702 | int java_index() const { return _java_index; } | |||
703 | bool is_receiver() const { return _is_receiver; } | |||
704 | ||||
705 | virtual ciType* declared_type() const { return _declared_type; } | |||
706 | ||||
707 | // generic | |||
708 | virtual void input_values_do(ValueVisitor* f) { /* no values */ } | |||
709 | }; | |||
710 | ||||
711 | ||||
712 | LEAF(Constant, Instruction)class Constant: public Instruction { public: virtual Constant * as_Constant() { return this; } public: virtual const char* name () const { return "Constant"; } virtual void visit(InstructionVisitor * v) { v->do_Constant(this); } | |||
713 | public: | |||
714 | // creation | |||
715 | Constant(ValueType* type): | |||
716 | Instruction(type, NULL__null, /*type_is_constant*/ true) | |||
717 | { | |||
718 | assert(type->is_constant(), "must be a constant")do { if (!(type->is_constant())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 718, "assert(" "type->is_constant()" ") failed", "must be a constant" ); ::breakpoint(); } } while (0); | |||
719 | } | |||
720 | ||||
721 | Constant(ValueType* type, ValueStack* state_before): | |||
722 | Instruction(type, state_before, /*type_is_constant*/ true) | |||
723 | { | |||
724 | assert(state_before != NULL, "only used for constants which need patching")do { if (!(state_before != __null)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 724, "assert(" "state_before != __null" ") failed", "only used for constants which need patching" ); ::breakpoint(); } } while (0); | |||
725 | assert(type->is_constant(), "must be a constant")do { if (!(type->is_constant())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 725, "assert(" "type->is_constant()" ") failed", "must be a constant" ); ::breakpoint(); } } while (0); | |||
726 | // since it's patching it needs to be pinned | |||
727 | pin(); | |||
728 | } | |||
729 | ||||
730 | // generic | |||
731 | virtual bool can_trap() const { return state_before() != NULL__null; } | |||
732 | virtual void input_values_do(ValueVisitor* f) { /* no values */ } | |||
733 | ||||
734 | virtual intx hash() const; | |||
735 | virtual bool is_equal(Value v) const; | |||
736 | ||||
737 | virtual ciType* exact_type() const; | |||
738 | ||||
739 | enum CompareResult { not_comparable = -1, cond_false, cond_true }; | |||
740 | ||||
741 | virtual CompareResult compare(Instruction::Condition condition, Value right) const; | |||
742 | BlockBegin* compare(Instruction::Condition cond, Value right, | |||
743 | BlockBegin* true_sux, BlockBegin* false_sux) const { | |||
744 | switch (compare(cond, right)) { | |||
745 | case not_comparable: | |||
746 | return NULL__null; | |||
747 | case cond_false: | |||
748 | return false_sux; | |||
749 | case cond_true: | |||
750 | return true_sux; | |||
751 | default: | |||
752 | ShouldNotReachHere()do { (*g_assert_poison) = 'X';; report_should_not_reach_here( "/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 752); ::breakpoint(); } while (0); | |||
753 | return NULL__null; | |||
754 | } | |||
755 | } | |||
756 | }; | |||
757 | ||||
758 | ||||
759 | BASE(AccessField, Instruction)class AccessField: public Instruction { public: virtual AccessField * as_AccessField() { return this; } | |||
760 | private: | |||
761 | Value _obj; | |||
762 | int _offset; | |||
763 | ciField* _field; | |||
764 | NullCheck* _explicit_null_check; // For explicit null check elimination | |||
765 | ||||
766 | public: | |||
767 | // creation | |||
768 | AccessField(Value obj, int offset, ciField* field, bool is_static, | |||
769 | ValueStack* state_before, bool needs_patching) | |||
770 | : Instruction(as_ValueType(field->type()->basic_type()), state_before) | |||
771 | , _obj(obj) | |||
772 | , _offset(offset) | |||
773 | , _field(field) | |||
774 | , _explicit_null_check(NULL__null) | |||
775 | { | |||
776 | set_needs_null_check(!is_static); | |||
777 | set_flag(IsStaticFlag, is_static); | |||
778 | set_flag(NeedsPatchingFlag, needs_patching); | |||
779 | ASSERT_VALUES | |||
780 | // pin of all instructions with memory access | |||
781 | pin(); | |||
782 | } | |||
783 | ||||
784 | // accessors | |||
785 | Value obj() const { return _obj; } | |||
786 | int offset() const { return _offset; } | |||
787 | ciField* field() const { return _field; } | |||
788 | BasicType field_type() const { return _field->type()->basic_type(); } | |||
789 | bool is_static() const { return check_flag(IsStaticFlag); } | |||
790 | NullCheck* explicit_null_check() const { return _explicit_null_check; } | |||
791 | bool needs_patching() const { return check_flag(NeedsPatchingFlag); } | |||
792 | ||||
793 | // Unresolved getstatic and putstatic can cause initialization. | |||
794 | // Technically it occurs at the Constant that materializes the base | |||
795 | // of the static fields but it's simpler to model it here. | |||
796 | bool is_init_point() const { return is_static() && (needs_patching() || !_field->holder()->is_initialized()); } | |||
797 | ||||
798 | // manipulation | |||
799 | ||||
800 | // Under certain circumstances, if a previous NullCheck instruction | |||
801 | // proved the target object non-null, we can eliminate the explicit | |||
802 | // null check and do an implicit one, simply specifying the debug | |||
803 | // information from the NullCheck. This field should only be consulted | |||
804 | // if needs_null_check() is true. | |||
805 | void set_explicit_null_check(NullCheck* check) { _explicit_null_check = check; } | |||
806 | ||||
807 | // generic | |||
808 | virtual bool can_trap() const { return needs_null_check() || needs_patching(); } | |||
809 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_obj); } | |||
810 | }; | |||
811 | ||||
812 | ||||
813 | LEAF(LoadField, AccessField)class LoadField: public AccessField { public: virtual LoadField * as_LoadField() { return this; } public: virtual const char* name() const { return "LoadField"; } virtual void visit(InstructionVisitor * v) { v->do_LoadField(this); } | |||
814 | public: | |||
815 | // creation | |||
816 | LoadField(Value obj, int offset, ciField* field, bool is_static, | |||
817 | ValueStack* state_before, bool needs_patching) | |||
818 | : AccessField(obj, offset, field, is_static, state_before, needs_patching) | |||
819 | {} | |||
820 | ||||
821 | ciType* declared_type() const; | |||
822 | ||||
823 | // generic; cannot be eliminated if needs patching or if volatile. | |||
824 | HASHING3(LoadField, !needs_patching() && !field()->is_volatile(), obj()->subst(), offset(), declared_type())virtual intx hash() const { return (!needs_patching() && !field()->is_volatile()) ? ((((((((intx)(name())) << 7) ^ ((intx)(obj()->subst()))) << 7) ^ ((intx)(offset ()))) << 7) ^ ((intx)(declared_type()))) : 0; } virtual bool is_equal(Value v) const { if (!(!needs_patching() && !field()->is_volatile()) ) return false; LoadField* _v = v ->as_LoadField(); if (_v == __null ) return false; if (obj ()->subst() != _v->obj()->subst()) return false; if ( offset() != _v->offset()) return false; if (declared_type( ) != _v->declared_type()) return false; return true; } | |||
825 | }; | |||
826 | ||||
827 | ||||
828 | LEAF(StoreField, AccessField)class StoreField: public AccessField { public: virtual StoreField * as_StoreField() { return this; } public: virtual const char * name() const { return "StoreField"; } virtual void visit(InstructionVisitor * v) { v->do_StoreField(this); } | |||
829 | private: | |||
830 | Value _value; | |||
831 | ||||
832 | public: | |||
833 | // creation | |||
834 | StoreField(Value obj, int offset, ciField* field, Value value, bool is_static, | |||
835 | ValueStack* state_before, bool needs_patching) | |||
836 | : AccessField(obj, offset, field, is_static, state_before, needs_patching) | |||
837 | , _value(value) | |||
838 | { | |||
839 | set_flag(NeedsWriteBarrierFlag, as_ValueType(field_type())->is_object()); | |||
840 | ASSERT_VALUES | |||
841 | pin(); | |||
842 | } | |||
843 | ||||
844 | // accessors | |||
845 | Value value() const { return _value; } | |||
846 | bool needs_write_barrier() const { return check_flag(NeedsWriteBarrierFlag); } | |||
847 | ||||
848 | // generic | |||
849 | virtual void input_values_do(ValueVisitor* f) { AccessField::input_values_do(f); f->visit(&_value); } | |||
850 | }; | |||
851 | ||||
852 | ||||
853 | BASE(AccessArray, Instruction)class AccessArray: public Instruction { public: virtual AccessArray * as_AccessArray() { return this; } | |||
854 | private: | |||
855 | Value _array; | |||
856 | ||||
857 | public: | |||
858 | // creation | |||
859 | AccessArray(ValueType* type, Value array, ValueStack* state_before) | |||
860 | : Instruction(type, state_before) | |||
861 | , _array(array) | |||
862 | { | |||
863 | set_needs_null_check(true); | |||
864 | ASSERT_VALUES | |||
865 | pin(); // instruction with side effect (null exception or range check throwing) | |||
866 | } | |||
867 | ||||
868 | Value array() const { return _array; } | |||
869 | ||||
870 | // generic | |||
871 | virtual bool can_trap() const { return needs_null_check(); } | |||
872 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_array); } | |||
873 | }; | |||
874 | ||||
875 | ||||
876 | LEAF(ArrayLength, AccessArray)class ArrayLength: public AccessArray { public: virtual ArrayLength * as_ArrayLength() { return this; } public: virtual const char * name() const { return "ArrayLength"; } virtual void visit(InstructionVisitor * v) { v->do_ArrayLength(this); } | |||
877 | private: | |||
878 | NullCheck* _explicit_null_check; // For explicit null check elimination | |||
879 | ||||
880 | public: | |||
881 | // creation | |||
882 | ArrayLength(Value array, ValueStack* state_before) | |||
883 | : AccessArray(intType, array, state_before) | |||
884 | , _explicit_null_check(NULL__null) {} | |||
885 | ||||
886 | // accessors | |||
887 | NullCheck* explicit_null_check() const { return _explicit_null_check; } | |||
888 | ||||
889 | // setters | |||
890 | // See LoadField::set_explicit_null_check for documentation | |||
891 | void set_explicit_null_check(NullCheck* check) { _explicit_null_check = check; } | |||
892 | ||||
893 | // generic | |||
894 | HASHING1(ArrayLength, true, array()->subst())virtual intx hash() const { return (true) ? ((((intx)(name()) ) << 7) ^ ((intx)(array()->subst()))) : 0; } virtual bool is_equal(Value v) const { if (!(true) ) return false; ArrayLength * _v = v->as_ArrayLength(); if (_v == __null ) return false ; if (array()->subst() != _v->array()->subst()) return false; return true; } | |||
895 | }; | |||
896 | ||||
897 | ||||
898 | BASE(AccessIndexed, AccessArray)class AccessIndexed: public AccessArray { public: virtual AccessIndexed * as_AccessIndexed() { return this; } | |||
899 | private: | |||
900 | Value _index; | |||
901 | Value _length; | |||
902 | BasicType _elt_type; | |||
903 | bool _mismatched; | |||
904 | ||||
905 | public: | |||
906 | // creation | |||
907 | AccessIndexed(Value array, Value index, Value length, BasicType elt_type, ValueStack* state_before, bool mismatched) | |||
908 | : AccessArray(as_ValueType(elt_type), array, state_before) | |||
909 | , _index(index) | |||
910 | , _length(length) | |||
911 | , _elt_type(elt_type) | |||
912 | , _mismatched(mismatched) | |||
913 | { | |||
914 | set_flag(Instruction::NeedsRangeCheckFlag, true); | |||
915 | ASSERT_VALUES | |||
916 | } | |||
917 | ||||
918 | // accessors | |||
919 | Value index() const { return _index; } | |||
920 | Value length() const { return _length; } | |||
921 | BasicType elt_type() const { return _elt_type; } | |||
922 | bool mismatched() const { return _mismatched; } | |||
923 | ||||
924 | void clear_length() { _length = NULL__null; } | |||
925 | // perform elimination of range checks involving constants | |||
926 | bool compute_needs_range_check(); | |||
927 | ||||
928 | // generic | |||
929 | virtual void input_values_do(ValueVisitor* f) { AccessArray::input_values_do(f); f->visit(&_index); if (_length != NULL__null) f->visit(&_length); } | |||
930 | }; | |||
931 | ||||
932 | ||||
933 | LEAF(LoadIndexed, AccessIndexed)class LoadIndexed: public AccessIndexed { public: virtual LoadIndexed * as_LoadIndexed() { return this; } public: virtual const char * name() const { return "LoadIndexed"; } virtual void visit(InstructionVisitor * v) { v->do_LoadIndexed(this); } | |||
934 | private: | |||
935 | NullCheck* _explicit_null_check; // For explicit null check elimination | |||
936 | ||||
937 | public: | |||
938 | // creation | |||
939 | LoadIndexed(Value array, Value index, Value length, BasicType elt_type, ValueStack* state_before, bool mismatched = false) | |||
940 | : AccessIndexed(array, index, length, elt_type, state_before, mismatched) | |||
941 | , _explicit_null_check(NULL__null) {} | |||
942 | ||||
943 | // accessors | |||
944 | NullCheck* explicit_null_check() const { return _explicit_null_check; } | |||
945 | ||||
946 | // setters | |||
947 | // See LoadField::set_explicit_null_check for documentation | |||
948 | void set_explicit_null_check(NullCheck* check) { _explicit_null_check = check; } | |||
949 | ||||
950 | ciType* exact_type() const; | |||
951 | ciType* declared_type() const; | |||
952 | ||||
953 | // generic; | |||
954 | HASHING3(LoadIndexed, true, type()->tag(), array()->subst(), index()->subst())virtual intx hash() const { return (true) ? ((((((((intx)(name ())) << 7) ^ ((intx)(type()->tag()))) << 7) ^ ( (intx)(array()->subst()))) << 7) ^ ((intx)(index()-> subst()))) : 0; } virtual bool is_equal(Value v) const { if ( !(true) ) return false; LoadIndexed* _v = v->as_LoadIndexed (); if (_v == __null ) return false; if (type()->tag() != _v ->type()->tag()) return false; if (array()->subst() != _v->array()->subst()) return false; if (index()->subst () != _v->index()->subst()) return false; return true; } | |||
955 | }; | |||
956 | ||||
957 | ||||
958 | LEAF(StoreIndexed, AccessIndexed)class StoreIndexed: public AccessIndexed { public: virtual StoreIndexed * as_StoreIndexed() { return this; } public: virtual const char * name() const { return "StoreIndexed"; } virtual void visit( InstructionVisitor* v) { v->do_StoreIndexed(this); } | |||
959 | private: | |||
960 | Value _value; | |||
961 | ||||
962 | ciMethod* _profiled_method; | |||
963 | int _profiled_bci; | |||
964 | bool _check_boolean; | |||
965 | ||||
966 | public: | |||
967 | // creation | |||
968 | StoreIndexed(Value array, Value index, Value length, BasicType elt_type, Value value, ValueStack* state_before, | |||
969 | bool check_boolean, bool mismatched = false) | |||
970 | : AccessIndexed(array, index, length, elt_type, state_before, mismatched) | |||
971 | , _value(value), _profiled_method(NULL__null), _profiled_bci(0), _check_boolean(check_boolean) | |||
972 | { | |||
973 | set_flag(NeedsWriteBarrierFlag, (as_ValueType(elt_type)->is_object())); | |||
974 | set_flag(NeedsStoreCheckFlag, (as_ValueType(elt_type)->is_object())); | |||
975 | ASSERT_VALUES | |||
976 | pin(); | |||
977 | } | |||
978 | ||||
979 | // accessors | |||
980 | Value value() const { return _value; } | |||
981 | bool needs_write_barrier() const { return check_flag(NeedsWriteBarrierFlag); } | |||
982 | bool needs_store_check() const { return check_flag(NeedsStoreCheckFlag); } | |||
983 | bool check_boolean() const { return _check_boolean; } | |||
984 | // Helpers for MethodData* profiling | |||
985 | void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } | |||
986 | void set_profiled_method(ciMethod* method) { _profiled_method = method; } | |||
987 | void set_profiled_bci(int bci) { _profiled_bci = bci; } | |||
988 | bool should_profile() const { return check_flag(ProfileMDOFlag); } | |||
989 | ciMethod* profiled_method() const { return _profiled_method; } | |||
990 | int profiled_bci() const { return _profiled_bci; } | |||
991 | // generic | |||
992 | virtual void input_values_do(ValueVisitor* f) { AccessIndexed::input_values_do(f); f->visit(&_value); } | |||
993 | }; | |||
994 | ||||
995 | ||||
996 | LEAF(NegateOp, Instruction)class NegateOp: public Instruction { public: virtual NegateOp * as_NegateOp() { return this; } public: virtual const char* name () const { return "NegateOp"; } virtual void visit(InstructionVisitor * v) { v->do_NegateOp(this); } | |||
997 | private: | |||
998 | Value _x; | |||
999 | ||||
1000 | public: | |||
1001 | // creation | |||
1002 | NegateOp(Value x) : Instruction(x->type()->base()), _x(x) { | |||
1003 | ASSERT_VALUES | |||
1004 | } | |||
1005 | ||||
1006 | // accessors | |||
1007 | Value x() const { return _x; } | |||
1008 | ||||
1009 | // generic | |||
1010 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_x); } | |||
1011 | }; | |||
1012 | ||||
1013 | ||||
1014 | BASE(Op2, Instruction)class Op2: public Instruction { public: virtual Op2* as_Op2() { return this; } | |||
1015 | private: | |||
1016 | Bytecodes::Code _op; | |||
1017 | Value _x; | |||
1018 | Value _y; | |||
1019 | ||||
1020 | public: | |||
1021 | // creation | |||
1022 | Op2(ValueType* type, Bytecodes::Code op, Value x, Value y, ValueStack* state_before = NULL__null) | |||
1023 | : Instruction(type, state_before) | |||
1024 | , _op(op) | |||
1025 | , _x(x) | |||
1026 | , _y(y) | |||
1027 | { | |||
1028 | ASSERT_VALUES | |||
1029 | } | |||
1030 | ||||
1031 | // accessors | |||
1032 | Bytecodes::Code op() const { return _op; } | |||
1033 | Value x() const { return _x; } | |||
1034 | Value y() const { return _y; } | |||
1035 | ||||
1036 | // manipulators | |||
1037 | void swap_operands() { | |||
1038 | assert(is_commutative(), "operation must be commutative")do { if (!(is_commutative())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1038, "assert(" "is_commutative()" ") failed", "operation must be commutative" ); ::breakpoint(); } } while (0); | |||
1039 | Value t = _x; _x = _y; _y = t; | |||
1040 | } | |||
1041 | ||||
1042 | // generic | |||
1043 | virtual bool is_commutative() const { return false; } | |||
1044 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_x); f->visit(&_y); } | |||
1045 | }; | |||
1046 | ||||
1047 | ||||
1048 | LEAF(ArithmeticOp, Op2)class ArithmeticOp: public Op2 { public: virtual ArithmeticOp * as_ArithmeticOp() { return this; } public: virtual const char * name() const { return "ArithmeticOp"; } virtual void visit( InstructionVisitor* v) { v->do_ArithmeticOp(this); } | |||
1049 | public: | |||
1050 | // creation | |||
1051 | ArithmeticOp(Bytecodes::Code op, Value x, Value y, ValueStack* state_before) | |||
1052 | : Op2(x->type()->meet(y->type()), op, x, y, state_before) | |||
1053 | { | |||
1054 | if (can_trap()) pin(); | |||
1055 | } | |||
1056 | ||||
1057 | // generic | |||
1058 | virtual bool is_commutative() const; | |||
1059 | virtual bool can_trap() const; | |||
1060 | HASHING3(Op2, true, op(), x()->subst(), y()->subst())virtual intx hash() const { return (true) ? ((((((((intx)(name ())) << 7) ^ ((intx)(op()))) << 7) ^ ((intx)(x()-> subst()))) << 7) ^ ((intx)(y()->subst()))) : 0; } virtual bool is_equal(Value v) const { if (!(true) ) return false; Op2 * _v = v->as_Op2(); if (_v == __null ) return false; if (op () != _v->op()) return false; if (x()->subst() != _v-> x()->subst()) return false; if (y()->subst() != _v-> y()->subst()) return false; return true; } | |||
1061 | }; | |||
1062 | ||||
1063 | ||||
1064 | LEAF(ShiftOp, Op2)class ShiftOp: public Op2 { public: virtual ShiftOp* as_ShiftOp () { return this; } public: virtual const char* name() const { return "ShiftOp"; } virtual void visit(InstructionVisitor* v ) { v->do_ShiftOp(this); } | |||
1065 | public: | |||
1066 | // creation | |||
1067 | ShiftOp(Bytecodes::Code op, Value x, Value s) : Op2(x->type()->base(), op, x, s) {} | |||
| ||||
1068 | ||||
1069 | // generic | |||
1070 | HASHING3(Op2, true, op(), x()->subst(), y()->subst())virtual intx hash() const { return (true) ? ((((((((intx)(name ())) << 7) ^ ((intx)(op()))) << 7) ^ ((intx)(x()-> subst()))) << 7) ^ ((intx)(y()->subst()))) : 0; } virtual bool is_equal(Value v) const { if (!(true) ) return false; Op2 * _v = v->as_Op2(); if (_v == __null ) return false; if (op () != _v->op()) return false; if (x()->subst() != _v-> x()->subst()) return false; if (y()->subst() != _v-> y()->subst()) return false; return true; } | |||
1071 | }; | |||
1072 | ||||
1073 | ||||
1074 | LEAF(LogicOp, Op2)class LogicOp: public Op2 { public: virtual LogicOp* as_LogicOp () { return this; } public: virtual const char* name() const { return "LogicOp"; } virtual void visit(InstructionVisitor* v ) { v->do_LogicOp(this); } | |||
1075 | public: | |||
1076 | // creation | |||
1077 | LogicOp(Bytecodes::Code op, Value x, Value y) : Op2(x->type()->meet(y->type()), op, x, y) {} | |||
1078 | ||||
1079 | // generic | |||
1080 | virtual bool is_commutative() const; | |||
1081 | HASHING3(Op2, true, op(), x()->subst(), y()->subst())virtual intx hash() const { return (true) ? ((((((((intx)(name ())) << 7) ^ ((intx)(op()))) << 7) ^ ((intx)(x()-> subst()))) << 7) ^ ((intx)(y()->subst()))) : 0; } virtual bool is_equal(Value v) const { if (!(true) ) return false; Op2 * _v = v->as_Op2(); if (_v == __null ) return false; if (op () != _v->op()) return false; if (x()->subst() != _v-> x()->subst()) return false; if (y()->subst() != _v-> y()->subst()) return false; return true; } | |||
1082 | }; | |||
1083 | ||||
1084 | ||||
1085 | LEAF(CompareOp, Op2)class CompareOp: public Op2 { public: virtual CompareOp* as_CompareOp () { return this; } public: virtual const char* name() const { return "CompareOp"; } virtual void visit(InstructionVisitor* v) { v->do_CompareOp(this); } | |||
1086 | public: | |||
1087 | // creation | |||
1088 | CompareOp(Bytecodes::Code op, Value x, Value y, ValueStack* state_before) | |||
1089 | : Op2(intType, op, x, y, state_before) | |||
1090 | {} | |||
1091 | ||||
1092 | // generic | |||
1093 | HASHING3(Op2, true, op(), x()->subst(), y()->subst())virtual intx hash() const { return (true) ? ((((((((intx)(name ())) << 7) ^ ((intx)(op()))) << 7) ^ ((intx)(x()-> subst()))) << 7) ^ ((intx)(y()->subst()))) : 0; } virtual bool is_equal(Value v) const { if (!(true) ) return false; Op2 * _v = v->as_Op2(); if (_v == __null ) return false; if (op () != _v->op()) return false; if (x()->subst() != _v-> x()->subst()) return false; if (y()->subst() != _v-> y()->subst()) return false; return true; } | |||
1094 | }; | |||
1095 | ||||
1096 | ||||
1097 | LEAF(IfOp, Op2)class IfOp: public Op2 { public: virtual IfOp* as_IfOp() { return this; } public: virtual const char* name() const { return "IfOp" ; } virtual void visit(InstructionVisitor* v) { v->do_IfOp (this); } | |||
1098 | private: | |||
1099 | Value _tval; | |||
1100 | Value _fval; | |||
1101 | ||||
1102 | public: | |||
1103 | // creation | |||
1104 | IfOp(Value x, Condition cond, Value y, Value tval, Value fval) | |||
1105 | : Op2(tval->type()->meet(fval->type()), (Bytecodes::Code)cond, x, y) | |||
1106 | , _tval(tval) | |||
1107 | , _fval(fval) | |||
1108 | { | |||
1109 | ASSERT_VALUES | |||
1110 | assert(tval->type()->tag() == fval->type()->tag(), "types must match")do { if (!(tval->type()->tag() == fval->type()->tag ())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1110, "assert(" "tval->type()->tag() == fval->type()->tag()" ") failed", "types must match"); ::breakpoint(); } } while ( 0); | |||
1111 | } | |||
1112 | ||||
1113 | // accessors | |||
1114 | virtual bool is_commutative() const; | |||
1115 | Bytecodes::Code op() const { ShouldNotCallThis()do { (*g_assert_poison) = 'X';; report_should_not_call("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1115); ::breakpoint(); } while (0); return Bytecodes::_illegal; } | |||
1116 | Condition cond() const { return (Condition)Op2::op(); } | |||
1117 | Value tval() const { return _tval; } | |||
1118 | Value fval() const { return _fval; } | |||
1119 | ||||
1120 | // generic | |||
1121 | virtual void input_values_do(ValueVisitor* f) { Op2::input_values_do(f); f->visit(&_tval); f->visit(&_fval); } | |||
1122 | }; | |||
1123 | ||||
1124 | ||||
1125 | LEAF(Convert, Instruction)class Convert: public Instruction { public: virtual Convert* as_Convert () { return this; } public: virtual const char* name() const { return "Convert"; } virtual void visit(InstructionVisitor* v ) { v->do_Convert(this); } | |||
1126 | private: | |||
1127 | Bytecodes::Code _op; | |||
1128 | Value _value; | |||
1129 | ||||
1130 | public: | |||
1131 | // creation | |||
1132 | Convert(Bytecodes::Code op, Value value, ValueType* to_type) : Instruction(to_type), _op(op), _value(value) { | |||
1133 | ASSERT_VALUES | |||
1134 | } | |||
1135 | ||||
1136 | // accessors | |||
1137 | Bytecodes::Code op() const { return _op; } | |||
1138 | Value value() const { return _value; } | |||
1139 | ||||
1140 | // generic | |||
1141 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_value); } | |||
1142 | HASHING2(Convert, true, op(), value()->subst())virtual intx hash() const { return (true) ? ((((((intx)(name( ))) << 7) ^ ((intx)(op()))) << 7) ^ ((intx)(value ()->subst()))) : 0; } virtual bool is_equal(Value v) const { if (!(true) ) return false; Convert* _v = v->as_Convert (); if (_v == __null ) return false; if (op() != _v->op()) return false; if (value()->subst() != _v->value()-> subst()) return false; return true; } | |||
1143 | }; | |||
1144 | ||||
1145 | ||||
1146 | LEAF(NullCheck, Instruction)class NullCheck: public Instruction { public: virtual NullCheck * as_NullCheck() { return this; } public: virtual const char* name() const { return "NullCheck"; } virtual void visit(InstructionVisitor * v) { v->do_NullCheck(this); } | |||
1147 | private: | |||
1148 | Value _obj; | |||
1149 | ||||
1150 | public: | |||
1151 | // creation | |||
1152 | NullCheck(Value obj, ValueStack* state_before) | |||
1153 | : Instruction(obj->type()->base(), state_before) | |||
1154 | , _obj(obj) | |||
1155 | { | |||
1156 | ASSERT_VALUES | |||
1157 | set_can_trap(true); | |||
1158 | assert(_obj->type()->is_object(), "null check must be applied to objects only")do { if (!(_obj->type()->is_object())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1158, "assert(" "_obj->type()->is_object()" ") failed" , "null check must be applied to objects only"); ::breakpoint (); } } while (0); | |||
1159 | pin(Instruction::PinExplicitNullCheck); | |||
1160 | } | |||
1161 | ||||
1162 | // accessors | |||
1163 | Value obj() const { return _obj; } | |||
1164 | ||||
1165 | // setters | |||
1166 | void set_can_trap(bool can_trap) { set_flag(CanTrapFlag, can_trap); } | |||
1167 | ||||
1168 | // generic | |||
1169 | virtual bool can_trap() const { return check_flag(CanTrapFlag); /* null-check elimination sets to false */ } | |||
1170 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_obj); } | |||
1171 | HASHING1(NullCheck, true, obj()->subst())virtual intx hash() const { return (true) ? ((((intx)(name()) ) << 7) ^ ((intx)(obj()->subst()))) : 0; } virtual bool is_equal(Value v) const { if (!(true) ) return false; NullCheck * _v = v->as_NullCheck(); if (_v == __null ) return false; if (obj()->subst() != _v->obj()->subst()) return false ; return true; } | |||
1172 | }; | |||
1173 | ||||
1174 | ||||
1175 | // This node is supposed to cast the type of another node to a more precise | |||
1176 | // declared type. | |||
1177 | LEAF(TypeCast, Instruction)class TypeCast: public Instruction { public: virtual TypeCast * as_TypeCast() { return this; } public: virtual const char* name () const { return "TypeCast"; } virtual void visit(InstructionVisitor * v) { v->do_TypeCast(this); } | |||
1178 | private: | |||
1179 | ciType* _declared_type; | |||
1180 | Value _obj; | |||
1181 | ||||
1182 | public: | |||
1183 | // The type of this node is the same type as the object type (and it might be constant). | |||
1184 | TypeCast(ciType* type, Value obj, ValueStack* state_before) | |||
1185 | : Instruction(obj->type(), state_before, obj->type()->is_constant()), | |||
1186 | _declared_type(type), | |||
1187 | _obj(obj) {} | |||
1188 | ||||
1189 | // accessors | |||
1190 | ciType* declared_type() const { return _declared_type; } | |||
1191 | Value obj() const { return _obj; } | |||
1192 | ||||
1193 | // generic | |||
1194 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_obj); } | |||
1195 | }; | |||
1196 | ||||
1197 | ||||
1198 | BASE(StateSplit, Instruction)class StateSplit: public Instruction { public: virtual StateSplit * as_StateSplit() { return this; } | |||
1199 | private: | |||
1200 | ValueStack* _state; | |||
1201 | ||||
1202 | protected: | |||
1203 | static void substitute(BlockList& list, BlockBegin* old_block, BlockBegin* new_block); | |||
1204 | ||||
1205 | public: | |||
1206 | // creation | |||
1207 | StateSplit(ValueType* type, ValueStack* state_before = NULL__null) | |||
1208 | : Instruction(type, state_before) | |||
1209 | , _state(NULL__null) | |||
1210 | { | |||
1211 | pin(PinStateSplitConstructor); | |||
1212 | } | |||
1213 | ||||
1214 | // accessors | |||
1215 | ValueStack* state() const { return _state; } | |||
1216 | IRScope* scope() const; // the state's scope | |||
1217 | ||||
1218 | // manipulation | |||
1219 | void set_state(ValueStack* state) { assert(_state == NULL, "overwriting existing state")do { if (!(_state == __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1219, "assert(" "_state == __null" ") failed", "overwriting existing state" ); ::breakpoint(); } } while (0); check_state(state); _state = state; } | |||
1220 | ||||
1221 | // generic | |||
1222 | virtual void input_values_do(ValueVisitor* f) { /* no values */ } | |||
1223 | virtual void state_values_do(ValueVisitor* f); | |||
1224 | }; | |||
1225 | ||||
1226 | ||||
1227 | LEAF(Invoke, StateSplit)class Invoke: public StateSplit { public: virtual Invoke* as_Invoke () { return this; } public: virtual const char* name() const { return "Invoke"; } virtual void visit(InstructionVisitor* v) { v->do_Invoke(this); } | |||
1228 | private: | |||
1229 | Bytecodes::Code _code; | |||
1230 | Value _recv; | |||
1231 | Values* _args; | |||
1232 | BasicTypeList* _signature; | |||
1233 | ciMethod* _target; | |||
1234 | ||||
1235 | public: | |||
1236 | // creation | |||
1237 | Invoke(Bytecodes::Code code, ValueType* result_type, Value recv, Values* args, | |||
1238 | ciMethod* target, ValueStack* state_before); | |||
1239 | ||||
1240 | // accessors | |||
1241 | Bytecodes::Code code() const { return _code; } | |||
1242 | Value receiver() const { return _recv; } | |||
1243 | bool has_receiver() const { return receiver() != NULL__null; } | |||
1244 | int number_of_arguments() const { return _args->length(); } | |||
1245 | Value argument_at(int i) const { return _args->at(i); } | |||
1246 | BasicTypeList* signature() const { return _signature; } | |||
1247 | ciMethod* target() const { return _target; } | |||
1248 | ||||
1249 | ciType* declared_type() const; | |||
1250 | ||||
1251 | // Returns false if target is not loaded | |||
1252 | bool target_is_final() const { return check_flag(TargetIsFinalFlag); } | |||
1253 | bool target_is_loaded() const { return check_flag(TargetIsLoadedFlag); } | |||
1254 | ||||
1255 | // JSR 292 support | |||
1256 | bool is_invokedynamic() const { return code() == Bytecodes::_invokedynamic; } | |||
1257 | bool is_method_handle_intrinsic() const { return target()->is_method_handle_intrinsic(); } | |||
1258 | ||||
1259 | virtual bool needs_exception_state() const { return false; } | |||
1260 | ||||
1261 | // generic | |||
1262 | virtual bool can_trap() const { return true; } | |||
1263 | virtual void input_values_do(ValueVisitor* f) { | |||
1264 | StateSplit::input_values_do(f); | |||
1265 | if (has_receiver()) f->visit(&_recv); | |||
1266 | for (int i = 0; i < _args->length(); i++) f->visit(_args->adr_at(i)); | |||
1267 | } | |||
1268 | virtual void state_values_do(ValueVisitor *f); | |||
1269 | }; | |||
1270 | ||||
1271 | ||||
1272 | LEAF(NewInstance, StateSplit)class NewInstance: public StateSplit { public: virtual NewInstance * as_NewInstance() { return this; } public: virtual const char * name() const { return "NewInstance"; } virtual void visit(InstructionVisitor * v) { v->do_NewInstance(this); } | |||
1273 | private: | |||
1274 | ciInstanceKlass* _klass; | |||
1275 | bool _is_unresolved; | |||
1276 | ||||
1277 | public: | |||
1278 | // creation | |||
1279 | NewInstance(ciInstanceKlass* klass, ValueStack* state_before, bool is_unresolved) | |||
1280 | : StateSplit(instanceType, state_before) | |||
1281 | , _klass(klass), _is_unresolved(is_unresolved) | |||
1282 | {} | |||
1283 | ||||
1284 | // accessors | |||
1285 | ciInstanceKlass* klass() const { return _klass; } | |||
1286 | bool is_unresolved() const { return _is_unresolved; } | |||
1287 | ||||
1288 | virtual bool needs_exception_state() const { return false; } | |||
1289 | ||||
1290 | // generic | |||
1291 | virtual bool can_trap() const { return true; } | |||
1292 | ciType* exact_type() const; | |||
1293 | ciType* declared_type() const; | |||
1294 | }; | |||
1295 | ||||
1296 | ||||
1297 | BASE(NewArray, StateSplit)class NewArray: public StateSplit { public: virtual NewArray* as_NewArray() { return this; } | |||
1298 | private: | |||
1299 | Value _length; | |||
1300 | ||||
1301 | public: | |||
1302 | // creation | |||
1303 | NewArray(Value length, ValueStack* state_before) | |||
1304 | : StateSplit(objectType, state_before) | |||
1305 | , _length(length) | |||
1306 | { | |||
1307 | // Do not ASSERT_VALUES since length is NULL for NewMultiArray | |||
1308 | } | |||
1309 | ||||
1310 | // accessors | |||
1311 | Value length() const { return _length; } | |||
1312 | ||||
1313 | virtual bool needs_exception_state() const { return false; } | |||
1314 | ||||
1315 | ciType* exact_type() const { return NULL__null; } | |||
1316 | ciType* declared_type() const; | |||
1317 | ||||
1318 | // generic | |||
1319 | virtual bool can_trap() const { return true; } | |||
1320 | virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_length); } | |||
1321 | }; | |||
1322 | ||||
1323 | ||||
1324 | LEAF(NewTypeArray, NewArray)class NewTypeArray: public NewArray { public: virtual NewTypeArray * as_NewTypeArray() { return this; } public: virtual const char * name() const { return "NewTypeArray"; } virtual void visit( InstructionVisitor* v) { v->do_NewTypeArray(this); } | |||
1325 | private: | |||
1326 | BasicType _elt_type; | |||
1327 | ||||
1328 | public: | |||
1329 | // creation | |||
1330 | NewTypeArray(Value length, BasicType elt_type, ValueStack* state_before) | |||
1331 | : NewArray(length, state_before) | |||
1332 | , _elt_type(elt_type) | |||
1333 | {} | |||
1334 | ||||
1335 | // accessors | |||
1336 | BasicType elt_type() const { return _elt_type; } | |||
1337 | ciType* exact_type() const; | |||
1338 | }; | |||
1339 | ||||
1340 | ||||
1341 | LEAF(NewObjectArray, NewArray)class NewObjectArray: public NewArray { public: virtual NewObjectArray * as_NewObjectArray() { return this; } public: virtual const char * name() const { return "NewObjectArray"; } virtual void visit (InstructionVisitor* v) { v->do_NewObjectArray(this); } | |||
1342 | private: | |||
1343 | ciKlass* _klass; | |||
1344 | ||||
1345 | public: | |||
1346 | // creation | |||
1347 | NewObjectArray(ciKlass* klass, Value length, ValueStack* state_before) : NewArray(length, state_before), _klass(klass) {} | |||
1348 | ||||
1349 | // accessors | |||
1350 | ciKlass* klass() const { return _klass; } | |||
1351 | ciType* exact_type() const; | |||
1352 | }; | |||
1353 | ||||
1354 | ||||
1355 | LEAF(NewMultiArray, NewArray)class NewMultiArray: public NewArray { public: virtual NewMultiArray * as_NewMultiArray() { return this; } public: virtual const char * name() const { return "NewMultiArray"; } virtual void visit (InstructionVisitor* v) { v->do_NewMultiArray(this); } | |||
1356 | private: | |||
1357 | ciKlass* _klass; | |||
1358 | Values* _dims; | |||
1359 | ||||
1360 | public: | |||
1361 | // creation | |||
1362 | NewMultiArray(ciKlass* klass, Values* dims, ValueStack* state_before) : NewArray(NULL__null, state_before), _klass(klass), _dims(dims) { | |||
1363 | ASSERT_VALUES | |||
1364 | } | |||
1365 | ||||
1366 | // accessors | |||
1367 | ciKlass* klass() const { return _klass; } | |||
1368 | Values* dims() const { return _dims; } | |||
1369 | int rank() const { return dims()->length(); } | |||
1370 | ||||
1371 | // generic | |||
1372 | virtual void input_values_do(ValueVisitor* f) { | |||
1373 | // NOTE: we do not call NewArray::input_values_do since "length" | |||
1374 | // is meaningless for a multi-dimensional array; passing the | |||
1375 | // zeroth element down to NewArray as its length is a bad idea | |||
1376 | // since there will be a copy in the "dims" array which doesn't | |||
1377 | // get updated, and the value must not be traversed twice. Was bug | |||
1378 | // - kbr 4/10/2001 | |||
1379 | StateSplit::input_values_do(f); | |||
1380 | for (int i = 0; i < _dims->length(); i++) f->visit(_dims->adr_at(i)); | |||
1381 | } | |||
1382 | }; | |||
1383 | ||||
1384 | ||||
1385 | BASE(TypeCheck, StateSplit)class TypeCheck: public StateSplit { public: virtual TypeCheck * as_TypeCheck() { return this; } | |||
1386 | private: | |||
1387 | ciKlass* _klass; | |||
1388 | Value _obj; | |||
1389 | ||||
1390 | ciMethod* _profiled_method; | |||
1391 | int _profiled_bci; | |||
1392 | ||||
1393 | public: | |||
1394 | // creation | |||
1395 | TypeCheck(ciKlass* klass, Value obj, ValueType* type, ValueStack* state_before) | |||
1396 | : StateSplit(type, state_before), _klass(klass), _obj(obj), | |||
1397 | _profiled_method(NULL__null), _profiled_bci(0) { | |||
1398 | ASSERT_VALUES | |||
1399 | set_direct_compare(false); | |||
1400 | } | |||
1401 | ||||
1402 | // accessors | |||
1403 | ciKlass* klass() const { return _klass; } | |||
1404 | Value obj() const { return _obj; } | |||
1405 | bool is_loaded() const { return klass() != NULL__null; } | |||
1406 | bool direct_compare() const { return check_flag(DirectCompareFlag); } | |||
1407 | ||||
1408 | // manipulation | |||
1409 | void set_direct_compare(bool flag) { set_flag(DirectCompareFlag, flag); } | |||
1410 | ||||
1411 | // generic | |||
1412 | virtual bool can_trap() const { return true; } | |||
1413 | virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_obj); } | |||
1414 | ||||
1415 | // Helpers for MethodData* profiling | |||
1416 | void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } | |||
1417 | void set_profiled_method(ciMethod* method) { _profiled_method = method; } | |||
1418 | void set_profiled_bci(int bci) { _profiled_bci = bci; } | |||
1419 | bool should_profile() const { return check_flag(ProfileMDOFlag); } | |||
1420 | ciMethod* profiled_method() const { return _profiled_method; } | |||
1421 | int profiled_bci() const { return _profiled_bci; } | |||
1422 | }; | |||
1423 | ||||
1424 | ||||
1425 | LEAF(CheckCast, TypeCheck)class CheckCast: public TypeCheck { public: virtual CheckCast * as_CheckCast() { return this; } public: virtual const char* name() const { return "CheckCast"; } virtual void visit(InstructionVisitor * v) { v->do_CheckCast(this); } | |||
1426 | public: | |||
1427 | // creation | |||
1428 | CheckCast(ciKlass* klass, Value obj, ValueStack* state_before) | |||
1429 | : TypeCheck(klass, obj, objectType, state_before) {} | |||
1430 | ||||
1431 | void set_incompatible_class_change_check() { | |||
1432 | set_flag(ThrowIncompatibleClassChangeErrorFlag, true); | |||
1433 | } | |||
1434 | bool is_incompatible_class_change_check() const { | |||
1435 | return check_flag(ThrowIncompatibleClassChangeErrorFlag); | |||
1436 | } | |||
1437 | void set_invokespecial_receiver_check() { | |||
1438 | set_flag(InvokeSpecialReceiverCheckFlag, true); | |||
1439 | } | |||
1440 | bool is_invokespecial_receiver_check() const { | |||
1441 | return check_flag(InvokeSpecialReceiverCheckFlag); | |||
1442 | } | |||
1443 | ||||
1444 | virtual bool needs_exception_state() const { | |||
1445 | return !is_invokespecial_receiver_check(); | |||
1446 | } | |||
1447 | ||||
1448 | ciType* declared_type() const; | |||
1449 | }; | |||
1450 | ||||
1451 | ||||
1452 | LEAF(InstanceOf, TypeCheck)class InstanceOf: public TypeCheck { public: virtual InstanceOf * as_InstanceOf() { return this; } public: virtual const char * name() const { return "InstanceOf"; } virtual void visit(InstructionVisitor * v) { v->do_InstanceOf(this); } | |||
1453 | public: | |||
1454 | // creation | |||
1455 | InstanceOf(ciKlass* klass, Value obj, ValueStack* state_before) : TypeCheck(klass, obj, intType, state_before) {} | |||
1456 | ||||
1457 | virtual bool needs_exception_state() const { return false; } | |||
1458 | }; | |||
1459 | ||||
1460 | ||||
1461 | BASE(AccessMonitor, StateSplit)class AccessMonitor: public StateSplit { public: virtual AccessMonitor * as_AccessMonitor() { return this; } | |||
1462 | private: | |||
1463 | Value _obj; | |||
1464 | int _monitor_no; | |||
1465 | ||||
1466 | public: | |||
1467 | // creation | |||
1468 | AccessMonitor(Value obj, int monitor_no, ValueStack* state_before = NULL__null) | |||
1469 | : StateSplit(illegalType, state_before) | |||
1470 | , _obj(obj) | |||
1471 | , _monitor_no(monitor_no) | |||
1472 | { | |||
1473 | set_needs_null_check(true); | |||
1474 | ASSERT_VALUES | |||
1475 | } | |||
1476 | ||||
1477 | // accessors | |||
1478 | Value obj() const { return _obj; } | |||
1479 | int monitor_no() const { return _monitor_no; } | |||
1480 | ||||
1481 | // generic | |||
1482 | virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_obj); } | |||
1483 | }; | |||
1484 | ||||
1485 | ||||
1486 | LEAF(MonitorEnter, AccessMonitor)class MonitorEnter: public AccessMonitor { public: virtual MonitorEnter * as_MonitorEnter() { return this; } public: virtual const char * name() const { return "MonitorEnter"; } virtual void visit( InstructionVisitor* v) { v->do_MonitorEnter(this); } | |||
1487 | public: | |||
1488 | // creation | |||
1489 | MonitorEnter(Value obj, int monitor_no, ValueStack* state_before) | |||
1490 | : AccessMonitor(obj, monitor_no, state_before) | |||
1491 | { | |||
1492 | ASSERT_VALUES | |||
1493 | } | |||
1494 | ||||
1495 | // generic | |||
1496 | virtual bool can_trap() const { return true; } | |||
1497 | }; | |||
1498 | ||||
1499 | ||||
1500 | LEAF(MonitorExit, AccessMonitor)class MonitorExit: public AccessMonitor { public: virtual MonitorExit * as_MonitorExit() { return this; } public: virtual const char * name() const { return "MonitorExit"; } virtual void visit(InstructionVisitor * v) { v->do_MonitorExit(this); } | |||
1501 | public: | |||
1502 | // creation | |||
1503 | MonitorExit(Value obj, int monitor_no) | |||
1504 | : AccessMonitor(obj, monitor_no, NULL__null) | |||
1505 | { | |||
1506 | ASSERT_VALUES | |||
1507 | } | |||
1508 | }; | |||
1509 | ||||
1510 | ||||
1511 | LEAF(Intrinsic, StateSplit)class Intrinsic: public StateSplit { public: virtual Intrinsic * as_Intrinsic() { return this; } public: virtual const char* name() const { return "Intrinsic"; } virtual void visit(InstructionVisitor * v) { v->do_Intrinsic(this); } | |||
1512 | private: | |||
1513 | vmIntrinsics::ID _id; | |||
1514 | Values* _args; | |||
1515 | Value _recv; | |||
1516 | ArgsNonNullState _nonnull_state; | |||
1517 | ||||
1518 | public: | |||
1519 | // preserves_state can be set to true for Intrinsics | |||
1520 | // which are guaranteed to preserve register state across any slow | |||
1521 | // cases; setting it to true does not mean that the Intrinsic can | |||
1522 | // not trap, only that if we continue execution in the same basic | |||
1523 | // block after the Intrinsic, all of the registers are intact. This | |||
1524 | // allows load elimination and common expression elimination to be | |||
1525 | // performed across the Intrinsic. The default value is false. | |||
1526 | Intrinsic(ValueType* type, | |||
1527 | vmIntrinsics::ID id, | |||
1528 | Values* args, | |||
1529 | bool has_receiver, | |||
1530 | ValueStack* state_before, | |||
1531 | bool preserves_state, | |||
1532 | bool cantrap = true) | |||
1533 | : StateSplit(type, state_before) | |||
1534 | , _id(id) | |||
1535 | , _args(args) | |||
1536 | , _recv(NULL__null) | |||
1537 | { | |||
1538 | assert(args != NULL, "args must exist")do { if (!(args != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1538, "assert(" "args != __null" ") failed", "args must exist" ); ::breakpoint(); } } while (0); | |||
1539 | ASSERT_VALUES | |||
1540 | set_flag(PreservesStateFlag, preserves_state); | |||
1541 | set_flag(CanTrapFlag, cantrap); | |||
1542 | if (has_receiver) { | |||
1543 | _recv = argument_at(0); | |||
1544 | } | |||
1545 | set_needs_null_check(has_receiver); | |||
1546 | ||||
1547 | // some intrinsics can't trap, so don't force them to be pinned | |||
1548 | if (!can_trap() && !vmIntrinsics::should_be_pinned(_id)) { | |||
1549 | unpin(PinStateSplitConstructor); | |||
1550 | } | |||
1551 | } | |||
1552 | ||||
1553 | // accessors | |||
1554 | vmIntrinsics::ID id() const { return _id; } | |||
1555 | int number_of_arguments() const { return _args->length(); } | |||
1556 | Value argument_at(int i) const { return _args->at(i); } | |||
1557 | ||||
1558 | bool has_receiver() const { return (_recv != NULL__null); } | |||
1559 | Value receiver() const { assert(has_receiver(), "must have receiver")do { if (!(has_receiver())) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1559, "assert(" "has_receiver()" ") failed", "must have receiver" ); ::breakpoint(); } } while (0); return _recv; } | |||
1560 | bool preserves_state() const { return check_flag(PreservesStateFlag); } | |||
1561 | ||||
1562 | bool arg_needs_null_check(int i) const { | |||
1563 | return _nonnull_state.arg_needs_null_check(i); | |||
1564 | } | |||
1565 | ||||
1566 | void set_arg_needs_null_check(int i, bool check) { | |||
1567 | _nonnull_state.set_arg_needs_null_check(i, check); | |||
1568 | } | |||
1569 | ||||
1570 | // generic | |||
1571 | virtual bool can_trap() const { return check_flag(CanTrapFlag); } | |||
1572 | virtual void input_values_do(ValueVisitor* f) { | |||
1573 | StateSplit::input_values_do(f); | |||
1574 | for (int i = 0; i < _args->length(); i++) f->visit(_args->adr_at(i)); | |||
1575 | } | |||
1576 | }; | |||
1577 | ||||
1578 | ||||
1579 | class LIR_List; | |||
1580 | ||||
1581 | LEAF(BlockBegin, StateSplit)class BlockBegin: public StateSplit { public: virtual BlockBegin * as_BlockBegin() { return this; } public: virtual const char * name() const { return "BlockBegin"; } virtual void visit(InstructionVisitor * v) { v->do_BlockBegin(this); } | |||
1582 | private: | |||
1583 | int _block_id; // the unique block id | |||
1584 | int _bci; // start-bci of block | |||
1585 | int _depth_first_number; // number of this block in a depth-first ordering | |||
1586 | int _linear_scan_number; // number of this block in linear-scan ordering | |||
1587 | int _dominator_depth; | |||
1588 | int _loop_depth; // the loop nesting level of this block | |||
1589 | int _loop_index; // number of the innermost loop of this block | |||
1590 | int _flags; // the flags associated with this block | |||
1591 | ||||
1592 | // fields used by BlockListBuilder | |||
1593 | int _total_preds; // number of predecessors found by BlockListBuilder | |||
1594 | ResourceBitMap _stores_to_locals; // bit is set when a local variable is stored in the block | |||
1595 | ||||
1596 | // SSA specific fields: (factor out later) | |||
1597 | BlockList _predecessors; // the predecessors of this block | |||
1598 | BlockList _dominates; // list of blocks that are dominated by this block | |||
1599 | BlockBegin* _dominator; // the dominator of this block | |||
1600 | // SSA specific ends | |||
1601 | BlockEnd* _end; // the last instruction of this block | |||
1602 | BlockList _exception_handlers; // the exception handlers potentially invoked by this block | |||
1603 | ValueStackStack* _exception_states; // only for xhandler entries: states of all instructions that have an edge to this xhandler | |||
1604 | int _exception_handler_pco; // if this block is the start of an exception handler, | |||
1605 | // this records the PC offset in the assembly code of the | |||
1606 | // first instruction in this block | |||
1607 | Label _label; // the label associated with this block | |||
1608 | LIR_List* _lir; // the low level intermediate representation for this block | |||
1609 | ||||
1610 | ResourceBitMap _live_in; // set of live LIR_Opr registers at entry to this block | |||
1611 | ResourceBitMap _live_out; // set of live LIR_Opr registers at exit from this block | |||
1612 | ResourceBitMap _live_gen; // set of registers used before any redefinition in this block | |||
1613 | ResourceBitMap _live_kill; // set of registers defined in this block | |||
1614 | ||||
1615 | ResourceBitMap _fpu_register_usage; | |||
1616 | intArray* _fpu_stack_state; // For x86 FPU code generation with UseLinearScan | |||
1617 | int _first_lir_instruction_id; // ID of first LIR instruction in this block | |||
1618 | int _last_lir_instruction_id; // ID of last LIR instruction in this block | |||
1619 | ||||
1620 | void iterate_preorder (boolArray& mark, BlockClosure* closure); | |||
1621 | void iterate_postorder(boolArray& mark, BlockClosure* closure); | |||
1622 | ||||
1623 | friend class SuxAndWeightAdjuster; | |||
1624 | ||||
1625 | public: | |||
1626 | void* operator new(size_t size) throw() { | |||
1627 | Compilation* c = Compilation::current(); | |||
1628 | void* res = c->arena()->Amalloc(size); | |||
1629 | return res; | |||
1630 | } | |||
1631 | ||||
1632 | // initialization/counting | |||
1633 | static int number_of_blocks() { | |||
1634 | return Compilation::current()->number_of_blocks(); | |||
1635 | } | |||
1636 | ||||
1637 | // creation | |||
1638 | BlockBegin(int bci) | |||
1639 | : StateSplit(illegalType) | |||
1640 | , _block_id(Compilation::current()->get_next_block_id()) | |||
1641 | , _bci(bci) | |||
1642 | , _depth_first_number(-1) | |||
1643 | , _linear_scan_number(-1) | |||
1644 | , _dominator_depth(-1) | |||
1645 | , _loop_depth(0) | |||
1646 | , _loop_index(-1) | |||
1647 | , _flags(0) | |||
1648 | , _total_preds(0) | |||
1649 | , _stores_to_locals() | |||
1650 | , _predecessors(2) | |||
1651 | , _dominates(2) | |||
1652 | , _dominator(NULL__null) | |||
1653 | , _end(NULL__null) | |||
1654 | , _exception_handlers(1) | |||
1655 | , _exception_states(NULL__null) | |||
1656 | , _exception_handler_pco(-1) | |||
1657 | , _lir(NULL__null) | |||
1658 | , _live_in() | |||
1659 | , _live_out() | |||
1660 | , _live_gen() | |||
1661 | , _live_kill() | |||
1662 | , _fpu_register_usage() | |||
1663 | , _fpu_stack_state(NULL__null) | |||
1664 | , _first_lir_instruction_id(-1) | |||
1665 | , _last_lir_instruction_id(-1) | |||
1666 | { | |||
1667 | _block = this; | |||
1668 | #ifndef PRODUCT | |||
1669 | set_printable_bci(bci); | |||
1670 | #endif | |||
1671 | } | |||
1672 | ||||
1673 | // accessors | |||
1674 | int block_id() const { return _block_id; } | |||
1675 | int bci() const { return _bci; } | |||
1676 | BlockList* dominates() { return &_dominates; } | |||
1677 | BlockBegin* dominator() const { return _dominator; } | |||
1678 | int loop_depth() const { return _loop_depth; } | |||
1679 | int dominator_depth() const { return _dominator_depth; } | |||
1680 | int depth_first_number() const { return _depth_first_number; } | |||
1681 | int linear_scan_number() const { return _linear_scan_number; } | |||
1682 | BlockEnd* end() const { return _end; } | |||
1683 | Label* label() { return &_label; } | |||
1684 | LIR_List* lir() const { return _lir; } | |||
1685 | int exception_handler_pco() const { return _exception_handler_pco; } | |||
1686 | ResourceBitMap& live_in() { return _live_in; } | |||
1687 | ResourceBitMap& live_out() { return _live_out; } | |||
1688 | ResourceBitMap& live_gen() { return _live_gen; } | |||
1689 | ResourceBitMap& live_kill() { return _live_kill; } | |||
1690 | ResourceBitMap& fpu_register_usage() { return _fpu_register_usage; } | |||
1691 | intArray* fpu_stack_state() const { return _fpu_stack_state; } | |||
1692 | int first_lir_instruction_id() const { return _first_lir_instruction_id; } | |||
1693 | int last_lir_instruction_id() const { return _last_lir_instruction_id; } | |||
1694 | int total_preds() const { return _total_preds; } | |||
1695 | BitMap& stores_to_locals() { return _stores_to_locals; } | |||
1696 | ||||
1697 | // manipulation | |||
1698 | void set_dominator(BlockBegin* dom) { _dominator = dom; } | |||
1699 | void set_loop_depth(int d) { _loop_depth = d; } | |||
1700 | void set_dominator_depth(int d) { _dominator_depth = d; } | |||
1701 | void set_depth_first_number(int dfn) { _depth_first_number = dfn; } | |||
1702 | void set_linear_scan_number(int lsn) { _linear_scan_number = lsn; } | |||
1703 | void set_end(BlockEnd* new_end); | |||
1704 | static void disconnect_edge(BlockBegin* from, BlockBegin* to); | |||
1705 | BlockBegin* insert_block_between(BlockBegin* sux); | |||
1706 | void substitute_sux(BlockBegin* old_sux, BlockBegin* new_sux); | |||
1707 | void set_lir(LIR_List* lir) { _lir = lir; } | |||
1708 | void set_exception_handler_pco(int pco) { _exception_handler_pco = pco; } | |||
1709 | void set_live_in (const ResourceBitMap& map) { _live_in = map; } | |||
1710 | void set_live_out (const ResourceBitMap& map) { _live_out = map; } | |||
1711 | void set_live_gen (const ResourceBitMap& map) { _live_gen = map; } | |||
1712 | void set_live_kill(const ResourceBitMap& map) { _live_kill = map; } | |||
1713 | void set_fpu_register_usage(const ResourceBitMap& map) { _fpu_register_usage = map; } | |||
1714 | void set_fpu_stack_state(intArray* state) { _fpu_stack_state = state; } | |||
1715 | void set_first_lir_instruction_id(int id) { _first_lir_instruction_id = id; } | |||
1716 | void set_last_lir_instruction_id(int id) { _last_lir_instruction_id = id; } | |||
1717 | void increment_total_preds(int n = 1) { _total_preds += n; } | |||
1718 | void init_stores_to_locals(int locals_count) { _stores_to_locals.initialize(locals_count); } | |||
1719 | ||||
1720 | // generic | |||
1721 | virtual void state_values_do(ValueVisitor* f); | |||
1722 | ||||
1723 | // successors and predecessors | |||
1724 | int number_of_sux() const; | |||
1725 | BlockBegin* sux_at(int i) const; | |||
1726 | void add_predecessor(BlockBegin* pred); | |||
1727 | void remove_predecessor(BlockBegin* pred); | |||
1728 | bool is_predecessor(BlockBegin* pred) const { return _predecessors.contains(pred); } | |||
1729 | int number_of_preds() const { return _predecessors.length(); } | |||
1730 | BlockBegin* pred_at(int i) const { return _predecessors.at(i); } | |||
1731 | ||||
1732 | // exception handlers potentially invoked by this block | |||
1733 | void add_exception_handler(BlockBegin* b); | |||
1734 | bool is_exception_handler(BlockBegin* b) const { return _exception_handlers.contains(b); } | |||
1735 | int number_of_exception_handlers() const { return _exception_handlers.length(); } | |||
1736 | BlockBegin* exception_handler_at(int i) const { return _exception_handlers.at(i); } | |||
1737 | ||||
1738 | // states of the instructions that have an edge to this exception handler | |||
1739 | int number_of_exception_states() { assert(is_set(exception_entry_flag), "only for xhandlers")do { if (!(is_set(exception_entry_flag))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1739, "assert(" "is_set(exception_entry_flag)" ") failed", "only for xhandlers" ); ::breakpoint(); } } while (0); return _exception_states == NULL__null ? 0 : _exception_states->length(); } | |||
1740 | ValueStack* exception_state_at(int idx) const { assert(is_set(exception_entry_flag), "only for xhandlers")do { if (!(is_set(exception_entry_flag))) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1740, "assert(" "is_set(exception_entry_flag)" ") failed", "only for xhandlers" ); ::breakpoint(); } } while (0); return _exception_states->at(idx); } | |||
1741 | int add_exception_state(ValueStack* state); | |||
1742 | ||||
1743 | // flags | |||
1744 | enum Flag { | |||
1745 | no_flag = 0, | |||
1746 | std_entry_flag = 1 << 0, | |||
1747 | osr_entry_flag = 1 << 1, | |||
1748 | exception_entry_flag = 1 << 2, | |||
1749 | subroutine_entry_flag = 1 << 3, | |||
1750 | backward_branch_target_flag = 1 << 4, | |||
1751 | is_on_work_list_flag = 1 << 5, | |||
1752 | was_visited_flag = 1 << 6, | |||
1753 | parser_loop_header_flag = 1 << 7, // set by parser to identify blocks where phi functions can not be created on demand | |||
1754 | critical_edge_split_flag = 1 << 8, // set for all blocks that are introduced when critical edges are split | |||
1755 | linear_scan_loop_header_flag = 1 << 9, // set during loop-detection for LinearScan | |||
1756 | linear_scan_loop_end_flag = 1 << 10, // set during loop-detection for LinearScan | |||
1757 | donot_eliminate_range_checks = 1 << 11 // Should be try to eliminate range checks in this block | |||
1758 | }; | |||
1759 | ||||
1760 | void set(Flag f) { _flags |= f; } | |||
1761 | void clear(Flag f) { _flags &= ~f; } | |||
1762 | bool is_set(Flag f) const { return (_flags & f) != 0; } | |||
1763 | bool is_entry_block() const { | |||
1764 | const int entry_mask = std_entry_flag | osr_entry_flag | exception_entry_flag; | |||
1765 | return (_flags & entry_mask) != 0; | |||
1766 | } | |||
1767 | ||||
1768 | // iteration | |||
1769 | void iterate_preorder (BlockClosure* closure); | |||
1770 | void iterate_postorder (BlockClosure* closure); | |||
1771 | ||||
1772 | void block_values_do(ValueVisitor* f); | |||
1773 | ||||
1774 | // loops | |||
1775 | void set_loop_index(int ix) { _loop_index = ix; } | |||
1776 | int loop_index() const { return _loop_index; } | |||
1777 | ||||
1778 | // merging | |||
1779 | bool try_merge(ValueStack* state); // try to merge states at block begin | |||
1780 | void merge(ValueStack* state) { bool b = try_merge(state); assert(b, "merge failed")do { if (!(b)) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1780, "assert(" "b" ") failed", "merge failed"); ::breakpoint (); } } while (0); } | |||
1781 | ||||
1782 | // debugging | |||
1783 | void print_block() PRODUCT_RETURN; | |||
1784 | void print_block(InstructionPrinter& ip, bool live_only = false) PRODUCT_RETURN; | |||
1785 | ||||
1786 | }; | |||
1787 | ||||
1788 | ||||
1789 | BASE(BlockEnd, StateSplit)class BlockEnd: public StateSplit { public: virtual BlockEnd* as_BlockEnd() { return this; } | |||
1790 | private: | |||
1791 | BlockList* _sux; | |||
1792 | ||||
1793 | protected: | |||
1794 | BlockList* sux() const { return _sux; } | |||
1795 | ||||
1796 | void set_sux(BlockList* sux) { | |||
1797 | #ifdef ASSERT1 | |||
1798 | assert(sux != NULL, "sux must exist")do { if (!(sux != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1798, "assert(" "sux != __null" ") failed", "sux must exist" ); ::breakpoint(); } } while (0); | |||
1799 | for (int i = sux->length() - 1; i >= 0; i--) assert(sux->at(i) != NULL, "sux must exist")do { if (!(sux->at(i) != __null)) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1799, "assert(" "sux->at(i) != __null" ") failed", "sux must exist" ); ::breakpoint(); } } while (0); | |||
1800 | #endif | |||
1801 | _sux = sux; | |||
1802 | } | |||
1803 | ||||
1804 | public: | |||
1805 | // creation | |||
1806 | BlockEnd(ValueType* type, ValueStack* state_before, bool is_safepoint) | |||
1807 | : StateSplit(type, state_before) | |||
1808 | , _sux(NULL__null) | |||
1809 | { | |||
1810 | set_flag(IsSafepointFlag, is_safepoint); | |||
1811 | } | |||
1812 | ||||
1813 | // accessors | |||
1814 | bool is_safepoint() const { return check_flag(IsSafepointFlag); } | |||
1815 | // For compatibility with old code, for new code use block() | |||
1816 | BlockBegin* begin() const { return _block; } | |||
1817 | ||||
1818 | // manipulation | |||
1819 | inline void remove_sux_at(int i) { _sux->remove_at(i);} | |||
1820 | inline int find_sux(BlockBegin* sux) {return _sux->find(sux);} | |||
1821 | ||||
1822 | // successors | |||
1823 | int number_of_sux() const { return _sux != NULL__null ? _sux->length() : 0; } | |||
1824 | BlockBegin* sux_at(int i) const { return _sux->at(i); } | |||
1825 | BlockBegin* default_sux() const { return sux_at(number_of_sux() - 1); } | |||
1826 | void substitute_sux(BlockBegin* old_sux, BlockBegin* new_sux); | |||
1827 | }; | |||
1828 | ||||
1829 | ||||
1830 | LEAF(Goto, BlockEnd)class Goto: public BlockEnd { public: virtual Goto* as_Goto() { return this; } public: virtual const char* name() const { return "Goto"; } virtual void visit(InstructionVisitor* v) { v-> do_Goto(this); } | |||
1831 | public: | |||
1832 | enum Direction { | |||
1833 | none, // Just a regular goto | |||
1834 | taken, not_taken // Goto produced from If | |||
1835 | }; | |||
1836 | private: | |||
1837 | ciMethod* _profiled_method; | |||
1838 | int _profiled_bci; | |||
1839 | Direction _direction; | |||
1840 | public: | |||
1841 | // creation | |||
1842 | Goto(BlockBegin* sux, ValueStack* state_before, bool is_safepoint = false) | |||
1843 | : BlockEnd(illegalType, state_before, is_safepoint) | |||
1844 | , _profiled_method(NULL__null) | |||
1845 | , _profiled_bci(0) | |||
1846 | , _direction(none) { | |||
1847 | BlockList* s = new BlockList(1); | |||
1848 | s->append(sux); | |||
1849 | set_sux(s); | |||
1850 | } | |||
1851 | ||||
1852 | Goto(BlockBegin* sux, bool is_safepoint) : BlockEnd(illegalType, NULL__null, is_safepoint) | |||
1853 | , _profiled_method(NULL__null) | |||
1854 | , _profiled_bci(0) | |||
1855 | , _direction(none) { | |||
1856 | BlockList* s = new BlockList(1); | |||
1857 | s->append(sux); | |||
1858 | set_sux(s); | |||
1859 | } | |||
1860 | ||||
1861 | bool should_profile() const { return check_flag(ProfileMDOFlag); } | |||
1862 | ciMethod* profiled_method() const { return _profiled_method; } // set only for profiled branches | |||
1863 | int profiled_bci() const { return _profiled_bci; } | |||
1864 | Direction direction() const { return _direction; } | |||
1865 | ||||
1866 | void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } | |||
1867 | void set_profiled_method(ciMethod* method) { _profiled_method = method; } | |||
1868 | void set_profiled_bci(int bci) { _profiled_bci = bci; } | |||
1869 | void set_direction(Direction d) { _direction = d; } | |||
1870 | }; | |||
1871 | ||||
1872 | #ifdef ASSERT1 | |||
1873 | LEAF(Assert, Instruction)class Assert: public Instruction { public: virtual Assert* as_Assert () { return this; } public: virtual const char* name() const { return "Assert"; } virtual void visit(InstructionVisitor* v) { v->do_Assert(this); } | |||
1874 | private: | |||
1875 | Value _x; | |||
1876 | Condition _cond; | |||
1877 | Value _y; | |||
1878 | char *_message; | |||
1879 | ||||
1880 | public: | |||
1881 | // creation | |||
1882 | // unordered_is_true is valid for float/double compares only | |||
1883 | Assert(Value x, Condition cond, bool unordered_is_true, Value y); | |||
1884 | ||||
1885 | // accessors | |||
1886 | Value x() const { return _x; } | |||
1887 | Condition cond() const { return _cond; } | |||
1888 | bool unordered_is_true() const { return check_flag(UnorderedIsTrueFlag); } | |||
1889 | Value y() const { return _y; } | |||
1890 | const char *message() const { return _message; } | |||
1891 | ||||
1892 | // generic | |||
1893 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_x); f->visit(&_y); } | |||
1894 | }; | |||
1895 | #endif | |||
1896 | ||||
1897 | LEAF(RangeCheckPredicate, StateSplit)class RangeCheckPredicate: public StateSplit { public: virtual RangeCheckPredicate* as_RangeCheckPredicate() { return this; } public: virtual const char* name() const { return "RangeCheckPredicate" ; } virtual void visit(InstructionVisitor* v) { v->do_RangeCheckPredicate (this); } | |||
1898 | private: | |||
1899 | Value _x; | |||
1900 | Condition _cond; | |||
1901 | Value _y; | |||
1902 | ||||
1903 | void check_state(); | |||
1904 | ||||
1905 | public: | |||
1906 | // creation | |||
1907 | // unordered_is_true is valid for float/double compares only | |||
1908 | RangeCheckPredicate(Value x, Condition cond, bool unordered_is_true, Value y, ValueStack* state) : StateSplit(illegalType) | |||
1909 | , _x(x) | |||
1910 | , _cond(cond) | |||
1911 | , _y(y) | |||
1912 | { | |||
1913 | ASSERT_VALUES | |||
1914 | set_flag(UnorderedIsTrueFlag, unordered_is_true); | |||
1915 | assert(x->type()->tag() == y->type()->tag(), "types must match")do { if (!(x->type()->tag() == y->type()->tag())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1915, "assert(" "x->type()->tag() == y->type()->tag()" ") failed", "types must match"); ::breakpoint(); } } while ( 0); | |||
1916 | this->set_state(state); | |||
1917 | check_state(); | |||
1918 | } | |||
1919 | ||||
1920 | // Always deoptimize | |||
1921 | RangeCheckPredicate(ValueStack* state) : StateSplit(illegalType) | |||
1922 | { | |||
1923 | this->set_state(state); | |||
1924 | _x = _y = NULL__null; | |||
1925 | check_state(); | |||
1926 | } | |||
1927 | ||||
1928 | // accessors | |||
1929 | Value x() const { return _x; } | |||
1930 | Condition cond() const { return _cond; } | |||
1931 | bool unordered_is_true() const { return check_flag(UnorderedIsTrueFlag); } | |||
1932 | Value y() const { return _y; } | |||
1933 | ||||
1934 | void always_fail() { _x = _y = NULL__null; } | |||
1935 | ||||
1936 | // generic | |||
1937 | virtual void input_values_do(ValueVisitor* f) { StateSplit::input_values_do(f); f->visit(&_x); f->visit(&_y); } | |||
1938 | HASHING3(RangeCheckPredicate, true, x()->subst(), y()->subst(), cond())virtual intx hash() const { return (true) ? ((((((((intx)(name ())) << 7) ^ ((intx)(x()->subst()))) << 7) ^ ( (intx)(y()->subst()))) << 7) ^ ((intx)(cond()))) : 0 ; } virtual bool is_equal(Value v) const { if (!(true) ) return false; RangeCheckPredicate* _v = v->as_RangeCheckPredicate (); if (_v == __null ) return false; if (x()->subst() != _v ->x()->subst()) return false; if (y()->subst() != _v ->y()->subst()) return false; if (cond() != _v->cond ()) return false; return true; } | |||
1939 | }; | |||
1940 | ||||
1941 | LEAF(If, BlockEnd)class If: public BlockEnd { public: virtual If* as_If() { return this; } public: virtual const char* name() const { return "If" ; } virtual void visit(InstructionVisitor* v) { v->do_If(this ); } | |||
1942 | private: | |||
1943 | Value _x; | |||
1944 | Condition _cond; | |||
1945 | Value _y; | |||
1946 | ciMethod* _profiled_method; | |||
1947 | int _profiled_bci; // Canonicalizer may alter bci of If node | |||
1948 | bool _swapped; // Is the order reversed with respect to the original If in the | |||
1949 | // bytecode stream? | |||
1950 | public: | |||
1951 | // creation | |||
1952 | // unordered_is_true is valid for float/double compares only | |||
1953 | If(Value x, Condition cond, bool unordered_is_true, Value y, BlockBegin* tsux, BlockBegin* fsux, ValueStack* state_before, bool is_safepoint) | |||
1954 | : BlockEnd(illegalType, state_before, is_safepoint) | |||
1955 | , _x(x) | |||
1956 | , _cond(cond) | |||
1957 | , _y(y) | |||
1958 | , _profiled_method(NULL__null) | |||
1959 | , _profiled_bci(0) | |||
1960 | , _swapped(false) | |||
1961 | { | |||
1962 | ASSERT_VALUES | |||
1963 | set_flag(UnorderedIsTrueFlag, unordered_is_true); | |||
1964 | assert(x->type()->tag() == y->type()->tag(), "types must match")do { if (!(x->type()->tag() == y->type()->tag())) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 1964, "assert(" "x->type()->tag() == y->type()->tag()" ") failed", "types must match"); ::breakpoint(); } } while ( 0); | |||
1965 | BlockList* s = new BlockList(2); | |||
1966 | s->append(tsux); | |||
1967 | s->append(fsux); | |||
1968 | set_sux(s); | |||
1969 | } | |||
1970 | ||||
1971 | // accessors | |||
1972 | Value x() const { return _x; } | |||
1973 | Condition cond() const { return _cond; } | |||
1974 | bool unordered_is_true() const { return check_flag(UnorderedIsTrueFlag); } | |||
1975 | Value y() const { return _y; } | |||
1976 | BlockBegin* sux_for(bool is_true) const { return sux_at(is_true ? 0 : 1); } | |||
1977 | BlockBegin* tsux() const { return sux_for(true); } | |||
1978 | BlockBegin* fsux() const { return sux_for(false); } | |||
1979 | BlockBegin* usux() const { return sux_for(unordered_is_true()); } | |||
1980 | bool should_profile() const { return check_flag(ProfileMDOFlag); } | |||
1981 | ciMethod* profiled_method() const { return _profiled_method; } // set only for profiled branches | |||
1982 | int profiled_bci() const { return _profiled_bci; } // set for profiled branches and tiered | |||
1983 | bool is_swapped() const { return _swapped; } | |||
1984 | ||||
1985 | // manipulation | |||
1986 | void swap_operands() { | |||
1987 | Value t = _x; _x = _y; _y = t; | |||
1988 | _cond = mirror(_cond); | |||
1989 | } | |||
1990 | ||||
1991 | void set_should_profile(bool value) { set_flag(ProfileMDOFlag, value); } | |||
1992 | void set_profiled_method(ciMethod* method) { _profiled_method = method; } | |||
1993 | void set_profiled_bci(int bci) { _profiled_bci = bci; } | |||
1994 | void set_swapped(bool value) { _swapped = value; } | |||
1995 | // generic | |||
1996 | virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); f->visit(&_x); f->visit(&_y); } | |||
1997 | }; | |||
1998 | ||||
1999 | ||||
2000 | BASE(Switch, BlockEnd)class Switch: public BlockEnd { public: virtual Switch* as_Switch () { return this; } | |||
2001 | private: | |||
2002 | Value _tag; | |||
2003 | ||||
2004 | public: | |||
2005 | // creation | |||
2006 | Switch(Value tag, BlockList* sux, ValueStack* state_before, bool is_safepoint) | |||
2007 | : BlockEnd(illegalType, state_before, is_safepoint) | |||
2008 | , _tag(tag) { | |||
2009 | ASSERT_VALUES | |||
2010 | set_sux(sux); | |||
2011 | } | |||
2012 | ||||
2013 | // accessors | |||
2014 | Value tag() const { return _tag; } | |||
2015 | int length() const { return number_of_sux() - 1; } | |||
2016 | ||||
2017 | virtual bool needs_exception_state() const { return false; } | |||
2018 | ||||
2019 | // generic | |||
2020 | virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); f->visit(&_tag); } | |||
2021 | }; | |||
2022 | ||||
2023 | ||||
2024 | LEAF(TableSwitch, Switch)class TableSwitch: public Switch { public: virtual TableSwitch * as_TableSwitch() { return this; } public: virtual const char * name() const { return "TableSwitch"; } virtual void visit(InstructionVisitor * v) { v->do_TableSwitch(this); } | |||
2025 | private: | |||
2026 | int _lo_key; | |||
2027 | ||||
2028 | public: | |||
2029 | // creation | |||
2030 | TableSwitch(Value tag, BlockList* sux, int lo_key, ValueStack* state_before, bool is_safepoint) | |||
2031 | : Switch(tag, sux, state_before, is_safepoint) | |||
2032 | , _lo_key(lo_key) { assert(_lo_key <= hi_key(), "integer overflow")do { if (!(_lo_key <= hi_key())) { (*g_assert_poison) = 'X' ;; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 2032, "assert(" "_lo_key <= hi_key()" ") failed", "integer overflow" ); ::breakpoint(); } } while (0); } | |||
2033 | ||||
2034 | // accessors | |||
2035 | int lo_key() const { return _lo_key; } | |||
2036 | int hi_key() const { return _lo_key + (length() - 1); } | |||
2037 | }; | |||
2038 | ||||
2039 | ||||
2040 | LEAF(LookupSwitch, Switch)class LookupSwitch: public Switch { public: virtual LookupSwitch * as_LookupSwitch() { return this; } public: virtual const char * name() const { return "LookupSwitch"; } virtual void visit( InstructionVisitor* v) { v->do_LookupSwitch(this); } | |||
2041 | private: | |||
2042 | intArray* _keys; | |||
2043 | ||||
2044 | public: | |||
2045 | // creation | |||
2046 | LookupSwitch(Value tag, BlockList* sux, intArray* keys, ValueStack* state_before, bool is_safepoint) | |||
2047 | : Switch(tag, sux, state_before, is_safepoint) | |||
2048 | , _keys(keys) { | |||
2049 | assert(keys != NULL, "keys must exist")do { if (!(keys != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 2049, "assert(" "keys != __null" ") failed", "keys must exist" ); ::breakpoint(); } } while (0); | |||
2050 | assert(keys->length() == length(), "sux & keys have incompatible lengths")do { if (!(keys->length() == length())) { (*g_assert_poison ) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 2050, "assert(" "keys->length() == length()" ") failed", "sux & keys have incompatible lengths"); ::breakpoint(); } } while (0); | |||
2051 | } | |||
2052 | ||||
2053 | // accessors | |||
2054 | int key_at(int i) const { return _keys->at(i); } | |||
2055 | }; | |||
2056 | ||||
2057 | ||||
2058 | LEAF(Return, BlockEnd)class Return: public BlockEnd { public: virtual Return* as_Return () { return this; } public: virtual const char* name() const { return "Return"; } virtual void visit(InstructionVisitor* v) { v->do_Return(this); } | |||
2059 | private: | |||
2060 | Value _result; | |||
2061 | ||||
2062 | public: | |||
2063 | // creation | |||
2064 | Return(Value result) : | |||
2065 | BlockEnd(result == NULL__null ? voidType : result->type()->base(), NULL__null, true), | |||
2066 | _result(result) {} | |||
2067 | ||||
2068 | // accessors | |||
2069 | Value result() const { return _result; } | |||
2070 | bool has_result() const { return result() != NULL__null; } | |||
2071 | ||||
2072 | // generic | |||
2073 | virtual void input_values_do(ValueVisitor* f) { | |||
2074 | BlockEnd::input_values_do(f); | |||
2075 | if (has_result()) f->visit(&_result); | |||
2076 | } | |||
2077 | }; | |||
2078 | ||||
2079 | ||||
2080 | LEAF(Throw, BlockEnd)class Throw: public BlockEnd { public: virtual Throw* as_Throw () { return this; } public: virtual const char* name() const { return "Throw"; } virtual void visit(InstructionVisitor* v) { v->do_Throw(this); } | |||
2081 | private: | |||
2082 | Value _exception; | |||
2083 | ||||
2084 | public: | |||
2085 | // creation | |||
2086 | Throw(Value exception, ValueStack* state_before) : BlockEnd(illegalType, state_before, true), _exception(exception) { | |||
2087 | ASSERT_VALUES | |||
2088 | } | |||
2089 | ||||
2090 | // accessors | |||
2091 | Value exception() const { return _exception; } | |||
2092 | ||||
2093 | // generic | |||
2094 | virtual bool can_trap() const { return true; } | |||
2095 | virtual void input_values_do(ValueVisitor* f) { BlockEnd::input_values_do(f); f->visit(&_exception); } | |||
2096 | }; | |||
2097 | ||||
2098 | ||||
2099 | LEAF(Base, BlockEnd)class Base: public BlockEnd { public: virtual Base* as_Base() { return this; } public: virtual const char* name() const { return "Base"; } virtual void visit(InstructionVisitor* v) { v-> do_Base(this); } | |||
2100 | public: | |||
2101 | // creation | |||
2102 | Base(BlockBegin* std_entry, BlockBegin* osr_entry) : BlockEnd(illegalType, NULL__null, false) { | |||
2103 | assert(std_entry->is_set(BlockBegin::std_entry_flag), "std entry must be flagged")do { if (!(std_entry->is_set(BlockBegin::std_entry_flag))) { (*g_assert_poison) = 'X';; report_vm_error("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 2103, "assert(" "std_entry->is_set(BlockBegin::std_entry_flag)" ") failed", "std entry must be flagged"); ::breakpoint(); } } while (0); | |||
2104 | assert(osr_entry == NULL || osr_entry->is_set(BlockBegin::osr_entry_flag), "osr entry must be flagged")do { if (!(osr_entry == __null || osr_entry->is_set(BlockBegin ::osr_entry_flag))) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 2104, "assert(" "osr_entry == __null || osr_entry->is_set(BlockBegin::osr_entry_flag)" ") failed", "osr entry must be flagged"); ::breakpoint(); } } while (0); | |||
2105 | BlockList* s = new BlockList(2); | |||
2106 | if (osr_entry != NULL__null) s->append(osr_entry); | |||
2107 | s->append(std_entry); // must be default sux! | |||
2108 | set_sux(s); | |||
2109 | } | |||
2110 | ||||
2111 | // accessors | |||
2112 | BlockBegin* std_entry() const { return default_sux(); } | |||
2113 | BlockBegin* osr_entry() const { return number_of_sux() < 2 ? NULL__null : sux_at(0); } | |||
2114 | }; | |||
2115 | ||||
2116 | ||||
2117 | LEAF(OsrEntry, Instruction)class OsrEntry: public Instruction { public: virtual OsrEntry * as_OsrEntry() { return this; } public: virtual const char* name () const { return "OsrEntry"; } virtual void visit(InstructionVisitor * v) { v->do_OsrEntry(this); } | |||
2118 | public: | |||
2119 | // creation | |||
2120 | #ifdef _LP641 | |||
2121 | OsrEntry() : Instruction(longType) { pin(); } | |||
2122 | #else | |||
2123 | OsrEntry() : Instruction(intType) { pin(); } | |||
2124 | #endif | |||
2125 | ||||
2126 | // generic | |||
2127 | virtual void input_values_do(ValueVisitor* f) { } | |||
2128 | }; | |||
2129 | ||||
2130 | ||||
2131 | // Models the incoming exception at a catch site | |||
2132 | LEAF(ExceptionObject, Instruction)class ExceptionObject: public Instruction { public: virtual ExceptionObject * as_ExceptionObject() { return this; } public: virtual const char* name() const { return "ExceptionObject"; } virtual void visit(InstructionVisitor* v) { v->do_ExceptionObject(this ); } | |||
2133 | public: | |||
2134 | // creation | |||
2135 | ExceptionObject() : Instruction(objectType) { | |||
2136 | pin(); | |||
2137 | } | |||
2138 | ||||
2139 | // generic | |||
2140 | virtual void input_values_do(ValueVisitor* f) { } | |||
2141 | }; | |||
2142 | ||||
2143 | ||||
2144 | // Models needed rounding for floating-point values on Intel. | |||
2145 | // Currently only used to represent rounding of double-precision | |||
2146 | // values stored into local variables, but could be used to model | |||
2147 | // intermediate rounding of single-precision values as well. | |||
2148 | LEAF(RoundFP, Instruction)class RoundFP: public Instruction { public: virtual RoundFP* as_RoundFP () { return this; } public: virtual const char* name() const { return "RoundFP"; } virtual void visit(InstructionVisitor* v ) { v->do_RoundFP(this); } | |||
2149 | private: | |||
2150 | Value _input; // floating-point value to be rounded | |||
2151 | ||||
2152 | public: | |||
2153 | RoundFP(Value input) | |||
2154 | : Instruction(input->type()) // Note: should not be used for constants | |||
2155 | , _input(input) | |||
2156 | { | |||
2157 | ASSERT_VALUES | |||
2158 | } | |||
2159 | ||||
2160 | // accessors | |||
2161 | Value input() const { return _input; } | |||
2162 | ||||
2163 | // generic | |||
2164 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_input); } | |||
2165 | }; | |||
2166 | ||||
2167 | ||||
2168 | BASE(UnsafeOp, Instruction)class UnsafeOp: public Instruction { public: virtual UnsafeOp * as_UnsafeOp() { return this; } | |||
2169 | private: | |||
2170 | Value _object; // Object to be fetched from or mutated | |||
2171 | Value _offset; // Offset within object | |||
2172 | bool _is_volatile; // true if volatile - dl/JSR166 | |||
2173 | BasicType _basic_type; // ValueType can not express byte-sized integers | |||
2174 | ||||
2175 | protected: | |||
2176 | // creation | |||
2177 | UnsafeOp(BasicType basic_type, Value object, Value offset, bool is_put, bool is_volatile) | |||
2178 | : Instruction(is_put ? voidType : as_ValueType(basic_type)), | |||
2179 | _object(object), _offset(offset), _is_volatile(is_volatile), _basic_type(basic_type) | |||
2180 | { | |||
2181 | //Note: Unsafe ops are not not guaranteed to throw NPE. | |||
2182 | // Convservatively, Unsafe operations must be pinned though we could be | |||
2183 | // looser about this if we wanted to.. | |||
2184 | pin(); | |||
2185 | } | |||
2186 | ||||
2187 | public: | |||
2188 | // accessors | |||
2189 | BasicType basic_type() { return _basic_type; } | |||
2190 | Value object() { return _object; } | |||
2191 | Value offset() { return _offset; } | |||
2192 | bool is_volatile() { return _is_volatile; } | |||
2193 | ||||
2194 | // generic | |||
2195 | virtual void input_values_do(ValueVisitor* f) { f->visit(&_object); | |||
2196 | f->visit(&_offset); } | |||
2197 | }; | |||
2198 | ||||
2199 | LEAF(UnsafeGet, UnsafeOp)class UnsafeGet: public UnsafeOp { public: virtual UnsafeGet* as_UnsafeGet() { return this; } public: virtual const char* name () const { return "UnsafeGet"; } virtual void visit(InstructionVisitor * v) { v->do_UnsafeGet(this); } | |||
2200 | private: | |||
2201 | bool _is_raw; | |||
2202 | public: | |||
2203 | UnsafeGet(BasicType basic_type, Value object, Value offset, bool is_volatile) | |||
2204 | : UnsafeOp(basic_type, object, offset, false, is_volatile) | |||
2205 | { | |||
2206 | ASSERT_VALUES | |||
2207 | _is_raw = false; | |||
2208 | } | |||
2209 | UnsafeGet(BasicType basic_type, Value object, Value offset, bool is_volatile, bool is_raw) | |||
2210 | : UnsafeOp(basic_type, object, offset, false, is_volatile), _is_raw(is_raw) | |||
2211 | { | |||
2212 | ASSERT_VALUES | |||
2213 | } | |||
2214 | ||||
2215 | // accessors | |||
2216 | bool is_raw() { return _is_raw; } | |||
2217 | }; | |||
2218 | ||||
2219 | ||||
2220 | LEAF(UnsafePut, UnsafeOp)class UnsafePut: public UnsafeOp { public: virtual UnsafePut* as_UnsafePut() { return this; } public: virtual const char* name () const { return "UnsafePut"; } virtual void visit(InstructionVisitor * v) { v->do_UnsafePut(this); } | |||
2221 | private: | |||
2222 | Value _value; // Value to be stored | |||
2223 | public: | |||
2224 | UnsafePut(BasicType basic_type, Value object, Value offset, Value value, bool is_volatile) | |||
2225 | : UnsafeOp(basic_type, object, offset, true, is_volatile) | |||
2226 | , _value(value) | |||
2227 | { | |||
2228 | ASSERT_VALUES | |||
2229 | } | |||
2230 | ||||
2231 | // accessors | |||
2232 | Value value() { return _value; } | |||
2233 | ||||
2234 | // generic | |||
2235 | virtual void input_values_do(ValueVisitor* f) { UnsafeOp::input_values_do(f); | |||
2236 | f->visit(&_value); } | |||
2237 | }; | |||
2238 | ||||
2239 | LEAF(UnsafeGetAndSet, UnsafeOp)class UnsafeGetAndSet: public UnsafeOp { public: virtual UnsafeGetAndSet * as_UnsafeGetAndSet() { return this; } public: virtual const char* name() const { return "UnsafeGetAndSet"; } virtual void visit(InstructionVisitor* v) { v->do_UnsafeGetAndSet(this ); } | |||
2240 | private: | |||
2241 | Value _value; // Value to be stored | |||
2242 | bool _is_add; | |||
2243 | public: | |||
2244 | UnsafeGetAndSet(BasicType basic_type, Value object, Value offset, Value value, bool is_add) | |||
2245 | : UnsafeOp(basic_type, object, offset, false, false) | |||
2246 | , _value(value) | |||
2247 | , _is_add(is_add) | |||
2248 | { | |||
2249 | ASSERT_VALUES | |||
2250 | } | |||
2251 | ||||
2252 | // accessors | |||
2253 | bool is_add() const { return _is_add; } | |||
2254 | Value value() { return _value; } | |||
2255 | ||||
2256 | // generic | |||
2257 | virtual void input_values_do(ValueVisitor* f) { UnsafeOp::input_values_do(f); | |||
2258 | f->visit(&_value); } | |||
2259 | }; | |||
2260 | ||||
2261 | LEAF(ProfileCall, Instruction)class ProfileCall: public Instruction { public: virtual ProfileCall * as_ProfileCall() { return this; } public: virtual const char * name() const { return "ProfileCall"; } virtual void visit(InstructionVisitor * v) { v->do_ProfileCall(this); } | |||
2262 | private: | |||
2263 | ciMethod* _method; | |||
2264 | int _bci_of_invoke; | |||
2265 | ciMethod* _callee; // the method that is called at the given bci | |||
2266 | Value _recv; | |||
2267 | ciKlass* _known_holder; | |||
2268 | Values* _obj_args; // arguments for type profiling | |||
2269 | ArgsNonNullState _nonnull_state; // Do we know whether some arguments are never null? | |||
2270 | bool _inlined; // Are we profiling a call that is inlined | |||
2271 | ||||
2272 | public: | |||
2273 | ProfileCall(ciMethod* method, int bci, ciMethod* callee, Value recv, ciKlass* known_holder, Values* obj_args, bool inlined) | |||
2274 | : Instruction(voidType) | |||
2275 | , _method(method) | |||
2276 | , _bci_of_invoke(bci) | |||
2277 | , _callee(callee) | |||
2278 | , _recv(recv) | |||
2279 | , _known_holder(known_holder) | |||
2280 | , _obj_args(obj_args) | |||
2281 | , _inlined(inlined) | |||
2282 | { | |||
2283 | // The ProfileCall has side-effects and must occur precisely where located | |||
2284 | pin(); | |||
2285 | } | |||
2286 | ||||
2287 | ciMethod* method() const { return _method; } | |||
2288 | int bci_of_invoke() const { return _bci_of_invoke; } | |||
2289 | ciMethod* callee() const { return _callee; } | |||
2290 | Value recv() const { return _recv; } | |||
2291 | ciKlass* known_holder() const { return _known_holder; } | |||
2292 | int nb_profiled_args() const { return _obj_args == NULL__null ? 0 : _obj_args->length(); } | |||
2293 | Value profiled_arg_at(int i) const { return _obj_args->at(i); } | |||
2294 | bool arg_needs_null_check(int i) const { | |||
2295 | return _nonnull_state.arg_needs_null_check(i); | |||
2296 | } | |||
2297 | bool inlined() const { return _inlined; } | |||
2298 | ||||
2299 | void set_arg_needs_null_check(int i, bool check) { | |||
2300 | _nonnull_state.set_arg_needs_null_check(i, check); | |||
2301 | } | |||
2302 | ||||
2303 | virtual void input_values_do(ValueVisitor* f) { | |||
2304 | if (_recv != NULL__null) { | |||
2305 | f->visit(&_recv); | |||
2306 | } | |||
2307 | for (int i = 0; i < nb_profiled_args(); i++) { | |||
2308 | f->visit(_obj_args->adr_at(i)); | |||
2309 | } | |||
2310 | } | |||
2311 | }; | |||
2312 | ||||
2313 | LEAF(ProfileReturnType, Instruction)class ProfileReturnType: public Instruction { public: virtual ProfileReturnType* as_ProfileReturnType() { return this; } public : virtual const char* name() const { return "ProfileReturnType" ; } virtual void visit(InstructionVisitor* v) { v->do_ProfileReturnType (this); } | |||
2314 | private: | |||
2315 | ciMethod* _method; | |||
2316 | ciMethod* _callee; | |||
2317 | int _bci_of_invoke; | |||
2318 | Value _ret; | |||
2319 | ||||
2320 | public: | |||
2321 | ProfileReturnType(ciMethod* method, int bci, ciMethod* callee, Value ret) | |||
2322 | : Instruction(voidType) | |||
2323 | , _method(method) | |||
2324 | , _callee(callee) | |||
2325 | , _bci_of_invoke(bci) | |||
2326 | , _ret(ret) | |||
2327 | { | |||
2328 | set_needs_null_check(true); | |||
2329 | // The ProfileType has side-effects and must occur precisely where located | |||
2330 | pin(); | |||
2331 | } | |||
2332 | ||||
2333 | ciMethod* method() const { return _method; } | |||
2334 | ciMethod* callee() const { return _callee; } | |||
2335 | int bci_of_invoke() const { return _bci_of_invoke; } | |||
2336 | Value ret() const { return _ret; } | |||
2337 | ||||
2338 | virtual void input_values_do(ValueVisitor* f) { | |||
2339 | if (_ret != NULL__null) { | |||
2340 | f->visit(&_ret); | |||
2341 | } | |||
2342 | } | |||
2343 | }; | |||
2344 | ||||
2345 | // Call some C runtime function that doesn't safepoint, | |||
2346 | // optionally passing the current thread as the first argument. | |||
2347 | LEAF(RuntimeCall, Instruction)class RuntimeCall: public Instruction { public: virtual RuntimeCall * as_RuntimeCall() { return this; } public: virtual const char * name() const { return "RuntimeCall"; } virtual void visit(InstructionVisitor * v) { v->do_RuntimeCall(this); } | |||
2348 | private: | |||
2349 | const char* _entry_name; | |||
2350 | address _entry; | |||
2351 | Values* _args; | |||
2352 | bool _pass_thread; // Pass the JavaThread* as an implicit first argument | |||
2353 | ||||
2354 | public: | |||
2355 | RuntimeCall(ValueType* type, const char* entry_name, address entry, Values* args, bool pass_thread = true) | |||
2356 | : Instruction(type) | |||
2357 | , _entry_name(entry_name) | |||
2358 | , _entry(entry) | |||
2359 | , _args(args) | |||
2360 | , _pass_thread(pass_thread) { | |||
2361 | ASSERT_VALUES | |||
2362 | pin(); | |||
2363 | } | |||
2364 | ||||
2365 | const char* entry_name() const { return _entry_name; } | |||
2366 | address entry() const { return _entry; } | |||
2367 | int number_of_arguments() const { return _args->length(); } | |||
2368 | Value argument_at(int i) const { return _args->at(i); } | |||
2369 | bool pass_thread() const { return _pass_thread; } | |||
2370 | ||||
2371 | virtual void input_values_do(ValueVisitor* f) { | |||
2372 | for (int i = 0; i < _args->length(); i++) f->visit(_args->adr_at(i)); | |||
2373 | } | |||
2374 | }; | |||
2375 | ||||
2376 | // Use to trip invocation counter of an inlined method | |||
2377 | ||||
2378 | LEAF(ProfileInvoke, Instruction)class ProfileInvoke: public Instruction { public: virtual ProfileInvoke * as_ProfileInvoke() { return this; } public: virtual const char * name() const { return "ProfileInvoke"; } virtual void visit (InstructionVisitor* v) { v->do_ProfileInvoke(this); } | |||
2379 | private: | |||
2380 | ciMethod* _inlinee; | |||
2381 | ValueStack* _state; | |||
2382 | ||||
2383 | public: | |||
2384 | ProfileInvoke(ciMethod* inlinee, ValueStack* state) | |||
2385 | : Instruction(voidType) | |||
2386 | , _inlinee(inlinee) | |||
2387 | , _state(state) | |||
2388 | { | |||
2389 | // The ProfileInvoke has side-effects and must occur precisely where located QQQ??? | |||
2390 | pin(); | |||
2391 | } | |||
2392 | ||||
2393 | ciMethod* inlinee() { return _inlinee; } | |||
2394 | ValueStack* state() { return _state; } | |||
2395 | virtual void input_values_do(ValueVisitor*) {} | |||
2396 | virtual void state_values_do(ValueVisitor*); | |||
2397 | }; | |||
2398 | ||||
2399 | LEAF(MemBar, Instruction)class MemBar: public Instruction { public: virtual MemBar* as_MemBar () { return this; } public: virtual const char* name() const { return "MemBar"; } virtual void visit(InstructionVisitor* v) { v->do_MemBar(this); } | |||
2400 | private: | |||
2401 | LIR_Code _code; | |||
2402 | ||||
2403 | public: | |||
2404 | MemBar(LIR_Code code) | |||
2405 | : Instruction(voidType) | |||
2406 | , _code(code) | |||
2407 | { | |||
2408 | pin(); | |||
2409 | } | |||
2410 | ||||
2411 | LIR_Code code() { return _code; } | |||
2412 | ||||
2413 | virtual void input_values_do(ValueVisitor*) {} | |||
2414 | }; | |||
2415 | ||||
2416 | class BlockPair: public CompilationResourceObj { | |||
2417 | private: | |||
2418 | BlockBegin* _from; | |||
2419 | BlockBegin* _to; | |||
2420 | public: | |||
2421 | BlockPair(BlockBegin* from, BlockBegin* to): _from(from), _to(to) {} | |||
2422 | BlockBegin* from() const { return _from; } | |||
2423 | BlockBegin* to() const { return _to; } | |||
2424 | bool is_same(BlockBegin* from, BlockBegin* to) const { return _from == from && _to == to; } | |||
2425 | bool is_same(BlockPair* p) const { return _from == p->from() && _to == p->to(); } | |||
2426 | void set_to(BlockBegin* b) { _to = b; } | |||
2427 | void set_from(BlockBegin* b) { _from = b; } | |||
2428 | }; | |||
2429 | ||||
2430 | typedef GrowableArray<BlockPair*> BlockPairList; | |||
2431 | ||||
2432 | inline int BlockBegin::number_of_sux() const { assert(_end != NULL, "need end")do { if (!(_end != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 2432, "assert(" "_end != __null" ") failed", "need end"); :: breakpoint(); } } while (0); return _end->number_of_sux(); } | |||
2433 | inline BlockBegin* BlockBegin::sux_at(int i) const { assert(_end != NULL , "need end")do { if (!(_end != __null)) { (*g_assert_poison) = 'X';; report_vm_error ("/home/daniel/Projects/java/jdk/src/hotspot/share/c1/c1_Instruction.hpp" , 2433, "assert(" "_end != __null" ") failed", "need end"); :: breakpoint(); } } while (0); return _end->sux_at(i); } | |||
2434 | ||||
2435 | #undef ASSERT_VALUES | |||
2436 | ||||
2437 | #endif // SHARE_C1_C1_INSTRUCTION_HPP |