22 *
23 */
24
25 #include "classfile/moduleEntry.hpp"
26 #include "code/codeCache.hpp"
27 #include "code/scopeDesc.hpp"
28 #include "code/vmreg.inline.hpp"
29 #include "compiler/abstractCompiler.hpp"
30 #include "compiler/disassembler.hpp"
31 #include "compiler/oopMap.hpp"
32 #include "gc/shared/collectedHeap.inline.hpp"
33 #include "interpreter/interpreter.hpp"
34 #include "interpreter/oopMapCache.hpp"
35 #include "logging/log.hpp"
36 #include "memory/resourceArea.hpp"
37 #include "memory/universe.hpp"
38 #include "oops/markWord.hpp"
39 #include "oops/method.inline.hpp"
40 #include "oops/methodData.hpp"
41 #include "oops/oop.inline.hpp"
42 #include "oops/stackChunkOop.inline.hpp"
43 #include "oops/verifyOopClosure.hpp"
44 #include "prims/methodHandles.hpp"
45 #include "runtime/continuation.hpp"
46 #include "runtime/continuationEntry.inline.hpp"
47 #include "runtime/frame.inline.hpp"
48 #include "runtime/handles.inline.hpp"
49 #include "runtime/javaCalls.hpp"
50 #include "runtime/javaThread.hpp"
51 #include "runtime/monitorChunk.hpp"
52 #include "runtime/os.hpp"
53 #include "runtime/sharedRuntime.hpp"
54 #include "runtime/safefetch.hpp"
55 #include "runtime/signature.hpp"
56 #include "runtime/stackValue.hpp"
57 #include "runtime/stubCodeGenerator.hpp"
58 #include "runtime/stubRoutines.hpp"
59 #include "utilities/debug.hpp"
60 #include "utilities/decoder.hpp"
61 #include "utilities/formatBuffer.hpp"
62
63 RegisterMap::RegisterMap(JavaThread *thread, UpdateMap update_map, ProcessFrames process_frames, WalkContinuation walk_cont) {
64 _thread = thread;
65 _update_map = update_map == UpdateMap::include;
66 _process_frames = process_frames == ProcessFrames::include;
67 _walk_cont = walk_cont == WalkContinuation::include;
68 clear();
69 DEBUG_ONLY (_update_for_id = nullptr;)
70 NOT_PRODUCT(_skip_missing = false;)
71 NOT_PRODUCT(_async = false;)
72
73 if (walk_cont == WalkContinuation::include && thread != nullptr && thread->last_continuation() != nullptr) {
74 _chunk = stackChunkHandle(Thread::current()->handle_area()->allocate_null_handle(), true /* dummy */);
75 }
76 _chunk_index = -1;
77
78 #ifndef PRODUCT
79 for (int i = 0; i < reg_count ; i++ ) _location[i] = nullptr;
80 #endif /* PRODUCT */
81 }
341 return !nm->is_at_poll_return(pc());
342 }
343
344 void frame::deoptimize(JavaThread* thread) {
345 assert(thread == nullptr
346 || (thread->frame_anchor()->has_last_Java_frame() &&
347 thread->frame_anchor()->walkable()), "must be");
348 // Schedule deoptimization of an nmethod activation with this frame.
349 assert(_cb != nullptr && _cb->is_nmethod(), "must be");
350
351 // If the call site is a MethodHandle call site use the MH deopt handler.
352 nmethod* nm = _cb->as_nmethod();
353 address deopt = nm->is_method_handle_return(pc()) ?
354 nm->deopt_mh_handler_begin() :
355 nm->deopt_handler_begin();
356
357 NativePostCallNop* inst = nativePostCallNop_at(pc());
358
359 // Save the original pc before we patch in the new one
360 nm->set_original_pc(this, pc());
361 patch_pc(thread, deopt);
362 assert(is_deoptimized_frame(), "must be");
363
364 #ifdef ASSERT
365 if (thread != nullptr) {
366 frame check = thread->last_frame();
367 if (is_older(check.id())) {
368 RegisterMap map(thread,
369 RegisterMap::UpdateMap::skip,
370 RegisterMap::ProcessFrames::include,
371 RegisterMap::WalkContinuation::skip);
372 while (id() != check.id()) {
373 check = check.sender(&map);
374 }
375 assert(check.is_deoptimized_frame(), "missed deopt");
376 }
377 }
378 #endif // ASSERT
379 }
380
739 }
740
741
742 /*
743 The interpreter_frame_expression_stack_at method in the case of SPARC needs the
744 max_stack value of the method in order to compute the expression stack address.
745 It uses the Method* in order to get the max_stack value but during GC this
746 Method* value saved on the frame is changed by reverse_and_push and hence cannot
747 be used. So we save the max_stack value in the FrameClosure object and pass it
748 down to the interpreter_frame_expression_stack_at method
749 */
750 class InterpreterFrameClosure : public OffsetClosure {
751 private:
752 const frame* _fr;
753 OopClosure* _f;
754 int _max_locals;
755 int _max_stack;
756
757 public:
758 InterpreterFrameClosure(const frame* fr, int max_locals, int max_stack,
759 OopClosure* f) {
760 _fr = fr;
761 _max_locals = max_locals;
762 _max_stack = max_stack;
763 _f = f;
764 }
765
766 void offset_do(int offset) {
767 oop* addr;
768 if (offset < _max_locals) {
769 addr = (oop*) _fr->interpreter_frame_local_at(offset);
770 assert((intptr_t*)addr >= _fr->sp(), "must be inside the frame");
771 _f->do_oop(addr);
772 } else {
773 addr = (oop*) _fr->interpreter_frame_expression_stack_at((offset - _max_locals));
774 // In case of exceptions, the expression stack is invalid and the esp will be reset to express
775 // this condition. Therefore, we call f only if addr is 'inside' the stack (i.e., addr >= esp for Intel).
776 bool in_stack;
777 if (frame::interpreter_frame_expression_stack_direction() > 0) {
778 in_stack = (intptr_t*)addr <= _fr->interpreter_frame_tos_address();
779 } else {
780 in_stack = (intptr_t*)addr >= _fr->interpreter_frame_tos_address();
781 }
782 if (in_stack) {
783 _f->do_oop(addr);
784 }
785 }
786 }
787 };
788
789
790 class InterpretedArgumentOopFinder: public SignatureIterator {
791 private:
792 OopClosure* _f; // Closure to invoke
793 int _offset; // TOS-relative offset, decremented with each argument
794 bool _has_receiver; // true if the callee has a receiver
795 const frame* _fr;
796
797 friend class SignatureIterator; // so do_parameters_on can call do_type
798 void do_type(BasicType type) {
799 _offset -= parameter_type_word_count(type);
800 if (is_reference_type(type)) oop_offset_do();
801 }
802
803 void oop_offset_do() {
938 signature = call.signature();
939 has_receiver = call.has_receiver();
940 if (map->include_argument_oops() &&
941 interpreter_frame_expression_stack_size() > 0) {
942 ResourceMark rm(thread); // is this right ???
943 // we are at a call site & the expression stack is not empty
944 // => process callee's arguments
945 //
946 // Note: The expression stack can be empty if an exception
947 // occurred during method resolution/execution. In all
948 // cases we empty the expression stack completely be-
949 // fore handling the exception (the exception handling
950 // code in the interpreter calls a blocking runtime
951 // routine which can cause this code to be executed).
952 // (was bug gri 7/27/98)
953 oops_interpreted_arguments_do(signature, has_receiver, f);
954 }
955 }
956 }
957
958 InterpreterFrameClosure blk(this, max_locals, m->max_stack(), f);
959
960 // process locals & expression stack
961 InterpreterOopMap mask;
962 if (query_oop_map_cache) {
963 m->mask_for(m, bci, &mask);
964 } else {
965 OopMapCache::compute_one_oop_map(m, bci, &mask);
966 }
967 mask.iterate_oop(&blk);
968 }
969
970
971 void frame::oops_interpreted_arguments_do(Symbol* signature, bool has_receiver, OopClosure* f) const {
972 InterpretedArgumentOopFinder finder(signature, has_receiver, this, f);
973 finder.oops_do();
974 }
975
976 void frame::oops_nmethod_do(OopClosure* f, NMethodClosure* cf, DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, const RegisterMap* reg_map) const {
977 assert(_cb != nullptr, "sanity check");
978 assert((oop_map() == nullptr) == (_cb->oop_maps() == nullptr), "frame and _cb must agree that oopmap is set or not");
979 if (oop_map() != nullptr) {
980 if (df != nullptr) {
981 _oop_map->oops_do(this, reg_map, f, df);
982 } else {
983 _oop_map->oops_do(this, reg_map, f, derived_mode);
984 }
985
986 // Preserve potential arguments for a callee. We handle this by dispatching
987 // on the codeblob. For c2i, we do
988 if (reg_map->include_argument_oops() && _cb->is_nmethod()) {
989 // Only nmethod preserves outgoing arguments at call.
1002 class CompiledArgumentOopFinder: public SignatureIterator {
1003 protected:
1004 OopClosure* _f;
1005 int _offset; // the current offset, incremented with each argument
1006 bool _has_receiver; // true if the callee has a receiver
1007 bool _has_appendix; // true if the call has an appendix
1008 frame _fr;
1009 RegisterMap* _reg_map;
1010 int _arg_size;
1011 VMRegPair* _regs; // VMReg list of arguments
1012
1013 friend class SignatureIterator; // so do_parameters_on can call do_type
1014 void do_type(BasicType type) {
1015 if (is_reference_type(type)) handle_oop_offset();
1016 _offset += parameter_type_word_count(type);
1017 }
1018
1019 virtual void handle_oop_offset() {
1020 // Extract low order register number from register array.
1021 // In LP64-land, the high-order bits are valid but unhelpful.
1022 VMReg reg = _regs[_offset].first();
1023 oop *loc = _fr.oopmapreg_to_oop_location(reg, _reg_map);
1024 #ifdef ASSERT
1025 if (loc == nullptr) {
1026 if (_reg_map->should_skip_missing()) {
1027 return;
1028 }
1029 tty->print_cr("Error walking frame oops:");
1030 _fr.print_on(tty);
1031 assert(loc != nullptr, "missing register map entry reg: %d %s loc: " INTPTR_FORMAT, reg->value(), reg->name(), p2i(loc));
1032 }
1033 #endif
1034 _f->do_oop(loc);
1035 }
1036
1037 public:
1038 CompiledArgumentOopFinder(Symbol* signature, bool has_receiver, bool has_appendix, OopClosure* f, frame fr, const RegisterMap* reg_map)
1039 : SignatureIterator(signature) {
1040
1041 // initialize CompiledArgumentOopFinder
1042 _f = f;
1043 _offset = 0;
1044 _has_receiver = has_receiver;
1045 _has_appendix = has_appendix;
1046 _fr = fr;
1047 _reg_map = (RegisterMap*)reg_map;
1048 _arg_size = ArgumentSizeComputer(signature).size() + (has_receiver ? 1 : 0) + (has_appendix ? 1 : 0);
1049
1050 int arg_size;
1051 _regs = SharedRuntime::find_callee_arguments(signature, has_receiver, has_appendix, &arg_size);
1052 assert(arg_size == _arg_size, "wrong arg size");
1053 }
1054
1055 void oops_do() {
1056 if (_has_receiver) {
1057 handle_oop_offset();
1058 _offset++;
1059 }
1060 do_parameters_on(this);
1061 if (_has_appendix) {
1062 handle_oop_offset();
1063 _offset++;
1064 }
1065 }
1066 };
1067
1068 void frame::oops_compiled_arguments_do(Symbol* signature, bool has_receiver, bool has_appendix,
1069 const RegisterMap* reg_map, OopClosure* f) const {
1070 // ResourceMark rm;
1071 CompiledArgumentOopFinder finder(signature, has_receiver, has_appendix, f, *this, reg_map);
1072 finder.oops_do();
|
22 *
23 */
24
25 #include "classfile/moduleEntry.hpp"
26 #include "code/codeCache.hpp"
27 #include "code/scopeDesc.hpp"
28 #include "code/vmreg.inline.hpp"
29 #include "compiler/abstractCompiler.hpp"
30 #include "compiler/disassembler.hpp"
31 #include "compiler/oopMap.hpp"
32 #include "gc/shared/collectedHeap.inline.hpp"
33 #include "interpreter/interpreter.hpp"
34 #include "interpreter/oopMapCache.hpp"
35 #include "logging/log.hpp"
36 #include "memory/resourceArea.hpp"
37 #include "memory/universe.hpp"
38 #include "oops/markWord.hpp"
39 #include "oops/method.inline.hpp"
40 #include "oops/methodData.hpp"
41 #include "oops/oop.inline.hpp"
42 #include "oops/inlineKlass.hpp"
43 #include "oops/stackChunkOop.inline.hpp"
44 #include "oops/verifyOopClosure.hpp"
45 #include "prims/methodHandles.hpp"
46 #include "runtime/continuation.hpp"
47 #include "runtime/continuationEntry.inline.hpp"
48 #include "runtime/frame.inline.hpp"
49 #include "runtime/handles.inline.hpp"
50 #include "runtime/javaCalls.hpp"
51 #include "runtime/javaThread.hpp"
52 #include "runtime/monitorChunk.hpp"
53 #include "runtime/os.hpp"
54 #include "runtime/sharedRuntime.hpp"
55 #include "runtime/safefetch.hpp"
56 #include "runtime/signature.hpp"
57 #include "runtime/stackValue.hpp"
58 #include "runtime/stubCodeGenerator.hpp"
59 #include "runtime/stubRoutines.hpp"
60 #include "utilities/debug.hpp"
61 #include "utilities/decoder.hpp"
62 #include "utilities/formatBuffer.hpp"
63 #ifdef COMPILER1
64 #include "c1/c1_Runtime1.hpp"
65 #endif
66
67 RegisterMap::RegisterMap(JavaThread *thread, UpdateMap update_map, ProcessFrames process_frames, WalkContinuation walk_cont) {
68 _thread = thread;
69 _update_map = update_map == UpdateMap::include;
70 _process_frames = process_frames == ProcessFrames::include;
71 _walk_cont = walk_cont == WalkContinuation::include;
72 clear();
73 DEBUG_ONLY (_update_for_id = nullptr;)
74 NOT_PRODUCT(_skip_missing = false;)
75 NOT_PRODUCT(_async = false;)
76
77 if (walk_cont == WalkContinuation::include && thread != nullptr && thread->last_continuation() != nullptr) {
78 _chunk = stackChunkHandle(Thread::current()->handle_area()->allocate_null_handle(), true /* dummy */);
79 }
80 _chunk_index = -1;
81
82 #ifndef PRODUCT
83 for (int i = 0; i < reg_count ; i++ ) _location[i] = nullptr;
84 #endif /* PRODUCT */
85 }
345 return !nm->is_at_poll_return(pc());
346 }
347
348 void frame::deoptimize(JavaThread* thread) {
349 assert(thread == nullptr
350 || (thread->frame_anchor()->has_last_Java_frame() &&
351 thread->frame_anchor()->walkable()), "must be");
352 // Schedule deoptimization of an nmethod activation with this frame.
353 assert(_cb != nullptr && _cb->is_nmethod(), "must be");
354
355 // If the call site is a MethodHandle call site use the MH deopt handler.
356 nmethod* nm = _cb->as_nmethod();
357 address deopt = nm->is_method_handle_return(pc()) ?
358 nm->deopt_mh_handler_begin() :
359 nm->deopt_handler_begin();
360
361 NativePostCallNop* inst = nativePostCallNop_at(pc());
362
363 // Save the original pc before we patch in the new one
364 nm->set_original_pc(this, pc());
365
366 #ifdef COMPILER1
367 if (nm->is_compiled_by_c1() && nm->method()->has_scalarized_args() &&
368 pc() < nm->verified_inline_entry_point()) {
369 // The VEP and VIEP(RO) of C1-compiled methods call into the runtime to buffer scalarized value
370 // type args. We can't deoptimize at that point because the buffers have not yet been initialized.
371 // Also, if the method is synchronized, we first need to acquire the lock.
372 // Don't patch the return pc to delay deoptimization until we enter the method body (the check
373 // added in LIRGenerator::do_Base will detect the pending deoptimization by checking the original_pc).
374 #if defined ASSERT && !defined AARCH64 // Stub call site does not look like NativeCall on AArch64
375 NativeCall* call = nativeCall_before(this->pc());
376 address dest = call->destination();
377 assert(dest == Runtime1::entry_for(C1StubId::buffer_inline_args_no_receiver_id) ||
378 dest == Runtime1::entry_for(C1StubId::buffer_inline_args_id), "unexpected safepoint in entry point");
379 #endif
380 return;
381 }
382 #endif
383
384 patch_pc(thread, deopt);
385 assert(is_deoptimized_frame(), "must be");
386
387 #ifdef ASSERT
388 if (thread != nullptr) {
389 frame check = thread->last_frame();
390 if (is_older(check.id())) {
391 RegisterMap map(thread,
392 RegisterMap::UpdateMap::skip,
393 RegisterMap::ProcessFrames::include,
394 RegisterMap::WalkContinuation::skip);
395 while (id() != check.id()) {
396 check = check.sender(&map);
397 }
398 assert(check.is_deoptimized_frame(), "missed deopt");
399 }
400 }
401 #endif // ASSERT
402 }
403
762 }
763
764
765 /*
766 The interpreter_frame_expression_stack_at method in the case of SPARC needs the
767 max_stack value of the method in order to compute the expression stack address.
768 It uses the Method* in order to get the max_stack value but during GC this
769 Method* value saved on the frame is changed by reverse_and_push and hence cannot
770 be used. So we save the max_stack value in the FrameClosure object and pass it
771 down to the interpreter_frame_expression_stack_at method
772 */
773 class InterpreterFrameClosure : public OffsetClosure {
774 private:
775 const frame* _fr;
776 OopClosure* _f;
777 int _max_locals;
778 int _max_stack;
779
780 public:
781 InterpreterFrameClosure(const frame* fr, int max_locals, int max_stack,
782 OopClosure* f, BufferedValueClosure* bvt_f) {
783 _fr = fr;
784 _max_locals = max_locals;
785 _max_stack = max_stack;
786 _f = f;
787 }
788
789 void offset_do(int offset) {
790 oop* addr;
791 if (offset < _max_locals) {
792 addr = (oop*) _fr->interpreter_frame_local_at(offset);
793 assert((intptr_t*)addr >= _fr->sp(), "must be inside the frame");
794 if (_f != nullptr) {
795 _f->do_oop(addr);
796 }
797 } else {
798 addr = (oop*) _fr->interpreter_frame_expression_stack_at((offset - _max_locals));
799 // In case of exceptions, the expression stack is invalid and the esp will be reset to express
800 // this condition. Therefore, we call f only if addr is 'inside' the stack (i.e., addr >= esp for Intel).
801 bool in_stack;
802 if (frame::interpreter_frame_expression_stack_direction() > 0) {
803 in_stack = (intptr_t*)addr <= _fr->interpreter_frame_tos_address();
804 } else {
805 in_stack = (intptr_t*)addr >= _fr->interpreter_frame_tos_address();
806 }
807 if (in_stack) {
808 if (_f != nullptr) {
809 _f->do_oop(addr);
810 }
811 }
812 }
813 }
814 };
815
816
817 class InterpretedArgumentOopFinder: public SignatureIterator {
818 private:
819 OopClosure* _f; // Closure to invoke
820 int _offset; // TOS-relative offset, decremented with each argument
821 bool _has_receiver; // true if the callee has a receiver
822 const frame* _fr;
823
824 friend class SignatureIterator; // so do_parameters_on can call do_type
825 void do_type(BasicType type) {
826 _offset -= parameter_type_word_count(type);
827 if (is_reference_type(type)) oop_offset_do();
828 }
829
830 void oop_offset_do() {
965 signature = call.signature();
966 has_receiver = call.has_receiver();
967 if (map->include_argument_oops() &&
968 interpreter_frame_expression_stack_size() > 0) {
969 ResourceMark rm(thread); // is this right ???
970 // we are at a call site & the expression stack is not empty
971 // => process callee's arguments
972 //
973 // Note: The expression stack can be empty if an exception
974 // occurred during method resolution/execution. In all
975 // cases we empty the expression stack completely be-
976 // fore handling the exception (the exception handling
977 // code in the interpreter calls a blocking runtime
978 // routine which can cause this code to be executed).
979 // (was bug gri 7/27/98)
980 oops_interpreted_arguments_do(signature, has_receiver, f);
981 }
982 }
983 }
984
985 InterpreterFrameClosure blk(this, max_locals, m->max_stack(), f, nullptr);
986
987 // process locals & expression stack
988 InterpreterOopMap mask;
989 if (query_oop_map_cache) {
990 m->mask_for(m, bci, &mask);
991 } else {
992 OopMapCache::compute_one_oop_map(m, bci, &mask);
993 }
994 mask.iterate_oop(&blk);
995 }
996
997 void frame::buffered_values_interpreted_do(BufferedValueClosure* f) {
998 assert(is_interpreted_frame(), "Not an interpreted frame");
999 Thread *thread = Thread::current();
1000 methodHandle m (thread, interpreter_frame_method());
1001 jint bci = interpreter_frame_bci();
1002
1003 assert(m->is_method(), "checking frame value");
1004 assert(!m->is_native() && bci >= 0 && bci < m->code_size(),
1005 "invalid bci value");
1006
1007 InterpreterFrameClosure blk(this, m->max_locals(), m->max_stack(), nullptr, f);
1008
1009 // process locals & expression stack
1010 InterpreterOopMap mask;
1011 m->mask_for(bci, &mask);
1012 mask.iterate_oop(&blk);
1013 }
1014
1015 void frame::oops_interpreted_arguments_do(Symbol* signature, bool has_receiver, OopClosure* f) const {
1016 InterpretedArgumentOopFinder finder(signature, has_receiver, this, f);
1017 finder.oops_do();
1018 }
1019
1020 void frame::oops_nmethod_do(OopClosure* f, NMethodClosure* cf, DerivedOopClosure* df, DerivedPointerIterationMode derived_mode, const RegisterMap* reg_map) const {
1021 assert(_cb != nullptr, "sanity check");
1022 assert((oop_map() == nullptr) == (_cb->oop_maps() == nullptr), "frame and _cb must agree that oopmap is set or not");
1023 if (oop_map() != nullptr) {
1024 if (df != nullptr) {
1025 _oop_map->oops_do(this, reg_map, f, df);
1026 } else {
1027 _oop_map->oops_do(this, reg_map, f, derived_mode);
1028 }
1029
1030 // Preserve potential arguments for a callee. We handle this by dispatching
1031 // on the codeblob. For c2i, we do
1032 if (reg_map->include_argument_oops() && _cb->is_nmethod()) {
1033 // Only nmethod preserves outgoing arguments at call.
1046 class CompiledArgumentOopFinder: public SignatureIterator {
1047 protected:
1048 OopClosure* _f;
1049 int _offset; // the current offset, incremented with each argument
1050 bool _has_receiver; // true if the callee has a receiver
1051 bool _has_appendix; // true if the call has an appendix
1052 frame _fr;
1053 RegisterMap* _reg_map;
1054 int _arg_size;
1055 VMRegPair* _regs; // VMReg list of arguments
1056
1057 friend class SignatureIterator; // so do_parameters_on can call do_type
1058 void do_type(BasicType type) {
1059 if (is_reference_type(type)) handle_oop_offset();
1060 _offset += parameter_type_word_count(type);
1061 }
1062
1063 virtual void handle_oop_offset() {
1064 // Extract low order register number from register array.
1065 // In LP64-land, the high-order bits are valid but unhelpful.
1066 assert(_offset < _arg_size, "out of bounds");
1067 VMReg reg = _regs[_offset].first();
1068 oop *loc = _fr.oopmapreg_to_oop_location(reg, _reg_map);
1069 #ifdef ASSERT
1070 if (loc == nullptr) {
1071 if (_reg_map->should_skip_missing()) {
1072 return;
1073 }
1074 tty->print_cr("Error walking frame oops:");
1075 _fr.print_on(tty);
1076 assert(loc != nullptr, "missing register map entry reg: %d %s loc: " INTPTR_FORMAT, reg->value(), reg->name(), p2i(loc));
1077 }
1078 #endif
1079 _f->do_oop(loc);
1080 }
1081
1082 public:
1083 CompiledArgumentOopFinder(Symbol* signature, bool has_receiver, bool has_appendix, OopClosure* f, frame fr, const RegisterMap* reg_map)
1084 : SignatureIterator(signature) {
1085
1086 // initialize CompiledArgumentOopFinder
1087 _f = f;
1088 _offset = 0;
1089 _has_receiver = has_receiver;
1090 _has_appendix = has_appendix;
1091 _fr = fr;
1092 _reg_map = (RegisterMap*)reg_map;
1093 _regs = SharedRuntime::find_callee_arguments(signature, has_receiver, has_appendix, &_arg_size);
1094 }
1095
1096 void oops_do() {
1097 if (_has_receiver) {
1098 handle_oop_offset();
1099 _offset++;
1100 }
1101 do_parameters_on(this);
1102 if (_has_appendix) {
1103 handle_oop_offset();
1104 _offset++;
1105 }
1106 }
1107 };
1108
1109 void frame::oops_compiled_arguments_do(Symbol* signature, bool has_receiver, bool has_appendix,
1110 const RegisterMap* reg_map, OopClosure* f) const {
1111 // ResourceMark rm;
1112 CompiledArgumentOopFinder finder(signature, has_receiver, has_appendix, f, *this, reg_map);
1113 finder.oops_do();
|