// Copyright 2011 Google Inc. All Rights Reserved. #include #include "UniquePtr.h" #include "class_linker.h" #include "common_test.h" #include "dex_verifier.h" #include "object.h" #include "jni.h" namespace art { #define REG(method, reg_vector, reg) \ ( ((reg) < (method)->NumRegisters()) && \ (( *((reg_vector) + (reg)/8) >> ((reg) % 8) ) & 0x01) ) #define EXPECT_REGS(...) do { \ int t[] = {__VA_ARGS__}; \ int t_size = sizeof(t) / sizeof(*t); \ for (int i = 0; i < t_size; ++i) \ EXPECT_TRUE(REG(m, reg_vector, t[i])); \ } while(false) static int gJava_StackWalk_refmap_calls = 0; struct ReferenceMapVisitor : public Thread::StackVisitor { ReferenceMapVisitor() { } void VisitFrame(const Frame& frame, uintptr_t pc) { Method* m = frame.GetMethod(); if (!m ||m->IsNative()) { return; } LOG(INFO) << "At " << PrettyMethod(m, false); art::DexVerifier::RegisterMap* map = new art::DexVerifier::RegisterMap( m->GetRegisterMapHeader(), m->GetRegisterMapData()); if (!pc) { // pc == NULL: m is either a native method or a phony method return; } if (m->IsCalleeSaveMethod()) { LOG(WARNING) << "no PC for " << PrettyMethod(m); return; } const uint8_t* reg_vector = art::DexVerifier::RegisterMapGetLine(map, m->ToDexPC(pc)); std::string m_name = m->GetName()->ToModifiedUtf8(); // Given the method name and the number of times the method has been called, // we know the Dex registers with live reference values. Assert that what we // find is what is expected. if (m_name.compare("f") == 0) { if (gJava_StackWalk_refmap_calls == 1) { EXPECT_EQ(0U, m->ToDexPC(pc)); EXPECT_REGS(1); } else { CHECK(gJava_StackWalk_refmap_calls == 2); EXPECT_EQ(4U, m->ToDexPC(pc)); EXPECT_REGS(1); // Note that v1 is not in the minimal root set } } else if (m_name.compare("g") == 0) { if (gJava_StackWalk_refmap_calls == 1) { EXPECT_EQ(0xaU, m->ToDexPC(pc)); EXPECT_REGS(1, 2, 3); } else { CHECK(gJava_StackWalk_refmap_calls == 2); EXPECT_EQ(0xaU, m->ToDexPC(pc)); EXPECT_REGS(1, 2, 3); } } else if (m_name.compare("shlemiel") == 0) { if (gJava_StackWalk_refmap_calls == 1) { EXPECT_EQ(0x2d5U, m->ToDexPC(pc)); EXPECT_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25); } else { CHECK(gJava_StackWalk_refmap_calls == 2); EXPECT_EQ(0x2d5U, m->ToDexPC(pc)); EXPECT_REGS(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25); } } LOG(INFO) << reg_vector; } }; extern "C" JNIEXPORT jint JNICALL Java_StackWalk_refmap(JNIEnv* env, jobject thisObj, jint count) { EXPECT_EQ(count, 0); gJava_StackWalk_refmap_calls++; // Visitor ReferenceMapVisitor mapper; Thread::Current()->WalkStack(&mapper); return count + 1; } extern "C" JNIEXPORT jint JNICALL Java_StackWalk_refmap2(JNIEnv* env, jobject thisObj, jint count) { gJava_StackWalk_refmap_calls++; // Visitor ReferenceMapVisitor mapper; Thread::Current()->WalkStack(&mapper); return count + 1; } }