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