Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2011 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 #ifndef ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
     18 #define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
     19 
     20 #include "art_method-inl.h"
     21 #include "gc_map.h"
     22 #include "scoped_thread_state_change.h"
     23 #include "stack_map.h"
     24 
     25 namespace art {
     26 
     27 // Helper class for tests checking that the compiler keeps track of dex registers
     28 // holding references.
     29 class CheckReferenceMapVisitor : public StackVisitor {
     30  public:
     31   explicit CheckReferenceMapVisitor(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
     32       : StackVisitor(thread, nullptr, StackVisitor::StackWalkKind::kIncludeInlinedFrames) {}
     33 
     34   bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     35     ArtMethod* m = GetMethod();
     36     if (m->IsCalleeSaveMethod() || m->IsNative()) {
     37       CHECK_EQ(GetDexPc(), DexFile::kDexNoIndex);
     38     }
     39 
     40     if (m == nullptr || m->IsNative() || m->IsRuntimeMethod() || IsShadowFrame()) {
     41       return true;
     42     }
     43 
     44     LOG(INFO) << "At " << PrettyMethod(m, false);
     45 
     46     if (m->IsCalleeSaveMethod()) {
     47       LOG(WARNING) << "no PC for " << PrettyMethod(m);
     48       return true;
     49     }
     50 
     51     return false;
     52   }
     53 
     54   void CheckReferences(int* registers, int number_of_references, uint32_t native_pc_offset)
     55       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     56     if (GetMethod()->IsOptimized(sizeof(void*))) {
     57       CheckOptimizedMethod(registers, number_of_references, native_pc_offset);
     58     } else {
     59       CheckQuickMethod(registers, number_of_references, native_pc_offset);
     60     }
     61   }
     62 
     63  private:
     64   void CheckOptimizedMethod(int* registers, int number_of_references, uint32_t native_pc_offset)
     65       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     66     ArtMethod* m = GetMethod();
     67     CodeInfo code_info = m->GetOptimizedCodeInfo();
     68     StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
     69     uint16_t number_of_dex_registers = m->GetCodeItem()->registers_size_;
     70     DexRegisterMap dex_register_map =
     71         code_info.GetDexRegisterMapOf(stack_map, number_of_dex_registers);
     72     MemoryRegion stack_mask = stack_map.GetStackMask(code_info);
     73     uint32_t register_mask = stack_map.GetRegisterMask(code_info);
     74     for (int i = 0; i < number_of_references; ++i) {
     75       int reg = registers[i];
     76       CHECK(reg < m->GetCodeItem()->registers_size_);
     77       DexRegisterLocation location =
     78           dex_register_map.GetDexRegisterLocation(reg, number_of_dex_registers, code_info);
     79       switch (location.GetKind()) {
     80         case DexRegisterLocation::Kind::kNone:
     81           // Not set, should not be a reference.
     82           CHECK(false);
     83           break;
     84         case DexRegisterLocation::Kind::kInStack:
     85           DCHECK_EQ(location.GetValue() % kFrameSlotSize, 0);
     86           CHECK(stack_mask.LoadBit(location.GetValue() / kFrameSlotSize));
     87           break;
     88         case DexRegisterLocation::Kind::kInRegister:
     89           CHECK_NE(register_mask & (1 << location.GetValue()), 0u);
     90           break;
     91         case DexRegisterLocation::Kind::kInFpuRegister:
     92           // In Fpu register, should not be a reference.
     93           CHECK(false);
     94           break;
     95         case DexRegisterLocation::Kind::kConstant:
     96           CHECK_EQ(location.GetValue(), 0);
     97           break;
     98         default:
     99           LOG(FATAL) << "Unexpected location kind"
    100                      << DexRegisterLocation::PrettyDescriptor(location.GetInternalKind());
    101       }
    102     }
    103   }
    104 
    105   void CheckQuickMethod(int* registers, int number_of_references, uint32_t native_pc_offset)
    106       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
    107     ArtMethod* m = GetMethod();
    108     NativePcOffsetToReferenceMap map(m->GetNativeGcMap(sizeof(void*)));
    109     const uint8_t* ref_bitmap = map.FindBitMap(native_pc_offset);
    110     CHECK(ref_bitmap);
    111     for (int i = 0; i < number_of_references; ++i) {
    112       int reg = registers[i];
    113       CHECK(reg < m->GetCodeItem()->registers_size_);
    114       CHECK((*((ref_bitmap) + reg / 8) >> (reg % 8) ) & 0x01)
    115           << "Error: Reg @" << i << " is not in GC map";
    116     }
    117   }
    118 };
    119 
    120 }  // namespace art
    121 
    122 #endif  // ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
    123