-
Notifications
You must be signed in to change notification settings - Fork 5.4k
/
graphKit.cpp
4283 lines (3813 loc) · 169 KB
/
graphKit.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* Copyright (c) 2001, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "ci/ciUtilities.hpp"
#include "classfile/javaClasses.hpp"
#include "ci/ciNativeEntryPoint.hpp"
#include "ci/ciObjArray.hpp"
#include "asm/register.hpp"
#include "compiler/compileLog.hpp"
#include "gc/shared/barrierSet.hpp"
#include "gc/shared/c2/barrierSetC2.hpp"
#include "interpreter/interpreter.hpp"
#include "memory/resourceArea.hpp"
#include "opto/addnode.hpp"
#include "opto/castnode.hpp"
#include "opto/convertnode.hpp"
#include "opto/graphKit.hpp"
#include "opto/idealKit.hpp"
#include "opto/intrinsicnode.hpp"
#include "opto/locknode.hpp"
#include "opto/machnode.hpp"
#include "opto/opaquenode.hpp"
#include "opto/parse.hpp"
#include "opto/rootnode.hpp"
#include "opto/runtime.hpp"
#include "opto/subtypenode.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/sharedRuntime.hpp"
#include "utilities/bitMap.inline.hpp"
#include "utilities/powerOfTwo.hpp"
#include "utilities/growableArray.hpp"
//----------------------------GraphKit-----------------------------------------
// Main utility constructor.
GraphKit::GraphKit(JVMState* jvms)
: Phase(Phase::Parser),
_env(C->env()),
_gvn(*C->initial_gvn()),
_barrier_set(BarrierSet::barrier_set()->barrier_set_c2())
{
_exceptions = jvms->map()->next_exception();
if (_exceptions != NULL) jvms->map()->set_next_exception(NULL);
set_jvms(jvms);
}
// Private constructor for parser.
GraphKit::GraphKit()
: Phase(Phase::Parser),
_env(C->env()),
_gvn(*C->initial_gvn()),
_barrier_set(BarrierSet::barrier_set()->barrier_set_c2())
{
_exceptions = NULL;
set_map(NULL);
debug_only(_sp = -99);
debug_only(set_bci(-99));
}
//---------------------------clean_stack---------------------------------------
// Clear away rubbish from the stack area of the JVM state.
// This destroys any arguments that may be waiting on the stack.
void GraphKit::clean_stack(int from_sp) {
SafePointNode* map = this->map();
JVMState* jvms = this->jvms();
int stk_size = jvms->stk_size();
int stkoff = jvms->stkoff();
Node* top = this->top();
for (int i = from_sp; i < stk_size; i++) {
if (map->in(stkoff + i) != top) {
map->set_req(stkoff + i, top);
}
}
}
//--------------------------------sync_jvms-----------------------------------
// Make sure our current jvms agrees with our parse state.
JVMState* GraphKit::sync_jvms() const {
JVMState* jvms = this->jvms();
jvms->set_bci(bci()); // Record the new bci in the JVMState
jvms->set_sp(sp()); // Record the new sp in the JVMState
assert(jvms_in_sync(), "jvms is now in sync");
return jvms;
}
//--------------------------------sync_jvms_for_reexecute---------------------
// Make sure our current jvms agrees with our parse state. This version
// uses the reexecute_sp for reexecuting bytecodes.
JVMState* GraphKit::sync_jvms_for_reexecute() {
JVMState* jvms = this->jvms();
jvms->set_bci(bci()); // Record the new bci in the JVMState
jvms->set_sp(reexecute_sp()); // Record the new sp in the JVMState
return jvms;
}
#ifdef ASSERT
bool GraphKit::jvms_in_sync() const {
Parse* parse = is_Parse();
if (parse == NULL) {
if (bci() != jvms()->bci()) return false;
if (sp() != (int)jvms()->sp()) return false;
return true;
}
if (jvms()->method() != parse->method()) return false;
if (jvms()->bci() != parse->bci()) return false;
int jvms_sp = jvms()->sp();
if (jvms_sp != parse->sp()) return false;
int jvms_depth = jvms()->depth();
if (jvms_depth != parse->depth()) return false;
return true;
}
// Local helper checks for special internal merge points
// used to accumulate and merge exception states.
// They are marked by the region's in(0) edge being the map itself.
// Such merge points must never "escape" into the parser at large,
// until they have been handed to gvn.transform.
static bool is_hidden_merge(Node* reg) {
if (reg == NULL) return false;
if (reg->is_Phi()) {
reg = reg->in(0);
if (reg == NULL) return false;
}
return reg->is_Region() && reg->in(0) != NULL && reg->in(0)->is_Root();
}
void GraphKit::verify_map() const {
if (map() == NULL) return; // null map is OK
assert(map()->req() <= jvms()->endoff(), "no extra garbage on map");
assert(!map()->has_exceptions(), "call add_exception_states_from 1st");
assert(!is_hidden_merge(control()), "call use_exception_state, not set_map");
}
void GraphKit::verify_exception_state(SafePointNode* ex_map) {
assert(ex_map->next_exception() == NULL, "not already part of a chain");
assert(has_saved_ex_oop(ex_map), "every exception state has an ex_oop");
}
#endif
//---------------------------stop_and_kill_map---------------------------------
// Set _map to NULL, signalling a stop to further bytecode execution.
// First smash the current map's control to a constant, to mark it dead.
void GraphKit::stop_and_kill_map() {
SafePointNode* dead_map = stop();
if (dead_map != NULL) {
dead_map->disconnect_inputs(C); // Mark the map as killed.
assert(dead_map->is_killed(), "must be so marked");
}
}
//--------------------------------stopped--------------------------------------
// Tell if _map is NULL, or control is top.
bool GraphKit::stopped() {
if (map() == NULL) return true;
else if (control() == top()) return true;
else return false;
}
//-----------------------------has_ex_handler----------------------------------
// Tell if this method or any caller method has exception handlers.
bool GraphKit::has_ex_handler() {
for (JVMState* jvmsp = jvms(); jvmsp != NULL; jvmsp = jvmsp->caller()) {
if (jvmsp->has_method() && jvmsp->method()->has_exception_handlers()) {
return true;
}
}
return false;
}
//------------------------------save_ex_oop------------------------------------
// Save an exception without blowing stack contents or other JVM state.
void GraphKit::set_saved_ex_oop(SafePointNode* ex_map, Node* ex_oop) {
assert(!has_saved_ex_oop(ex_map), "clear ex-oop before setting again");
ex_map->add_req(ex_oop);
debug_only(verify_exception_state(ex_map));
}
inline static Node* common_saved_ex_oop(SafePointNode* ex_map, bool clear_it) {
assert(GraphKit::has_saved_ex_oop(ex_map), "ex_oop must be there");
Node* ex_oop = ex_map->in(ex_map->req()-1);
if (clear_it) ex_map->del_req(ex_map->req()-1);
return ex_oop;
}
//-----------------------------saved_ex_oop------------------------------------
// Recover a saved exception from its map.
Node* GraphKit::saved_ex_oop(SafePointNode* ex_map) {
return common_saved_ex_oop(ex_map, false);
}
//--------------------------clear_saved_ex_oop---------------------------------
// Erase a previously saved exception from its map.
Node* GraphKit::clear_saved_ex_oop(SafePointNode* ex_map) {
return common_saved_ex_oop(ex_map, true);
}
#ifdef ASSERT
//---------------------------has_saved_ex_oop----------------------------------
// Erase a previously saved exception from its map.
bool GraphKit::has_saved_ex_oop(SafePointNode* ex_map) {
return ex_map->req() == ex_map->jvms()->endoff()+1;
}
#endif
//-------------------------make_exception_state--------------------------------
// Turn the current JVM state into an exception state, appending the ex_oop.
SafePointNode* GraphKit::make_exception_state(Node* ex_oop) {
sync_jvms();
SafePointNode* ex_map = stop(); // do not manipulate this map any more
set_saved_ex_oop(ex_map, ex_oop);
return ex_map;
}
//--------------------------add_exception_state--------------------------------
// Add an exception to my list of exceptions.
void GraphKit::add_exception_state(SafePointNode* ex_map) {
if (ex_map == NULL || ex_map->control() == top()) {
return;
}
#ifdef ASSERT
verify_exception_state(ex_map);
if (has_exceptions()) {
assert(ex_map->jvms()->same_calls_as(_exceptions->jvms()), "all collected exceptions must come from the same place");
}
#endif
// If there is already an exception of exactly this type, merge with it.
// In particular, null-checks and other low-level exceptions common up here.
Node* ex_oop = saved_ex_oop(ex_map);
const Type* ex_type = _gvn.type(ex_oop);
if (ex_oop == top()) {
// No action needed.
return;
}
assert(ex_type->isa_instptr(), "exception must be an instance");
for (SafePointNode* e2 = _exceptions; e2 != NULL; e2 = e2->next_exception()) {
const Type* ex_type2 = _gvn.type(saved_ex_oop(e2));
// We check sp also because call bytecodes can generate exceptions
// both before and after arguments are popped!
if (ex_type2 == ex_type
&& e2->_jvms->sp() == ex_map->_jvms->sp()) {
combine_exception_states(ex_map, e2);
return;
}
}
// No pre-existing exception of the same type. Chain it on the list.
push_exception_state(ex_map);
}
//-----------------------add_exception_states_from-----------------------------
void GraphKit::add_exception_states_from(JVMState* jvms) {
SafePointNode* ex_map = jvms->map()->next_exception();
if (ex_map != NULL) {
jvms->map()->set_next_exception(NULL);
for (SafePointNode* next_map; ex_map != NULL; ex_map = next_map) {
next_map = ex_map->next_exception();
ex_map->set_next_exception(NULL);
add_exception_state(ex_map);
}
}
}
//-----------------------transfer_exceptions_into_jvms-------------------------
JVMState* GraphKit::transfer_exceptions_into_jvms() {
if (map() == NULL) {
// We need a JVMS to carry the exceptions, but the map has gone away.
// Create a scratch JVMS, cloned from any of the exception states...
if (has_exceptions()) {
_map = _exceptions;
_map = clone_map();
_map->set_next_exception(NULL);
clear_saved_ex_oop(_map);
debug_only(verify_map());
} else {
// ...or created from scratch
JVMState* jvms = new (C) JVMState(_method, NULL);
jvms->set_bci(_bci);
jvms->set_sp(_sp);
jvms->set_map(new SafePointNode(TypeFunc::Parms, jvms));
set_jvms(jvms);
for (uint i = 0; i < map()->req(); i++) map()->init_req(i, top());
set_all_memory(top());
while (map()->req() < jvms->endoff()) map()->add_req(top());
}
// (This is a kludge, in case you didn't notice.)
set_control(top());
}
JVMState* jvms = sync_jvms();
assert(!jvms->map()->has_exceptions(), "no exceptions on this map yet");
jvms->map()->set_next_exception(_exceptions);
_exceptions = NULL; // done with this set of exceptions
return jvms;
}
static inline void add_n_reqs(Node* dstphi, Node* srcphi) {
assert(is_hidden_merge(dstphi), "must be a special merge node");
assert(is_hidden_merge(srcphi), "must be a special merge node");
uint limit = srcphi->req();
for (uint i = PhiNode::Input; i < limit; i++) {
dstphi->add_req(srcphi->in(i));
}
}
static inline void add_one_req(Node* dstphi, Node* src) {
assert(is_hidden_merge(dstphi), "must be a special merge node");
assert(!is_hidden_merge(src), "must not be a special merge node");
dstphi->add_req(src);
}
//-----------------------combine_exception_states------------------------------
// This helper function combines exception states by building phis on a
// specially marked state-merging region. These regions and phis are
// untransformed, and can build up gradually. The region is marked by
// having a control input of its exception map, rather than NULL. Such
// regions do not appear except in this function, and in use_exception_state.
void GraphKit::combine_exception_states(SafePointNode* ex_map, SafePointNode* phi_map) {
if (failing()) return; // dying anyway...
JVMState* ex_jvms = ex_map->_jvms;
assert(ex_jvms->same_calls_as(phi_map->_jvms), "consistent call chains");
assert(ex_jvms->stkoff() == phi_map->_jvms->stkoff(), "matching locals");
assert(ex_jvms->sp() == phi_map->_jvms->sp(), "matching stack sizes");
assert(ex_jvms->monoff() == phi_map->_jvms->monoff(), "matching JVMS");
assert(ex_jvms->scloff() == phi_map->_jvms->scloff(), "matching scalar replaced objects");
assert(ex_map->req() == phi_map->req(), "matching maps");
uint tos = ex_jvms->stkoff() + ex_jvms->sp();
Node* hidden_merge_mark = root();
Node* region = phi_map->control();
MergeMemNode* phi_mem = phi_map->merged_memory();
MergeMemNode* ex_mem = ex_map->merged_memory();
if (region->in(0) != hidden_merge_mark) {
// The control input is not (yet) a specially-marked region in phi_map.
// Make it so, and build some phis.
region = new RegionNode(2);
_gvn.set_type(region, Type::CONTROL);
region->set_req(0, hidden_merge_mark); // marks an internal ex-state
region->init_req(1, phi_map->control());
phi_map->set_control(region);
Node* io_phi = PhiNode::make(region, phi_map->i_o(), Type::ABIO);
record_for_igvn(io_phi);
_gvn.set_type(io_phi, Type::ABIO);
phi_map->set_i_o(io_phi);
for (MergeMemStream mms(phi_mem); mms.next_non_empty(); ) {
Node* m = mms.memory();
Node* m_phi = PhiNode::make(region, m, Type::MEMORY, mms.adr_type(C));
record_for_igvn(m_phi);
_gvn.set_type(m_phi, Type::MEMORY);
mms.set_memory(m_phi);
}
}
// Either or both of phi_map and ex_map might already be converted into phis.
Node* ex_control = ex_map->control();
// if there is special marking on ex_map also, we add multiple edges from src
bool add_multiple = (ex_control->in(0) == hidden_merge_mark);
// how wide was the destination phi_map, originally?
uint orig_width = region->req();
if (add_multiple) {
add_n_reqs(region, ex_control);
add_n_reqs(phi_map->i_o(), ex_map->i_o());
} else {
// ex_map has no merges, so we just add single edges everywhere
add_one_req(region, ex_control);
add_one_req(phi_map->i_o(), ex_map->i_o());
}
for (MergeMemStream mms(phi_mem, ex_mem); mms.next_non_empty2(); ) {
if (mms.is_empty()) {
// get a copy of the base memory, and patch some inputs into it
const TypePtr* adr_type = mms.adr_type(C);
Node* phi = mms.force_memory()->as_Phi()->slice_memory(adr_type);
assert(phi->as_Phi()->region() == mms.base_memory()->in(0), "");
mms.set_memory(phi);
// Prepare to append interesting stuff onto the newly sliced phi:
while (phi->req() > orig_width) phi->del_req(phi->req()-1);
}
// Append stuff from ex_map:
if (add_multiple) {
add_n_reqs(mms.memory(), mms.memory2());
} else {
add_one_req(mms.memory(), mms.memory2());
}
}
uint limit = ex_map->req();
for (uint i = TypeFunc::Parms; i < limit; i++) {
// Skip everything in the JVMS after tos. (The ex_oop follows.)
if (i == tos) i = ex_jvms->monoff();
Node* src = ex_map->in(i);
Node* dst = phi_map->in(i);
if (src != dst) {
PhiNode* phi;
if (dst->in(0) != region) {
dst = phi = PhiNode::make(region, dst, _gvn.type(dst));
record_for_igvn(phi);
_gvn.set_type(phi, phi->type());
phi_map->set_req(i, dst);
// Prepare to append interesting stuff onto the new phi:
while (dst->req() > orig_width) dst->del_req(dst->req()-1);
} else {
assert(dst->is_Phi(), "nobody else uses a hidden region");
phi = dst->as_Phi();
}
if (add_multiple && src->in(0) == ex_control) {
// Both are phis.
add_n_reqs(dst, src);
} else {
while (dst->req() < region->req()) add_one_req(dst, src);
}
const Type* srctype = _gvn.type(src);
if (phi->type() != srctype) {
const Type* dsttype = phi->type()->meet_speculative(srctype);
if (phi->type() != dsttype) {
phi->set_type(dsttype);
_gvn.set_type(phi, dsttype);
}
}
}
}
phi_map->merge_replaced_nodes_with(ex_map);
}
//--------------------------use_exception_state--------------------------------
Node* GraphKit::use_exception_state(SafePointNode* phi_map) {
if (failing()) { stop(); return top(); }
Node* region = phi_map->control();
Node* hidden_merge_mark = root();
assert(phi_map->jvms()->map() == phi_map, "sanity: 1-1 relation");
Node* ex_oop = clear_saved_ex_oop(phi_map);
if (region->in(0) == hidden_merge_mark) {
// Special marking for internal ex-states. Process the phis now.
region->set_req(0, region); // now it's an ordinary region
set_jvms(phi_map->jvms()); // ...so now we can use it as a map
// Note: Setting the jvms also sets the bci and sp.
set_control(_gvn.transform(region));
uint tos = jvms()->stkoff() + sp();
for (uint i = 1; i < tos; i++) {
Node* x = phi_map->in(i);
if (x->in(0) == region) {
assert(x->is_Phi(), "expected a special phi");
phi_map->set_req(i, _gvn.transform(x));
}
}
for (MergeMemStream mms(merged_memory()); mms.next_non_empty(); ) {
Node* x = mms.memory();
if (x->in(0) == region) {
assert(x->is_Phi(), "nobody else uses a hidden region");
mms.set_memory(_gvn.transform(x));
}
}
if (ex_oop->in(0) == region) {
assert(ex_oop->is_Phi(), "expected a special phi");
ex_oop = _gvn.transform(ex_oop);
}
} else {
set_jvms(phi_map->jvms());
}
assert(!is_hidden_merge(phi_map->control()), "hidden ex. states cleared");
assert(!is_hidden_merge(phi_map->i_o()), "hidden ex. states cleared");
return ex_oop;
}
//---------------------------------java_bc-------------------------------------
Bytecodes::Code GraphKit::java_bc() const {
ciMethod* method = this->method();
int bci = this->bci();
if (method != NULL && bci != InvocationEntryBci)
return method->java_code_at_bci(bci);
else
return Bytecodes::_illegal;
}
void GraphKit::uncommon_trap_if_should_post_on_exceptions(Deoptimization::DeoptReason reason,
bool must_throw) {
// if the exception capability is set, then we will generate code
// to check the JavaThread.should_post_on_exceptions flag to see
// if we actually need to report exception events (for this
// thread). If we don't need to report exception events, we will
// take the normal fast path provided by add_exception_events. If
// exception event reporting is enabled for this thread, we will
// take the uncommon_trap in the BuildCutout below.
// first must access the should_post_on_exceptions_flag in this thread's JavaThread
Node* jthread = _gvn.transform(new ThreadLocalNode());
Node* adr = basic_plus_adr(top(), jthread, in_bytes(JavaThread::should_post_on_exceptions_flag_offset()));
Node* should_post_flag = make_load(control(), adr, TypeInt::INT, T_INT, Compile::AliasIdxRaw, MemNode::unordered);
// Test the should_post_on_exceptions_flag vs. 0
Node* chk = _gvn.transform( new CmpINode(should_post_flag, intcon(0)) );
Node* tst = _gvn.transform( new BoolNode(chk, BoolTest::eq) );
// Branch to slow_path if should_post_on_exceptions_flag was true
{ BuildCutout unless(this, tst, PROB_MAX);
// Do not try anything fancy if we're notifying the VM on every throw.
// Cf. case Bytecodes::_athrow in parse2.cpp.
uncommon_trap(reason, Deoptimization::Action_none,
(ciKlass*)NULL, (char*)NULL, must_throw);
}
}
//------------------------------builtin_throw----------------------------------
void GraphKit::builtin_throw(Deoptimization::DeoptReason reason, Node* arg) {
bool must_throw = true;
if (env()->jvmti_can_post_on_exceptions()) {
// check if we must post exception events, take uncommon trap if so
uncommon_trap_if_should_post_on_exceptions(reason, must_throw);
// here if should_post_on_exceptions is false
// continue on with the normal codegen
}
// If this particular condition has not yet happened at this
// bytecode, then use the uncommon trap mechanism, and allow for
// a future recompilation if several traps occur here.
// If the throw is hot, try to use a more complicated inline mechanism
// which keeps execution inside the compiled code.
bool treat_throw_as_hot = false;
ciMethodData* md = method()->method_data();
if (ProfileTraps) {
if (too_many_traps(reason)) {
treat_throw_as_hot = true;
}
// (If there is no MDO at all, assume it is early in
// execution, and that any deopts are part of the
// startup transient, and don't need to be remembered.)
// Also, if there is a local exception handler, treat all throws
// as hot if there has been at least one in this method.
if (C->trap_count(reason) != 0
&& method()->method_data()->trap_count(reason) != 0
&& has_ex_handler()) {
treat_throw_as_hot = true;
}
}
// If this throw happens frequently, an uncommon trap might cause
// a performance pothole. If there is a local exception handler,
// and if this particular bytecode appears to be deoptimizing often,
// let us handle the throw inline, with a preconstructed instance.
// Note: If the deopt count has blown up, the uncommon trap
// runtime is going to flush this nmethod, not matter what.
if (treat_throw_as_hot
&& (!StackTraceInThrowable || OmitStackTraceInFastThrow)) {
// If the throw is local, we use a pre-existing instance and
// punt on the backtrace. This would lead to a missing backtrace
// (a repeat of 4292742) if the backtrace object is ever asked
// for its backtrace.
// Fixing this remaining case of 4292742 requires some flavor of
// escape analysis. Leave that for the future.
ciInstance* ex_obj = NULL;
switch (reason) {
case Deoptimization::Reason_null_check:
ex_obj = env()->NullPointerException_instance();
break;
case Deoptimization::Reason_div0_check:
ex_obj = env()->ArithmeticException_instance();
break;
case Deoptimization::Reason_range_check:
ex_obj = env()->ArrayIndexOutOfBoundsException_instance();
break;
case Deoptimization::Reason_class_check:
if (java_bc() == Bytecodes::_aastore) {
ex_obj = env()->ArrayStoreException_instance();
} else {
ex_obj = env()->ClassCastException_instance();
}
break;
default:
break;
}
if (failing()) { stop(); return; } // exception allocation might fail
if (ex_obj != NULL) {
// Cheat with a preallocated exception object.
if (C->log() != NULL)
C->log()->elem("hot_throw preallocated='1' reason='%s'",
Deoptimization::trap_reason_name(reason));
const TypeInstPtr* ex_con = TypeInstPtr::make(ex_obj);
Node* ex_node = _gvn.transform(ConNode::make(ex_con));
// Clear the detail message of the preallocated exception object.
// Weblogic sometimes mutates the detail message of exceptions
// using reflection.
int offset = java_lang_Throwable::get_detailMessage_offset();
const TypePtr* adr_typ = ex_con->add_offset(offset);
Node *adr = basic_plus_adr(ex_node, ex_node, offset);
const TypeOopPtr* val_type = TypeOopPtr::make_from_klass(env()->String_klass());
Node *store = access_store_at(ex_node, adr, adr_typ, null(), val_type, T_OBJECT, IN_HEAP);
add_exception_state(make_exception_state(ex_node));
return;
}
}
// %%% Maybe add entry to OptoRuntime which directly throws the exc.?
// It won't be much cheaper than bailing to the interp., since we'll
// have to pass up all the debug-info, and the runtime will have to
// create the stack trace.
// Usual case: Bail to interpreter.
// Reserve the right to recompile if we haven't seen anything yet.
ciMethod* m = Deoptimization::reason_is_speculate(reason) ? C->method() : NULL;
Deoptimization::DeoptAction action = Deoptimization::Action_maybe_recompile;
if (treat_throw_as_hot
&& (method()->method_data()->trap_recompiled_at(bci(), m)
|| C->too_many_traps(reason))) {
// We cannot afford to take more traps here. Suffer in the interpreter.
if (C->log() != NULL)
C->log()->elem("hot_throw preallocated='0' reason='%s' mcount='%d'",
Deoptimization::trap_reason_name(reason),
C->trap_count(reason));
action = Deoptimization::Action_none;
}
// "must_throw" prunes the JVM state to include only the stack, if there
// are no local exception handlers. This should cut down on register
// allocation time and code size, by drastically reducing the number
// of in-edges on the call to the uncommon trap.
uncommon_trap(reason, action, (ciKlass*)NULL, (char*)NULL, must_throw);
}
//----------------------------PreserveJVMState---------------------------------
PreserveJVMState::PreserveJVMState(GraphKit* kit, bool clone_map) {
debug_only(kit->verify_map());
_kit = kit;
_map = kit->map(); // preserve the map
_sp = kit->sp();
kit->set_map(clone_map ? kit->clone_map() : NULL);
#ifdef ASSERT
_bci = kit->bci();
Parse* parser = kit->is_Parse();
int block = (parser == NULL || parser->block() == NULL) ? -1 : parser->block()->rpo();
_block = block;
#endif
}
PreserveJVMState::~PreserveJVMState() {
GraphKit* kit = _kit;
#ifdef ASSERT
assert(kit->bci() == _bci, "bci must not shift");
Parse* parser = kit->is_Parse();
int block = (parser == NULL || parser->block() == NULL) ? -1 : parser->block()->rpo();
assert(block == _block, "block must not shift");
#endif
kit->set_map(_map);
kit->set_sp(_sp);
}
//-----------------------------BuildCutout-------------------------------------
BuildCutout::BuildCutout(GraphKit* kit, Node* p, float prob, float cnt)
: PreserveJVMState(kit)
{
assert(p->is_Con() || p->is_Bool(), "test must be a bool");
SafePointNode* outer_map = _map; // preserved map is caller's
SafePointNode* inner_map = kit->map();
IfNode* iff = kit->create_and_map_if(outer_map->control(), p, prob, cnt);
outer_map->set_control(kit->gvn().transform( new IfTrueNode(iff) ));
inner_map->set_control(kit->gvn().transform( new IfFalseNode(iff) ));
}
BuildCutout::~BuildCutout() {
GraphKit* kit = _kit;
assert(kit->stopped(), "cutout code must stop, throw, return, etc.");
}
//---------------------------PreserveReexecuteState----------------------------
PreserveReexecuteState::PreserveReexecuteState(GraphKit* kit) {
assert(!kit->stopped(), "must call stopped() before");
_kit = kit;
_sp = kit->sp();
_reexecute = kit->jvms()->_reexecute;
}
PreserveReexecuteState::~PreserveReexecuteState() {
if (_kit->stopped()) return;
_kit->jvms()->_reexecute = _reexecute;
_kit->set_sp(_sp);
}
//------------------------------clone_map--------------------------------------
// Implementation of PreserveJVMState
//
// Only clone_map(...) here. If this function is only used in the
// PreserveJVMState class we may want to get rid of this extra
// function eventually and do it all there.
SafePointNode* GraphKit::clone_map() {
if (map() == NULL) return NULL;
// Clone the memory edge first
Node* mem = MergeMemNode::make(map()->memory());
gvn().set_type_bottom(mem);
SafePointNode *clonemap = (SafePointNode*)map()->clone();
JVMState* jvms = this->jvms();
JVMState* clonejvms = jvms->clone_shallow(C);
clonemap->set_memory(mem);
clonemap->set_jvms(clonejvms);
clonejvms->set_map(clonemap);
record_for_igvn(clonemap);
gvn().set_type_bottom(clonemap);
return clonemap;
}
//-----------------------------set_map_clone-----------------------------------
void GraphKit::set_map_clone(SafePointNode* m) {
_map = m;
_map = clone_map();
_map->set_next_exception(NULL);
debug_only(verify_map());
}
//----------------------------kill_dead_locals---------------------------------
// Detect any locals which are known to be dead, and force them to top.
void GraphKit::kill_dead_locals() {
// Consult the liveness information for the locals. If any
// of them are unused, then they can be replaced by top(). This
// should help register allocation time and cut down on the size
// of the deoptimization information.
// This call is made from many of the bytecode handling
// subroutines called from the Big Switch in do_one_bytecode.
// Every bytecode which might include a slow path is responsible
// for killing its dead locals. The more consistent we
// are about killing deads, the fewer useless phis will be
// constructed for them at various merge points.
// bci can be -1 (InvocationEntryBci). We return the entry
// liveness for the method.
if (method() == NULL || method()->code_size() == 0) {
// We are building a graph for a call to a native method.
// All locals are live.
return;
}
ResourceMark rm;
// Consult the liveness information for the locals. If any
// of them are unused, then they can be replaced by top(). This
// should help register allocation time and cut down on the size
// of the deoptimization information.
MethodLivenessResult live_locals = method()->liveness_at_bci(bci());
int len = (int)live_locals.size();
assert(len <= jvms()->loc_size(), "too many live locals");
for (int local = 0; local < len; local++) {
if (!live_locals.at(local)) {
set_local(local, top());
}
}
}
#ifdef ASSERT
//-------------------------dead_locals_are_killed------------------------------
// Return true if all dead locals are set to top in the map.
// Used to assert "clean" debug info at various points.
bool GraphKit::dead_locals_are_killed() {
if (method() == NULL || method()->code_size() == 0) {
// No locals need to be dead, so all is as it should be.
return true;
}
// Make sure somebody called kill_dead_locals upstream.
ResourceMark rm;
for (JVMState* jvms = this->jvms(); jvms != NULL; jvms = jvms->caller()) {
if (jvms->loc_size() == 0) continue; // no locals to consult
SafePointNode* map = jvms->map();
ciMethod* method = jvms->method();
int bci = jvms->bci();
if (jvms == this->jvms()) {
bci = this->bci(); // it might not yet be synched
}
MethodLivenessResult live_locals = method->liveness_at_bci(bci);
int len = (int)live_locals.size();
if (!live_locals.is_valid() || len == 0)
// This method is trivial, or is poisoned by a breakpoint.
return true;
assert(len == jvms->loc_size(), "live map consistent with locals map");
for (int local = 0; local < len; local++) {
if (!live_locals.at(local) && map->local(jvms, local) != top()) {
if (PrintMiscellaneous && (Verbose || WizardMode)) {
tty->print_cr("Zombie local %d: ", local);
jvms->dump();
}
return false;
}
}
}
return true;
}
#endif //ASSERT
// Helper function for enforcing certain bytecodes to reexecute if deoptimization happens.
static bool should_reexecute_implied_by_bytecode(JVMState *jvms, bool is_anewarray) {
ciMethod* cur_method = jvms->method();
int cur_bci = jvms->bci();
if (cur_method != NULL && cur_bci != InvocationEntryBci) {
Bytecodes::Code code = cur_method->java_code_at_bci(cur_bci);
return Interpreter::bytecode_should_reexecute(code) ||
(is_anewarray && code == Bytecodes::_multianewarray);
// Reexecute _multianewarray bytecode which was replaced with
// sequence of [a]newarray. See Parse::do_multianewarray().
//
// Note: interpreter should not have it set since this optimization
// is limited by dimensions and guarded by flag so in some cases
// multianewarray() runtime calls will be generated and
// the bytecode should not be reexecutes (stack will not be reset).
} else {
return false;
}
}
// Helper function for adding JVMState and debug information to node
void GraphKit::add_safepoint_edges(SafePointNode* call, bool must_throw) {
// Add the safepoint edges to the call (or other safepoint).
// Make sure dead locals are set to top. This
// should help register allocation time and cut down on the size
// of the deoptimization information.
assert(dead_locals_are_killed(), "garbage in debug info before safepoint");
// Walk the inline list to fill in the correct set of JVMState's
// Also fill in the associated edges for each JVMState.
// If the bytecode needs to be reexecuted we need to put
// the arguments back on the stack.
const bool should_reexecute = jvms()->should_reexecute();
JVMState* youngest_jvms = should_reexecute ? sync_jvms_for_reexecute() : sync_jvms();
// NOTE: set_bci (called from sync_jvms) might reset the reexecute bit to
// undefined if the bci is different. This is normal for Parse but it
// should not happen for LibraryCallKit because only one bci is processed.
assert(!is_LibraryCallKit() || (jvms()->should_reexecute() == should_reexecute),
"in LibraryCallKit the reexecute bit should not change");
// If we are guaranteed to throw, we can prune everything but the
// input to the current bytecode.
bool can_prune_locals = false;
uint stack_slots_not_pruned = 0;
int inputs = 0, depth = 0;
if (must_throw) {
assert(method() == youngest_jvms->method(), "sanity");
if (compute_stack_effects(inputs, depth)) {
can_prune_locals = true;
stack_slots_not_pruned = inputs;
}
}
if (env()->should_retain_local_variables()) {
// At any safepoint, this method can get breakpointed, which would
// then require an immediate deoptimization.
can_prune_locals = false; // do not prune locals
stack_slots_not_pruned = 0;
}
// do not scribble on the input jvms
JVMState* out_jvms = youngest_jvms->clone_deep(C);
call->set_jvms(out_jvms); // Start jvms list for call node
// For a known set of bytecodes, the interpreter should reexecute them if
// deoptimization happens. We set the reexecute state for them here
if (out_jvms->is_reexecute_undefined() && //don't change if already specified
should_reexecute_implied_by_bytecode(out_jvms, call->is_AllocateArray())) {
#ifdef ASSERT
int inputs = 0, not_used; // initialized by GraphKit::compute_stack_effects()
assert(method() == youngest_jvms->method(), "sanity");
assert(compute_stack_effects(inputs, not_used), "unknown bytecode: %s", Bytecodes::name(java_bc()));
assert(out_jvms->sp() >= (uint)inputs, "not enough operands for reexecution");
#endif // ASSERT
out_jvms->set_should_reexecute(true); //NOTE: youngest_jvms not changed
}
// Presize the call:
DEBUG_ONLY(uint non_debug_edges = call->req());
call->add_req_batch(top(), youngest_jvms->debug_depth());
assert(call->req() == non_debug_edges + youngest_jvms->debug_depth(), "");
// Set up edges so that the call looks like this:
// Call [state:] ctl io mem fptr retadr
// [parms:] parm0 ... parmN
// [root:] loc0 ... locN stk0 ... stkSP mon0 obj0 ... monN objN
// [...mid:] loc0 ... locN stk0 ... stkSP mon0 obj0 ... monN objN [...]
// [young:] loc0 ... locN stk0 ... stkSP mon0 obj0 ... monN objN
// Note that caller debug info precedes callee debug info.
// Fill pointer walks backwards from "young:" to "root:" in the diagram above:
uint debug_ptr = call->req();
// Loop over the map input edges associated with jvms, add them
// to the call node, & reset all offsets to match call node array.
for (JVMState* in_jvms = youngest_jvms; in_jvms != NULL; ) {
uint debug_end = debug_ptr;
uint debug_start = debug_ptr - in_jvms->debug_size();
debug_ptr = debug_start; // back up the ptr
uint p = debug_start; // walks forward in [debug_start, debug_end)
uint j, k, l;
SafePointNode* in_map = in_jvms->map();
out_jvms->set_map(call);
if (can_prune_locals) {
assert(in_jvms->method() == out_jvms->method(), "sanity");
// If the current throw can reach an exception handler in this JVMS,
// then we must keep everything live that can reach that handler.
// As a quick and dirty approximation, we look for any handlers at all.
if (in_jvms->method()->has_exception_handlers()) {
can_prune_locals = false;
}
}
// Add the Locals
k = in_jvms->locoff();
l = in_jvms->loc_size();
out_jvms->set_locoff(p);
if (!can_prune_locals) {
for (j = 0; j < l; j++)
call->set_req(p++, in_map->in(k+j));
} else {
p += l; // already set to top above by add_req_batch
}
// Add the Expression Stack
k = in_jvms->stkoff();
l = in_jvms->sp();
out_jvms->set_stkoff(p);
if (!can_prune_locals) {
for (j = 0; j < l; j++)
call->set_req(p++, in_map->in(k+j));
} else if (can_prune_locals && stack_slots_not_pruned != 0) {
// Divide stack into {S0,...,S1}, where S0 is set to top.
uint s1 = stack_slots_not_pruned;
stack_slots_not_pruned = 0; // for next iteration
if (s1 > l) s1 = l;
uint s0 = l - s1;
p += s0; // skip the tops preinstalled by add_req_batch
for (j = s0; j < l; j++)
call->set_req(p++, in_map->in(k+j));
} else {
p += l; // already set to top above by add_req_batch
}
// Add the Monitors
k = in_jvms->monoff();
l = in_jvms->mon_size();
out_jvms->set_monoff(p);
for (j = 0; j < l; j++)
call->set_req(p++, in_map->in(k+j));
// Copy any scalar object fields.
k = in_jvms->scloff();
l = in_jvms->scl_size();
out_jvms->set_scloff(p);
for (j = 0; j < l; j++)
call->set_req(p++, in_map->in(k+j));
// Finish the new jvms.
out_jvms->set_endoff(p);
assert(out_jvms->endoff() == debug_end, "fill ptr must match");
assert(out_jvms->depth() == in_jvms->depth(), "depth must match");
assert(out_jvms->loc_size() == in_jvms->loc_size(), "size must match");
assert(out_jvms->mon_size() == in_jvms->mon_size(), "size must match");
assert(out_jvms->scl_size() == in_jvms->scl_size(), "size must match");
assert(out_jvms->debug_size() == in_jvms->debug_size(), "size must match");
// Update the two tail pointers in parallel.
out_jvms = out_jvms->caller();