-
Notifications
You must be signed in to change notification settings - Fork 5.8k
/
Copy pathinterpreterRuntime.cpp
1518 lines (1336 loc) · 64.2 KB
/
interpreterRuntime.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) 1997, 2025, 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 "classfile/javaClasses.inline.hpp"
#include "classfile/symbolTable.hpp"
#include "classfile/vmClasses.hpp"
#include "classfile/vmSymbols.hpp"
#include "code/codeCache.hpp"
#include "compiler/compilationPolicy.hpp"
#include "compiler/compileBroker.hpp"
#include "compiler/disassembler.hpp"
#include "gc/shared/barrierSetNMethod.hpp"
#include "gc/shared/collectedHeap.hpp"
#include "interpreter/bytecodeTracer.hpp"
#include "interpreter/interpreter.hpp"
#include "interpreter/interpreterRuntime.hpp"
#include "interpreter/linkResolver.hpp"
#include "interpreter/templateTable.hpp"
#include "jvm_io.h"
#include "logging/log.hpp"
#include "memory/oopFactory.hpp"
#include "memory/resourceArea.hpp"
#include "memory/universe.hpp"
#include "oops/constantPool.inline.hpp"
#include "oops/cpCache.inline.hpp"
#include "oops/instanceKlass.inline.hpp"
#include "oops/klass.inline.hpp"
#include "oops/methodData.hpp"
#include "oops/method.inline.hpp"
#include "oops/objArrayKlass.hpp"
#include "oops/objArrayOop.inline.hpp"
#include "oops/oop.inline.hpp"
#include "oops/symbol.hpp"
#include "prims/jvmtiExport.hpp"
#include "prims/methodHandles.hpp"
#include "prims/nativeLookup.hpp"
#include "runtime/atomic.hpp"
#include "runtime/continuation.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/fieldDescriptor.inline.hpp"
#include "runtime/frame.inline.hpp"
#include "runtime/handles.inline.hpp"
#include "runtime/icache.hpp"
#include "runtime/interfaceSupport.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/jfieldIDWorkaround.hpp"
#include "runtime/osThread.hpp"
#include "runtime/sharedRuntime.hpp"
#include "runtime/stackWatermarkSet.hpp"
#include "runtime/stubRoutines.hpp"
#include "runtime/synchronizer.inline.hpp"
#include "runtime/threadCritical.hpp"
#include "utilities/align.hpp"
#include "utilities/checkedCast.hpp"
#include "utilities/copy.hpp"
#include "utilities/events.hpp"
// Helper class to access current interpreter state
class LastFrameAccessor : public StackObj {
frame _last_frame;
public:
LastFrameAccessor(JavaThread* current) {
assert(current == Thread::current(), "sanity");
_last_frame = current->last_frame();
}
bool is_interpreted_frame() const { return _last_frame.is_interpreted_frame(); }
Method* method() const { return _last_frame.interpreter_frame_method(); }
address bcp() const { return _last_frame.interpreter_frame_bcp(); }
int bci() const { return _last_frame.interpreter_frame_bci(); }
address mdp() const { return _last_frame.interpreter_frame_mdp(); }
void set_bcp(address bcp) { _last_frame.interpreter_frame_set_bcp(bcp); }
void set_mdp(address dp) { _last_frame.interpreter_frame_set_mdp(dp); }
// pass method to avoid calling unsafe bcp_to_method (partial fix 4926272)
Bytecodes::Code code() const { return Bytecodes::code_at(method(), bcp()); }
Bytecode bytecode() const { return Bytecode(method(), bcp()); }
int get_index_u1(Bytecodes::Code bc) const { return bytecode().get_index_u1(bc); }
int get_index_u2(Bytecodes::Code bc) const { return bytecode().get_index_u2(bc); }
int get_index_u4(Bytecodes::Code bc) const { return bytecode().get_index_u4(bc); }
int number_of_dimensions() const { return bcp()[3]; }
oop callee_receiver(Symbol* signature) {
return _last_frame.interpreter_callee_receiver(signature);
}
BasicObjectLock* monitor_begin() const {
return _last_frame.interpreter_frame_monitor_begin();
}
BasicObjectLock* monitor_end() const {
return _last_frame.interpreter_frame_monitor_end();
}
BasicObjectLock* next_monitor(BasicObjectLock* current) const {
return _last_frame.next_monitor_in_interpreter_frame(current);
}
frame& get_frame() { return _last_frame; }
};
//------------------------------------------------------------------------------------------------------------------------
// State accessors
void InterpreterRuntime::set_bcp_and_mdp(address bcp, JavaThread* current) {
LastFrameAccessor last_frame(current);
last_frame.set_bcp(bcp);
if (ProfileInterpreter) {
// ProfileTraps uses MDOs independently of ProfileInterpreter.
// That is why we must check both ProfileInterpreter and mdo != nullptr.
MethodData* mdo = last_frame.method()->method_data();
if (mdo != nullptr) {
NEEDS_CLEANUP;
last_frame.set_mdp(mdo->bci_to_dp(last_frame.bci()));
}
}
}
//------------------------------------------------------------------------------------------------------------------------
// Constants
JRT_ENTRY(void, InterpreterRuntime::ldc(JavaThread* current, bool wide))
// access constant pool
LastFrameAccessor last_frame(current);
ConstantPool* pool = last_frame.method()->constants();
int cp_index = wide ? last_frame.get_index_u2(Bytecodes::_ldc_w) : last_frame.get_index_u1(Bytecodes::_ldc);
constantTag tag = pool->tag_at(cp_index);
assert (tag.is_unresolved_klass() || tag.is_klass(), "wrong ldc call");
Klass* klass = pool->klass_at(cp_index, CHECK);
oop java_class = klass->java_mirror();
current->set_vm_result_oop(java_class);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::resolve_ldc(JavaThread* current, Bytecodes::Code bytecode)) {
assert(bytecode == Bytecodes::_ldc ||
bytecode == Bytecodes::_ldc_w ||
bytecode == Bytecodes::_ldc2_w ||
bytecode == Bytecodes::_fast_aldc ||
bytecode == Bytecodes::_fast_aldc_w, "wrong bc");
ResourceMark rm(current);
const bool is_fast_aldc = (bytecode == Bytecodes::_fast_aldc ||
bytecode == Bytecodes::_fast_aldc_w);
LastFrameAccessor last_frame(current);
methodHandle m (current, last_frame.method());
Bytecode_loadconstant ldc(m, last_frame.bci());
// Double-check the size. (Condy can have any type.)
BasicType type = ldc.result_type();
switch (type2size[type]) {
case 2: guarantee(bytecode == Bytecodes::_ldc2_w, ""); break;
case 1: guarantee(bytecode != Bytecodes::_ldc2_w, ""); break;
default: ShouldNotReachHere();
}
// Resolve the constant. This does not do unboxing.
// But it does replace Universe::the_null_sentinel by null.
oop result = ldc.resolve_constant(CHECK);
assert(result != nullptr || is_fast_aldc, "null result only valid for fast_aldc");
#ifdef ASSERT
{
// The bytecode wrappers aren't GC-safe so construct a new one
Bytecode_loadconstant ldc2(m, last_frame.bci());
int rindex = ldc2.cache_index();
if (rindex < 0)
rindex = m->constants()->cp_to_object_index(ldc2.pool_index());
if (rindex >= 0) {
oop coop = m->constants()->resolved_reference_at(rindex);
oop roop = (result == nullptr ? Universe::the_null_sentinel() : result);
assert(roop == coop, "expected result for assembly code");
}
}
#endif
current->set_vm_result_oop(result);
if (!is_fast_aldc) {
// Tell the interpreter how to unbox the primitive.
guarantee(java_lang_boxing_object::is_instance(result, type), "");
int offset = java_lang_boxing_object::value_offset(type);
intptr_t flags = ((as_TosState(type) << ConstantPoolCache::tos_state_shift)
| (offset & ConstantPoolCache::field_index_mask));
current->set_vm_result_metadata((Metadata*)flags);
}
}
JRT_END
//------------------------------------------------------------------------------------------------------------------------
// Allocation
JRT_ENTRY(void, InterpreterRuntime::_new(JavaThread* current, ConstantPool* pool, int index))
Klass* k = pool->klass_at(index, CHECK);
InstanceKlass* klass = InstanceKlass::cast(k);
// Make sure we are not instantiating an abstract klass
klass->check_valid_for_instantiation(true, CHECK);
// Make sure klass is initialized
klass->initialize(CHECK);
oop obj = klass->allocate_instance(CHECK);
current->set_vm_result_oop(obj);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::newarray(JavaThread* current, BasicType type, jint size))
oop obj = oopFactory::new_typeArray(type, size, CHECK);
current->set_vm_result_oop(obj);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::anewarray(JavaThread* current, ConstantPool* pool, int index, jint size))
Klass* klass = pool->klass_at(index, CHECK);
objArrayOop obj = oopFactory::new_objArray(klass, size, CHECK);
current->set_vm_result_oop(obj);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::multianewarray(JavaThread* current, jint* first_size_address))
// We may want to pass in more arguments - could make this slightly faster
LastFrameAccessor last_frame(current);
ConstantPool* constants = last_frame.method()->constants();
int i = last_frame.get_index_u2(Bytecodes::_multianewarray);
Klass* klass = constants->klass_at(i, CHECK);
int nof_dims = last_frame.number_of_dimensions();
assert(klass->is_klass(), "not a class");
assert(nof_dims >= 1, "multianewarray rank must be nonzero");
// We must create an array of jints to pass to multi_allocate.
ResourceMark rm(current);
const int small_dims = 10;
jint dim_array[small_dims];
jint *dims = &dim_array[0];
if (nof_dims > small_dims) {
dims = (jint*) NEW_RESOURCE_ARRAY(jint, nof_dims);
}
for (int index = 0; index < nof_dims; index++) {
// offset from first_size_address is addressed as local[index]
int n = Interpreter::local_offset_in_bytes(index)/jintSize;
dims[index] = first_size_address[n];
}
oop obj = ArrayKlass::cast(klass)->multi_allocate(nof_dims, dims, CHECK);
current->set_vm_result_oop(obj);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::register_finalizer(JavaThread* current, oopDesc* obj))
assert(oopDesc::is_oop(obj), "must be a valid oop");
assert(obj->klass()->has_finalizer(), "shouldn't be here otherwise");
InstanceKlass::register_finalizer(instanceOop(obj), CHECK);
JRT_END
// Quicken instance-of and check-cast bytecodes
JRT_ENTRY(void, InterpreterRuntime::quicken_io_cc(JavaThread* current))
// Force resolving; quicken the bytecode
LastFrameAccessor last_frame(current);
int which = last_frame.get_index_u2(Bytecodes::_checkcast);
ConstantPool* cpool = last_frame.method()->constants();
// We'd expect to assert that we're only here to quicken bytecodes, but in a multithreaded
// program we might have seen an unquick'd bytecode in the interpreter but have another
// thread quicken the bytecode before we get here.
// assert( cpool->tag_at(which).is_unresolved_klass(), "should only come here to quicken bytecodes" );
Klass* klass = cpool->klass_at(which, CHECK);
current->set_vm_result_metadata(klass);
JRT_END
//------------------------------------------------------------------------------------------------------------------------
// Exceptions
void InterpreterRuntime::note_trap_inner(JavaThread* current, int reason,
const methodHandle& trap_method, int trap_bci) {
if (trap_method.not_null()) {
MethodData* trap_mdo = trap_method->method_data();
if (trap_mdo == nullptr) {
ExceptionMark em(current);
JavaThread* THREAD = current; // For exception macros.
Method::build_profiling_method_data(trap_method, THREAD);
if (HAS_PENDING_EXCEPTION) {
// Only metaspace OOM is expected. No Java code executed.
assert((PENDING_EXCEPTION->is_a(vmClasses::OutOfMemoryError_klass())),
"we expect only an OOM error here");
CLEAR_PENDING_EXCEPTION;
}
trap_mdo = trap_method->method_data();
// and fall through...
}
if (trap_mdo != nullptr) {
// Update per-method count of trap events. The interpreter
// is updating the MDO to simulate the effect of compiler traps.
Deoptimization::update_method_data_from_interpreter(trap_mdo, trap_bci, reason);
}
}
}
// Assume the compiler is (or will be) interested in this event.
// If necessary, create an MDO to hold the information, and record it.
void InterpreterRuntime::note_trap(JavaThread* current, int reason) {
assert(ProfileTraps, "call me only if profiling");
LastFrameAccessor last_frame(current);
methodHandle trap_method(current, last_frame.method());
int trap_bci = trap_method->bci_from(last_frame.bcp());
note_trap_inner(current, reason, trap_method, trap_bci);
}
static Handle get_preinitialized_exception(Klass* k, TRAPS) {
// get klass
InstanceKlass* klass = InstanceKlass::cast(k);
assert(klass->is_initialized(),
"this klass should have been initialized during VM initialization");
// create instance - do not call constructor since we may have no
// (java) stack space left (should assert constructor is empty)
Handle exception;
oop exception_oop = klass->allocate_instance(CHECK_(exception));
exception = Handle(THREAD, exception_oop);
if (StackTraceInThrowable) {
java_lang_Throwable::fill_in_stack_trace(exception);
}
return exception;
}
// Special handling for stack overflow: since we don't have any (java) stack
// space left we use the pre-allocated & pre-initialized StackOverflowError
// klass to create an stack overflow error instance. We do not call its
// constructor for the same reason (it is empty, anyway).
JRT_ENTRY(void, InterpreterRuntime::throw_StackOverflowError(JavaThread* current))
Handle exception = get_preinitialized_exception(
vmClasses::StackOverflowError_klass(),
CHECK);
// Increment counter for hs_err file reporting
Atomic::inc(&Exceptions::_stack_overflow_errors);
// Remove the ScopedValue bindings in case we got a StackOverflowError
// while we were trying to manipulate ScopedValue bindings.
current->clear_scopedValueBindings();
THROW_HANDLE(exception);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_delayed_StackOverflowError(JavaThread* current))
Handle exception = get_preinitialized_exception(
vmClasses::StackOverflowError_klass(),
CHECK);
java_lang_Throwable::set_message(exception(),
Universe::delayed_stack_overflow_error_message());
// Increment counter for hs_err file reporting
Atomic::inc(&Exceptions::_stack_overflow_errors);
// Remove the ScopedValue bindings in case we got a StackOverflowError
// while we were trying to manipulate ScopedValue bindings.
current->clear_scopedValueBindings();
THROW_HANDLE(exception);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::create_exception(JavaThread* current, char* name, char* message))
// lookup exception klass
TempNewSymbol s = SymbolTable::new_symbol(name);
if (ProfileTraps) {
if (s == vmSymbols::java_lang_ArithmeticException()) {
note_trap(current, Deoptimization::Reason_div0_check);
} else if (s == vmSymbols::java_lang_NullPointerException()) {
note_trap(current, Deoptimization::Reason_null_check);
}
}
// create exception
Handle exception = Exceptions::new_exception(current, s, message);
current->set_vm_result_oop(exception());
JRT_END
JRT_ENTRY(void, InterpreterRuntime::create_klass_exception(JavaThread* current, char* name, oopDesc* obj))
// Produce the error message first because note_trap can safepoint
ResourceMark rm(current);
const char* klass_name = obj->klass()->external_name();
// lookup exception klass
TempNewSymbol s = SymbolTable::new_symbol(name);
if (ProfileTraps) {
if (s == vmSymbols::java_lang_ArrayStoreException()) {
note_trap(current, Deoptimization::Reason_array_check);
} else {
note_trap(current, Deoptimization::Reason_class_check);
}
}
// create exception, with klass name as detail message
Handle exception = Exceptions::new_exception(current, s, klass_name);
current->set_vm_result_oop(exception());
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_ArrayIndexOutOfBoundsException(JavaThread* current, arrayOopDesc* a, jint index))
// Produce the error message first because note_trap can safepoint
ResourceMark rm(current);
stringStream ss;
ss.print("Index %d out of bounds for length %d", index, a->length());
if (ProfileTraps) {
note_trap(current, Deoptimization::Reason_range_check);
}
THROW_MSG(vmSymbols::java_lang_ArrayIndexOutOfBoundsException(), ss.as_string());
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_ClassCastException(
JavaThread* current, oopDesc* obj))
// Produce the error message first because note_trap can safepoint
ResourceMark rm(current);
char* message = SharedRuntime::generate_class_cast_message(
current, obj->klass());
if (ProfileTraps) {
note_trap(current, Deoptimization::Reason_class_check);
}
// create exception
THROW_MSG(vmSymbols::java_lang_ClassCastException(), message);
JRT_END
// exception_handler_for_exception(...) returns the continuation address,
// the exception oop (via TLS) and sets the bci/bcp for the continuation.
// The exception oop is returned to make sure it is preserved over GC (it
// is only on the stack if the exception was thrown explicitly via athrow).
// During this operation, the expression stack contains the values for the
// bci where the exception happened. If the exception was propagated back
// from a call, the expression stack contains the values for the bci at the
// invoke w/o arguments (i.e., as if one were inside the call).
// Note that the implementation of this method assumes it's only called when an exception has actually occured
JRT_ENTRY(address, InterpreterRuntime::exception_handler_for_exception(JavaThread* current, oopDesc* exception))
// We get here after we have unwound from a callee throwing an exception
// into the interpreter. Any deferred stack processing is notified of
// the event via the StackWatermarkSet.
StackWatermarkSet::after_unwind(current);
LastFrameAccessor last_frame(current);
Handle h_exception(current, exception);
methodHandle h_method (current, last_frame.method());
constantPoolHandle h_constants(current, h_method->constants());
bool should_repeat;
int handler_bci;
int current_bci = last_frame.bci();
if (current->frames_to_pop_failed_realloc() > 0) {
// Allocation of scalar replaced object used in this frame
// failed. Unconditionally pop the frame.
current->dec_frames_to_pop_failed_realloc();
current->set_vm_result_oop(h_exception());
// If the method is synchronized we already unlocked the monitor
// during deoptimization so the interpreter needs to skip it when
// the frame is popped.
current->set_do_not_unlock_if_synchronized(true);
return Interpreter::remove_activation_entry();
}
// Need to do this check first since when _do_not_unlock_if_synchronized
// is set, we don't want to trigger any classloading which may make calls
// into java, or surprisingly find a matching exception handler for bci 0
// since at this moment the method hasn't been "officially" entered yet.
if (current->do_not_unlock_if_synchronized()) {
ResourceMark rm;
assert(current_bci == 0, "bci isn't zero for do_not_unlock_if_synchronized");
current->set_vm_result_oop(exception);
return Interpreter::remove_activation_entry();
}
do {
should_repeat = false;
// assertions
assert(h_exception.not_null(), "null exceptions should be handled by athrow");
// Check that exception is a subclass of Throwable.
assert(h_exception->is_a(vmClasses::Throwable_klass()),
"Exception not subclass of Throwable");
// tracing
if (log_is_enabled(Info, exceptions)) {
ResourceMark rm(current);
stringStream tempst;
tempst.print("interpreter method <%s>\n"
" at bci %d for thread " INTPTR_FORMAT " (%s)",
h_method->print_value_string(), current_bci, p2i(current), current->name());
Exceptions::log_exception(h_exception, tempst.as_string());
}
// Don't go paging in something which won't be used.
// else if (extable->length() == 0) {
// // disabled for now - interpreter is not using shortcut yet
// // (shortcut is not to call runtime if we have no exception handlers)
// // warning("performance bug: should not call runtime if method has no exception handlers");
// }
// for AbortVMOnException flag
Exceptions::debug_check_abort(h_exception);
// exception handler lookup
Klass* klass = h_exception->klass();
handler_bci = Method::fast_exception_handler_bci_for(h_method, klass, current_bci, THREAD);
if (HAS_PENDING_EXCEPTION) {
// We threw an exception while trying to find the exception handler.
// Transfer the new exception to the exception handle which will
// be set into thread local storage, and do another lookup for an
// exception handler for this exception, this time starting at the
// BCI of the exception handler which caused the exception to be
// thrown (bug 4307310).
h_exception = Handle(THREAD, PENDING_EXCEPTION);
CLEAR_PENDING_EXCEPTION;
if (handler_bci >= 0) {
current_bci = handler_bci;
should_repeat = true;
}
}
} while (should_repeat == true);
#if INCLUDE_JVMCI
if (EnableJVMCI && h_method->method_data() != nullptr) {
ResourceMark rm(current);
MethodData* mdo = h_method->method_data();
// Lock to read ProfileData, and ensure lock is not broken by a safepoint
MutexLocker ml(mdo->extra_data_lock(), Mutex::_no_safepoint_check_flag);
ProfileData* pdata = mdo->allocate_bci_to_data(current_bci, nullptr);
if (pdata != nullptr && pdata->is_BitData()) {
BitData* bit_data = (BitData*) pdata;
bit_data->set_exception_seen();
}
}
#endif
// notify JVMTI of an exception throw; JVMTI will detect if this is a first
// time throw or a stack unwinding throw and accordingly notify the debugger
if (JvmtiExport::can_post_on_exceptions()) {
JvmtiExport::post_exception_throw(current, h_method(), last_frame.bcp(), h_exception());
}
address continuation = nullptr;
address handler_pc = nullptr;
if (handler_bci < 0 || !current->stack_overflow_state()->reguard_stack((address) &continuation)) {
// Forward exception to callee (leaving bci/bcp untouched) because (a) no
// handler in this method, or (b) after a stack overflow there is not yet
// enough stack space available to reprotect the stack.
continuation = Interpreter::remove_activation_entry();
#if COMPILER2_OR_JVMCI
// Count this for compilation purposes
h_method->interpreter_throwout_increment(THREAD);
#endif
} else {
// handler in this method => change bci/bcp to handler bci/bcp and continue there
handler_pc = h_method->code_base() + handler_bci;
h_method->set_exception_handler_entered(handler_bci); // profiling
#ifndef ZERO
set_bcp_and_mdp(handler_pc, current);
continuation = Interpreter::dispatch_table(vtos)[*handler_pc];
#else
continuation = (address)(intptr_t) handler_bci;
#endif
}
// notify debugger of an exception catch
// (this is good for exceptions caught in native methods as well)
if (JvmtiExport::can_post_on_exceptions()) {
JvmtiExport::notice_unwind_due_to_exception(current, h_method(), handler_pc, h_exception(), (handler_pc != nullptr));
}
current->set_vm_result_oop(h_exception());
return continuation;
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_pending_exception(JavaThread* current))
assert(current->has_pending_exception(), "must only be called if there's an exception pending");
// nothing to do - eventually we should remove this code entirely (see comments @ call sites)
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_AbstractMethodError(JavaThread* current))
THROW(vmSymbols::java_lang_AbstractMethodError());
JRT_END
// This method is called from the "abstract_entry" of the interpreter.
// At that point, the arguments have already been removed from the stack
// and therefore we don't have the receiver object at our fingertips. (Though,
// on some platforms the receiver still resides in a register...). Thus,
// we have no choice but print an error message not containing the receiver
// type.
JRT_ENTRY(void, InterpreterRuntime::throw_AbstractMethodErrorWithMethod(JavaThread* current,
Method* missingMethod))
ResourceMark rm(current);
assert(missingMethod != nullptr, "sanity");
methodHandle m(current, missingMethod);
LinkResolver::throw_abstract_method_error(m, THREAD);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_AbstractMethodErrorVerbose(JavaThread* current,
Klass* recvKlass,
Method* missingMethod))
ResourceMark rm(current);
methodHandle mh = methodHandle(current, missingMethod);
LinkResolver::throw_abstract_method_error(mh, recvKlass, THREAD);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_IncompatibleClassChangeError(JavaThread* current))
THROW(vmSymbols::java_lang_IncompatibleClassChangeError());
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_IncompatibleClassChangeErrorVerbose(JavaThread* current,
Klass* recvKlass,
Klass* interfaceKlass))
ResourceMark rm(current);
char buf[1000];
buf[0] = '\0';
jio_snprintf(buf, sizeof(buf),
"Class %s does not implement the requested interface %s",
recvKlass ? recvKlass->external_name() : "nullptr",
interfaceKlass ? interfaceKlass->external_name() : "nullptr");
THROW_MSG(vmSymbols::java_lang_IncompatibleClassChangeError(), buf);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_NullPointerException(JavaThread* current))
THROW(vmSymbols::java_lang_NullPointerException());
JRT_END
//------------------------------------------------------------------------------------------------------------------------
// Fields
//
void InterpreterRuntime::resolve_get_put(JavaThread* current, Bytecodes::Code bytecode) {
LastFrameAccessor last_frame(current);
constantPoolHandle pool(current, last_frame.method()->constants());
methodHandle m(current, last_frame.method());
resolve_get_put(bytecode, last_frame.get_index_u2(bytecode), m, pool, true /*initialize_holder*/, current);
}
void InterpreterRuntime::resolve_get_put(Bytecodes::Code bytecode, int field_index,
methodHandle& m,
constantPoolHandle& pool,
bool initialize_holder, TRAPS) {
fieldDescriptor info;
bool is_put = (bytecode == Bytecodes::_putfield || bytecode == Bytecodes::_nofast_putfield ||
bytecode == Bytecodes::_putstatic);
bool is_static = (bytecode == Bytecodes::_getstatic || bytecode == Bytecodes::_putstatic);
{
JvmtiHideSingleStepping jhss(THREAD);
LinkResolver::resolve_field_access(info, pool, field_index,
m, bytecode, initialize_holder, CHECK);
} // end JvmtiHideSingleStepping
// check if link resolution caused cpCache to be updated
if (pool->resolved_field_entry_at(field_index)->is_resolved(bytecode)) return;
// compute auxiliary field attributes
TosState state = as_TosState(info.field_type());
// Resolution of put instructions on final fields is delayed. That is required so that
// exceptions are thrown at the correct place (when the instruction is actually invoked).
// If we do not resolve an instruction in the current pass, leaving the put_code
// set to zero will cause the next put instruction to the same field to reresolve.
// Resolution of put instructions to final instance fields with invalid updates (i.e.,
// to final instance fields with updates originating from a method different than <init>)
// is inhibited. A putfield instruction targeting an instance final field must throw
// an IllegalAccessError if the instruction is not in an instance
// initializer method <init>. If resolution were not inhibited, a putfield
// in an initializer method could be resolved in the initializer. Subsequent
// putfield instructions to the same field would then use cached information.
// As a result, those instructions would not pass through the VM. That is,
// checks in resolve_field_access() would not be executed for those instructions
// and the required IllegalAccessError would not be thrown.
//
// Also, we need to delay resolving getstatic and putstatic instructions until the
// class is initialized. This is required so that access to the static
// field will call the initialization function every time until the class
// is completely initialized ala. in 2.17.5 in JVM Specification.
InstanceKlass* klass = info.field_holder();
bool uninitialized_static = is_static && !klass->is_initialized();
bool has_initialized_final_update = info.field_holder()->major_version() >= 53 &&
info.has_initialized_final_update();
assert(!(has_initialized_final_update && !info.access_flags().is_final()), "Fields with initialized final updates must be final");
Bytecodes::Code get_code = (Bytecodes::Code)0;
Bytecodes::Code put_code = (Bytecodes::Code)0;
if (!uninitialized_static) {
get_code = ((is_static) ? Bytecodes::_getstatic : Bytecodes::_getfield);
if ((is_put && !has_initialized_final_update) || !info.access_flags().is_final()) {
put_code = ((is_static) ? Bytecodes::_putstatic : Bytecodes::_putfield);
}
}
ResolvedFieldEntry* entry = pool->resolved_field_entry_at(field_index);
entry->set_flags(info.access_flags().is_final(), info.access_flags().is_volatile());
entry->fill_in(info.field_holder(), info.offset(),
checked_cast<u2>(info.index()), checked_cast<u1>(state),
static_cast<u1>(get_code), static_cast<u1>(put_code));
}
//------------------------------------------------------------------------------------------------------------------------
// Synchronization
//
// The interpreter's synchronization code is factored out so that it can
// be shared by method invocation and synchronized blocks.
//%note synchronization_3
//%note monitor_1
JRT_ENTRY_NO_ASYNC(void, InterpreterRuntime::monitorenter(JavaThread* current, BasicObjectLock* elem))
#ifdef ASSERT
current->last_frame().interpreter_frame_verify_monitor(elem);
#endif
Handle h_obj(current, elem->obj());
assert(Universe::heap()->is_in_or_null(h_obj()),
"must be null or an object");
ObjectSynchronizer::enter(h_obj, elem->lock(), current);
assert(Universe::heap()->is_in_or_null(elem->obj()),
"must be null or an object");
#ifdef ASSERT
if (!current->preempting()) current->last_frame().interpreter_frame_verify_monitor(elem);
#endif
JRT_END
JRT_LEAF(void, InterpreterRuntime::monitorexit(BasicObjectLock* elem))
oop obj = elem->obj();
assert(Universe::heap()->is_in(obj), "must be an object");
// The object could become unlocked through a JNI call, which we have no other checks for.
// Give a fatal message if CheckJNICalls. Otherwise we ignore it.
if (obj->is_unlocked()) {
if (CheckJNICalls) {
fatal("Object has been unlocked by JNI");
}
return;
}
ObjectSynchronizer::exit(obj, elem->lock(), JavaThread::current());
// Free entry. If it is not cleared, the exception handling code will try to unlock the monitor
// again at method exit or in the case of an exception.
elem->set_obj(nullptr);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::throw_illegal_monitor_state_exception(JavaThread* current))
THROW(vmSymbols::java_lang_IllegalMonitorStateException());
JRT_END
JRT_ENTRY(void, InterpreterRuntime::new_illegal_monitor_state_exception(JavaThread* current))
// Returns an illegal exception to install into the current thread. The
// pending_exception flag is cleared so normal exception handling does not
// trigger. Any current installed exception will be overwritten. This
// method will be called during an exception unwind.
assert(!HAS_PENDING_EXCEPTION, "no pending exception");
Handle exception(current, current->vm_result_oop());
assert(exception() != nullptr, "vm result should be set");
current->set_vm_result_oop(nullptr); // clear vm result before continuing (may cause memory leaks and assert failures)
exception = get_preinitialized_exception(vmClasses::IllegalMonitorStateException_klass(), CATCH);
current->set_vm_result_oop(exception());
JRT_END
//------------------------------------------------------------------------------------------------------------------------
// Invokes
JRT_ENTRY(Bytecodes::Code, InterpreterRuntime::get_original_bytecode_at(JavaThread* current, Method* method, address bcp))
return method->orig_bytecode_at(method->bci_from(bcp));
JRT_END
JRT_ENTRY(void, InterpreterRuntime::set_original_bytecode_at(JavaThread* current, Method* method, address bcp, Bytecodes::Code new_code))
method->set_orig_bytecode_at(method->bci_from(bcp), new_code);
JRT_END
JRT_ENTRY(void, InterpreterRuntime::_breakpoint(JavaThread* current, Method* method, address bcp))
JvmtiExport::post_raw_breakpoint(current, method, bcp);
JRT_END
void InterpreterRuntime::resolve_invoke(JavaThread* current, Bytecodes::Code bytecode) {
LastFrameAccessor last_frame(current);
// extract receiver from the outgoing argument list if necessary
Handle receiver(current, nullptr);
if (bytecode == Bytecodes::_invokevirtual || bytecode == Bytecodes::_invokeinterface ||
bytecode == Bytecodes::_invokespecial) {
ResourceMark rm(current);
methodHandle m (current, last_frame.method());
Bytecode_invoke call(m, last_frame.bci());
Symbol* signature = call.signature();
receiver = Handle(current, last_frame.callee_receiver(signature));
assert(Universe::heap()->is_in_or_null(receiver()),
"sanity check");
assert(receiver.is_null() ||
!Universe::heap()->is_in(receiver->klass()),
"sanity check");
}
// resolve method
CallInfo info;
constantPoolHandle pool(current, last_frame.method()->constants());
methodHandle resolved_method;
int method_index = last_frame.get_index_u2(bytecode);
{
JvmtiHideSingleStepping jhss(current);
JavaThread* THREAD = current; // For exception macros.
LinkResolver::resolve_invoke(info, receiver, pool,
method_index, bytecode,
THREAD);
if (HAS_PENDING_EXCEPTION) {
if (ProfileTraps && PENDING_EXCEPTION->klass()->name() == vmSymbols::java_lang_NullPointerException()) {
// Preserve the original exception across the call to note_trap()
PreserveExceptionMark pm(current);
// Recording the trap will help the compiler to potentially recognize this exception as "hot"
note_trap(current, Deoptimization::Reason_null_check);
}
return;
}
resolved_method = methodHandle(current, info.resolved_method());
} // end JvmtiHideSingleStepping
update_invoke_cp_cache_entry(info, bytecode, resolved_method, pool, method_index);
}
void InterpreterRuntime::update_invoke_cp_cache_entry(CallInfo& info, Bytecodes::Code bytecode,
methodHandle& resolved_method,
constantPoolHandle& pool,
int method_index) {
// Don't allow safepoints until the method is cached.
NoSafepointVerifier nsv;
// check if link resolution caused cpCache to be updated
ConstantPoolCache* cache = pool->cache();
if (cache->resolved_method_entry_at(method_index)->is_resolved(bytecode)) return;
#ifdef ASSERT
if (bytecode == Bytecodes::_invokeinterface) {
if (resolved_method->method_holder() == vmClasses::Object_klass()) {
// NOTE: THIS IS A FIX FOR A CORNER CASE in the JVM spec
// (see also CallInfo::set_interface for details)
assert(info.call_kind() == CallInfo::vtable_call ||
info.call_kind() == CallInfo::direct_call, "");
assert(resolved_method->is_final() || info.has_vtable_index(),
"should have been set already");
} else if (!resolved_method->has_itable_index()) {
// Resolved something like CharSequence.toString. Use vtable not itable.
assert(info.call_kind() != CallInfo::itable_call, "");
} else {
// Setup itable entry
assert(info.call_kind() == CallInfo::itable_call, "");
int index = resolved_method->itable_index();
assert(info.itable_index() == index, "");
}
} else if (bytecode == Bytecodes::_invokespecial) {
assert(info.call_kind() == CallInfo::direct_call, "must be direct call");
} else {
assert(info.call_kind() == CallInfo::direct_call ||
info.call_kind() == CallInfo::vtable_call, "");
}
#endif
// Get sender and only set cpCache entry to resolved if it is not an
// interface. The receiver for invokespecial calls within interface
// methods must be checked for every call.
InstanceKlass* sender = pool->pool_holder();
switch (info.call_kind()) {
case CallInfo::direct_call:
cache->set_direct_call(bytecode, method_index, resolved_method, sender->is_interface());
break;
case CallInfo::vtable_call:
cache->set_vtable_call(bytecode, method_index, resolved_method, info.vtable_index());
break;
case CallInfo::itable_call:
cache->set_itable_call(
bytecode,
method_index,
info.resolved_klass(),
resolved_method,
info.itable_index());
break;
default: ShouldNotReachHere();
}
}
void InterpreterRuntime::cds_resolve_invoke(Bytecodes::Code bytecode, int method_index,
constantPoolHandle& pool, TRAPS) {
LinkInfo link_info(pool, method_index, bytecode, CHECK);
if (!link_info.resolved_klass()->is_instance_klass() || InstanceKlass::cast(link_info.resolved_klass())->is_linked()) {
CallInfo call_info;
switch (bytecode) {
case Bytecodes::_invokevirtual: LinkResolver::cds_resolve_virtual_call (call_info, link_info, CHECK); break;
case Bytecodes::_invokeinterface: LinkResolver::cds_resolve_interface_call(call_info, link_info, CHECK); break;
case Bytecodes::_invokespecial: LinkResolver::cds_resolve_special_call (call_info, link_info, CHECK); break;
default: fatal("Unimplemented: %s", Bytecodes::name(bytecode));
}
methodHandle resolved_method(THREAD, call_info.resolved_method());
guarantee(resolved_method->method_holder()->is_linked(), "");
update_invoke_cp_cache_entry(call_info, bytecode, resolved_method, pool, method_index);
} else {
// FIXME: why a shared class is not linked yet?
// Can't link it here since there are no guarantees it'll be prelinked on the next run.
ResourceMark rm;
InstanceKlass* resolved_iklass = InstanceKlass::cast(link_info.resolved_klass());
log_info(cds, resolve)("Not resolved: class not linked: %s %s %s",
resolved_iklass->is_shared() ? "is_shared" : "",
resolved_iklass->init_state_name(),
resolved_iklass->external_name());
}
}
// First time execution: Resolve symbols, create a permanent MethodType object.
void InterpreterRuntime::resolve_invokehandle(JavaThread* current) {
const Bytecodes::Code bytecode = Bytecodes::_invokehandle;
LastFrameAccessor last_frame(current);
// resolve method
CallInfo info;
constantPoolHandle pool(current, last_frame.method()->constants());
int method_index = last_frame.get_index_u2(bytecode);
{
JvmtiHideSingleStepping jhss(current);
JavaThread* THREAD = current; // For exception macros.
LinkResolver::resolve_invoke(info, Handle(), pool,
method_index, bytecode,
CHECK);
} // end JvmtiHideSingleStepping
pool->cache()->set_method_handle(method_index, info);
}
void InterpreterRuntime::cds_resolve_invokehandle(int raw_index,
constantPoolHandle& pool, TRAPS) {
const Bytecodes::Code bytecode = Bytecodes::_invokehandle;
CallInfo info;
LinkResolver::resolve_invoke(info, Handle(), pool, raw_index, bytecode, CHECK);
pool->cache()->set_method_handle(raw_index, info);
}
// First time execution: Resolve symbols, create a permanent CallSite object.
void InterpreterRuntime::resolve_invokedynamic(JavaThread* current) {
LastFrameAccessor last_frame(current);
const Bytecodes::Code bytecode = Bytecodes::_invokedynamic;
// resolve method
CallInfo info;
constantPoolHandle pool(current, last_frame.method()->constants());
int index = last_frame.get_index_u4(bytecode);
{
JvmtiHideSingleStepping jhss(current);
JavaThread* THREAD = current; // For exception macros.
LinkResolver::resolve_invoke(info, Handle(), pool,
index, bytecode, CHECK);
} // end JvmtiHideSingleStepping
pool->cache()->set_dynamic_call(info, index);
}
void InterpreterRuntime::cds_resolve_invokedynamic(int raw_index,
constantPoolHandle& pool, TRAPS) {
const Bytecodes::Code bytecode = Bytecodes::_invokedynamic;
CallInfo info;
LinkResolver::resolve_invoke(info, Handle(), pool, raw_index, bytecode, CHECK);
pool->cache()->set_dynamic_call(info, raw_index);
}
// This function is the interface to the assembly code. It returns the resolved
// cpCache entry. This doesn't safepoint, but the helper routines safepoint.
// This function will check for redefinition!
JRT_ENTRY(void, InterpreterRuntime::resolve_from_cache(JavaThread* current, Bytecodes::Code bytecode)) {
switch (bytecode) {
case Bytecodes::_getstatic:
case Bytecodes::_putstatic:
case Bytecodes::_getfield:
case Bytecodes::_putfield:
resolve_get_put(current, bytecode);
break;
case Bytecodes::_invokevirtual:
case Bytecodes::_invokespecial:
case Bytecodes::_invokestatic:
case Bytecodes::_invokeinterface:
resolve_invoke(current, bytecode);
break;