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