Home | History | Annotate | Download | only in 004-StackWalk
      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 #include <stdio.h>
     18 #include <memory>
     19 
     20 #include "class_linker.h"
     21 #include "gc_map.h"
     22 #include "mirror/art_method-inl.h"
     23 #include "mirror/class-inl.h"
     24 #include "mirror/object_array-inl.h"
     25 #include "mirror/object-inl.h"
     26 #include "jni.h"
     27 #include "scoped_thread_state_change.h"
     28 
     29 namespace art {
     30 
     31 #define REG(reg_bitmap, reg) \
     32     (((reg) < m->GetCodeItem()->registers_size_) && \
     33      ((*((reg_bitmap) + (reg)/8) >> ((reg) % 8) ) & 0x01))
     34 
     35 #define CHECK_REGS(...) if (!IsShadowFrame()) { \
     36     int t[] = {__VA_ARGS__}; \
     37     int t_size = sizeof(t) / sizeof(*t); \
     38     for (int i = 0; i < t_size; ++i) \
     39       CHECK(REG(reg_bitmap, t[i])) << "Error: Reg " << i << " is not in RegisterMap"; \
     40   }
     41 
     42 static int gJava_StackWalk_refmap_calls = 0;
     43 
     44 struct TestReferenceMapVisitor : public StackVisitor {
     45   explicit TestReferenceMapVisitor(Thread* thread)
     46       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
     47       : StackVisitor(thread, NULL) {
     48   }
     49 
     50   bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     51     mirror::ArtMethod* m = GetMethod();
     52     CHECK(m != NULL);
     53     LOG(INFO) << "At " << PrettyMethod(m, false);
     54 
     55     if (m->IsCalleeSaveMethod() || m->IsNative()) {
     56       LOG(WARNING) << "no PC for " << PrettyMethod(m);
     57       CHECK_EQ(GetDexPc(), DexFile::kDexNoIndex);
     58       return true;
     59     }
     60     const uint8_t* reg_bitmap = NULL;
     61     if (!IsShadowFrame()) {
     62       NativePcOffsetToReferenceMap map(m->GetNativeGcMap());
     63       reg_bitmap = map.FindBitMap(GetNativePcOffset());
     64     }
     65     StringPiece m_name(m->GetName());
     66 
     67     // Given the method name and the number of times the method has been called,
     68     // we know the Dex registers with live reference values. Assert that what we
     69     // find is what is expected.
     70     if (m_name == "f") {
     71       if (gJava_StackWalk_refmap_calls == 1) {
     72         CHECK_EQ(1U, GetDexPc());
     73         CHECK_REGS(1);
     74       } else {
     75         CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
     76         CHECK_EQ(5U, GetDexPc());
     77         CHECK_REGS(1);
     78       }
     79     } else if (m_name == "g") {
     80       if (gJava_StackWalk_refmap_calls == 1) {
     81         CHECK_EQ(0xcU, GetDexPc());
     82         CHECK_REGS(0, 2);  // Note that v1 is not in the minimal root set
     83       } else {
     84         CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
     85         CHECK_EQ(0xcU, GetDexPc());
     86         CHECK_REGS(0, 2);
     87       }
     88     } else if (m_name == "shlemiel") {
     89       if (gJava_StackWalk_refmap_calls == 1) {
     90         CHECK_EQ(0x380U, GetDexPc());
     91         CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
     92       } else {
     93         CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
     94         CHECK_EQ(0x380U, GetDexPc());
     95         CHECK_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
     96       }
     97     }
     98 
     99     return true;
    100   }
    101 };
    102 
    103 extern "C" JNIEXPORT jint JNICALL Java_Main_stackmap(JNIEnv*, jobject, jint count) {
    104   ScopedObjectAccess soa(Thread::Current());
    105   CHECK_EQ(count, 0);
    106   gJava_StackWalk_refmap_calls++;
    107 
    108   // Visitor
    109   TestReferenceMapVisitor mapper(soa.Self());
    110   mapper.WalkStack();
    111 
    112   return count + 1;
    113 }
    114 
    115 extern "C" JNIEXPORT jint JNICALL Java_Main_refmap2(JNIEnv*, jobject, jint count) {
    116   ScopedObjectAccess soa(Thread::Current());
    117   gJava_StackWalk_refmap_calls++;
    118 
    119   // Visitor
    120   TestReferenceMapVisitor mapper(soa.Self());
    121   mapper.WalkStack();
    122 
    123   return count + 1;
    124 }
    125 
    126 }  // namespace art
    127