xref: /aosp_15_r20/art/runtime/check_reference_map_visitor.h (revision 795d594fd825385562da6b089ea9b2033f3abf5a)
1*795d594fSAndroid Build Coastguard Worker /*
2*795d594fSAndroid Build Coastguard Worker  * Copyright (C) 2011 The Android Open Source Project
3*795d594fSAndroid Build Coastguard Worker  *
4*795d594fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*795d594fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*795d594fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*795d594fSAndroid Build Coastguard Worker  *
8*795d594fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*795d594fSAndroid Build Coastguard Worker  *
10*795d594fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*795d594fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*795d594fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*795d594fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*795d594fSAndroid Build Coastguard Worker  * limitations under the License.
15*795d594fSAndroid Build Coastguard Worker  */
16*795d594fSAndroid Build Coastguard Worker 
17*795d594fSAndroid Build Coastguard Worker #ifndef ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
18*795d594fSAndroid Build Coastguard Worker #define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
19*795d594fSAndroid Build Coastguard Worker 
20*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
21*795d594fSAndroid Build Coastguard Worker #include "base/macros.h"
22*795d594fSAndroid Build Coastguard Worker #include "dex/code_item_accessors-inl.h"
23*795d594fSAndroid Build Coastguard Worker #include "dex/dex_file_types.h"
24*795d594fSAndroid Build Coastguard Worker #include "oat/oat_quick_method_header.h"
25*795d594fSAndroid Build Coastguard Worker #include "oat/stack_map.h"
26*795d594fSAndroid Build Coastguard Worker #include "scoped_thread_state_change-inl.h"
27*795d594fSAndroid Build Coastguard Worker #include "stack.h"
28*795d594fSAndroid Build Coastguard Worker 
29*795d594fSAndroid Build Coastguard Worker namespace art HIDDEN {
30*795d594fSAndroid Build Coastguard Worker 
31*795d594fSAndroid Build Coastguard Worker // Helper class for tests checking that the compiler keeps track of dex registers
32*795d594fSAndroid Build Coastguard Worker // holding references.
33*795d594fSAndroid Build Coastguard Worker class CheckReferenceMapVisitor : public StackVisitor {
34*795d594fSAndroid Build Coastguard Worker  public:
CheckReferenceMapVisitor(Thread * thread)35*795d594fSAndroid Build Coastguard Worker   explicit CheckReferenceMapVisitor(Thread* thread) REQUIRES_SHARED(Locks::mutator_lock_)
36*795d594fSAndroid Build Coastguard Worker       : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {}
37*795d594fSAndroid Build Coastguard Worker 
VisitFrame()38*795d594fSAndroid Build Coastguard Worker   bool VisitFrame() REQUIRES_SHARED(Locks::mutator_lock_) {
39*795d594fSAndroid Build Coastguard Worker     ArtMethod* m = GetMethod();
40*795d594fSAndroid Build Coastguard Worker     if (m->IsCalleeSaveMethod() || m->IsNative()) {
41*795d594fSAndroid Build Coastguard Worker       CHECK_EQ(GetDexPc(), dex::kDexNoIndex);
42*795d594fSAndroid Build Coastguard Worker     }
43*795d594fSAndroid Build Coastguard Worker 
44*795d594fSAndroid Build Coastguard Worker     // If the method is not compiled, continue the stack walk.
45*795d594fSAndroid Build Coastguard Worker     if (m == nullptr ||
46*795d594fSAndroid Build Coastguard Worker         m->IsNative() ||
47*795d594fSAndroid Build Coastguard Worker         m->IsRuntimeMethod() ||
48*795d594fSAndroid Build Coastguard Worker         IsShadowFrame() ||
49*795d594fSAndroid Build Coastguard Worker         !GetCurrentOatQuickMethodHeader()->IsOptimized()) {
50*795d594fSAndroid Build Coastguard Worker       return true;
51*795d594fSAndroid Build Coastguard Worker     }
52*795d594fSAndroid Build Coastguard Worker 
53*795d594fSAndroid Build Coastguard Worker     LOG(INFO) << "At " << m->PrettyMethod(false);
54*795d594fSAndroid Build Coastguard Worker 
55*795d594fSAndroid Build Coastguard Worker     if (m->IsCalleeSaveMethod()) {
56*795d594fSAndroid Build Coastguard Worker       LOG(WARNING) << "no PC for " << m->PrettyMethod();
57*795d594fSAndroid Build Coastguard Worker       return true;
58*795d594fSAndroid Build Coastguard Worker     }
59*795d594fSAndroid Build Coastguard Worker 
60*795d594fSAndroid Build Coastguard Worker     return false;
61*795d594fSAndroid Build Coastguard Worker   }
62*795d594fSAndroid Build Coastguard Worker 
CheckReferences(int * registers,int number_of_references,uint32_t dex_pc,uint32_t native_pc_offset,bool search_for_valid_stack_map)63*795d594fSAndroid Build Coastguard Worker   void CheckReferences(int* registers,
64*795d594fSAndroid Build Coastguard Worker                        int number_of_references,
65*795d594fSAndroid Build Coastguard Worker                        uint32_t dex_pc,
66*795d594fSAndroid Build Coastguard Worker                        uint32_t native_pc_offset,
67*795d594fSAndroid Build Coastguard Worker                        bool search_for_valid_stack_map)
68*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
69*795d594fSAndroid Build Coastguard Worker     CHECK(GetCurrentOatQuickMethodHeader()->IsOptimized());
70*795d594fSAndroid Build Coastguard Worker     CheckOptimizedMethod(
71*795d594fSAndroid Build Coastguard Worker         registers, number_of_references, dex_pc, native_pc_offset, search_for_valid_stack_map);
72*795d594fSAndroid Build Coastguard Worker   }
73*795d594fSAndroid Build Coastguard Worker 
74*795d594fSAndroid Build Coastguard Worker  private:
CheckOptimizedMethod(int * registers,int number_of_references,uint32_t dex_pc,uint32_t native_pc_offset,bool search_for_valid_stack_map)75*795d594fSAndroid Build Coastguard Worker   void CheckOptimizedMethod(int* registers,
76*795d594fSAndroid Build Coastguard Worker                             int number_of_references,
77*795d594fSAndroid Build Coastguard Worker                             uint32_t dex_pc,
78*795d594fSAndroid Build Coastguard Worker                             uint32_t native_pc_offset,
79*795d594fSAndroid Build Coastguard Worker                             bool search_for_valid_stack_map)
80*795d594fSAndroid Build Coastguard Worker       REQUIRES_SHARED(Locks::mutator_lock_) {
81*795d594fSAndroid Build Coastguard Worker     ArtMethod* m = GetMethod();
82*795d594fSAndroid Build Coastguard Worker     CodeInfo code_info(GetCurrentOatQuickMethodHeader());
83*795d594fSAndroid Build Coastguard Worker     StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
84*795d594fSAndroid Build Coastguard Worker     if (search_for_valid_stack_map && !code_info.GetStackMaskOf(stack_map).IsValid()) {
85*795d594fSAndroid Build Coastguard Worker       for (StackMap map : code_info.GetStackMaps()) {
86*795d594fSAndroid Build Coastguard Worker         if (map.GetDexPc() == dex_pc && code_info.GetStackMaskOf(map).IsValid()) {
87*795d594fSAndroid Build Coastguard Worker           stack_map = map;
88*795d594fSAndroid Build Coastguard Worker           break;
89*795d594fSAndroid Build Coastguard Worker         }
90*795d594fSAndroid Build Coastguard Worker       }
91*795d594fSAndroid Build Coastguard Worker     }
92*795d594fSAndroid Build Coastguard Worker     CodeItemDataAccessor accessor(m->DexInstructionData());
93*795d594fSAndroid Build Coastguard Worker     uint16_t number_of_dex_registers = accessor.RegistersSize();
94*795d594fSAndroid Build Coastguard Worker 
95*795d594fSAndroid Build Coastguard Worker     if (!Runtime::Current()->IsAsyncDeoptimizeable(GetOuterMethod(), GetCurrentQuickFramePc())) {
96*795d594fSAndroid Build Coastguard Worker       // We can only guarantee dex register info presence for debuggable methods.
97*795d594fSAndroid Build Coastguard Worker       return;
98*795d594fSAndroid Build Coastguard Worker     }
99*795d594fSAndroid Build Coastguard Worker 
100*795d594fSAndroid Build Coastguard Worker     DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map);
101*795d594fSAndroid Build Coastguard Worker     DCHECK_EQ(dex_register_map.size(), number_of_dex_registers);
102*795d594fSAndroid Build Coastguard Worker     uint32_t register_mask = code_info.GetRegisterMaskOf(stack_map);
103*795d594fSAndroid Build Coastguard Worker     BitMemoryRegion stack_mask = code_info.GetStackMaskOf(stack_map);
104*795d594fSAndroid Build Coastguard Worker     for (int i = 0; i < number_of_references; ++i) {
105*795d594fSAndroid Build Coastguard Worker       int reg = registers[i];
106*795d594fSAndroid Build Coastguard Worker       CHECK_LT(reg, accessor.RegistersSize());
107*795d594fSAndroid Build Coastguard Worker       DexRegisterLocation location = dex_register_map[reg];
108*795d594fSAndroid Build Coastguard Worker       switch (location.GetKind()) {
109*795d594fSAndroid Build Coastguard Worker         case DexRegisterLocation::Kind::kNone:
110*795d594fSAndroid Build Coastguard Worker           // Not set, should not be a reference.
111*795d594fSAndroid Build Coastguard Worker           CHECK(false);
112*795d594fSAndroid Build Coastguard Worker           break;
113*795d594fSAndroid Build Coastguard Worker         case DexRegisterLocation::Kind::kInStack:
114*795d594fSAndroid Build Coastguard Worker           CHECK(stack_mask.IsValid());
115*795d594fSAndroid Build Coastguard Worker           DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
116*795d594fSAndroid Build Coastguard Worker           CHECK(stack_mask.LoadBit(location.GetValue() / kFrameSlotSize));
117*795d594fSAndroid Build Coastguard Worker           break;
118*795d594fSAndroid Build Coastguard Worker         case DexRegisterLocation::Kind::kInRegister:
119*795d594fSAndroid Build Coastguard Worker         case DexRegisterLocation::Kind::kInRegisterHigh:
120*795d594fSAndroid Build Coastguard Worker           CHECK_NE(register_mask & (1 << location.GetValue()), 0u);
121*795d594fSAndroid Build Coastguard Worker           break;
122*795d594fSAndroid Build Coastguard Worker         case DexRegisterLocation::Kind::kInFpuRegister:
123*795d594fSAndroid Build Coastguard Worker         case DexRegisterLocation::Kind::kInFpuRegisterHigh:
124*795d594fSAndroid Build Coastguard Worker           // In Fpu register, should not be a reference.
125*795d594fSAndroid Build Coastguard Worker           CHECK(false);
126*795d594fSAndroid Build Coastguard Worker           break;
127*795d594fSAndroid Build Coastguard Worker         case DexRegisterLocation::Kind::kConstant:
128*795d594fSAndroid Build Coastguard Worker           CHECK_EQ(location.GetValue(), 0);
129*795d594fSAndroid Build Coastguard Worker           break;
130*795d594fSAndroid Build Coastguard Worker         default:
131*795d594fSAndroid Build Coastguard Worker           LOG(FATAL) << "Unexpected location kind " << location.GetKind();
132*795d594fSAndroid Build Coastguard Worker       }
133*795d594fSAndroid Build Coastguard Worker     }
134*795d594fSAndroid Build Coastguard Worker   }
135*795d594fSAndroid Build Coastguard Worker };
136*795d594fSAndroid Build Coastguard Worker 
137*795d594fSAndroid Build Coastguard Worker }  // namespace art
138*795d594fSAndroid Build Coastguard Worker 
139*795d594fSAndroid Build Coastguard Worker #endif  // ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
140