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 #include <string_view>
18*795d594fSAndroid Build Coastguard Worker
19*795d594fSAndroid Build Coastguard Worker #include "art_method-inl.h"
20*795d594fSAndroid Build Coastguard Worker #include "check_reference_map_visitor.h"
21*795d594fSAndroid Build Coastguard Worker #include "jni.h"
22*795d594fSAndroid Build Coastguard Worker
23*795d594fSAndroid Build Coastguard Worker namespace art {
24*795d594fSAndroid Build Coastguard Worker
25*795d594fSAndroid Build Coastguard Worker #define CHECK_REGS_ARE_REFERENCES(...) do { \
26*795d594fSAndroid Build Coastguard Worker int t[] = {__VA_ARGS__}; \
27*795d594fSAndroid Build Coastguard Worker int t_size = sizeof(t) / sizeof(*t); \
28*795d594fSAndroid Build Coastguard Worker CheckReferences( \
29*795d594fSAndroid Build Coastguard Worker t, t_size, GetDexPc(), GetNativePcOffset(), /* search_for_valid_sack_map= */ false); \
30*795d594fSAndroid Build Coastguard Worker } while (false);
31*795d594fSAndroid Build Coastguard Worker
32*795d594fSAndroid Build Coastguard Worker static int gJava_StackWalk_refmap_calls = 0;
33*795d594fSAndroid Build Coastguard Worker
34*795d594fSAndroid Build Coastguard Worker class TestReferenceMapVisitor : public CheckReferenceMapVisitor {
35*795d594fSAndroid Build Coastguard Worker public:
REQUIRES_SHARED(Locks::mutator_lock_)36*795d594fSAndroid Build Coastguard Worker explicit TestReferenceMapVisitor(Thread* thread) REQUIRES_SHARED(Locks::mutator_lock_)
37*795d594fSAndroid Build Coastguard Worker : CheckReferenceMapVisitor(thread) {}
38*795d594fSAndroid Build Coastguard Worker
VisitFrame()39*795d594fSAndroid Build Coastguard Worker bool VisitFrame() override REQUIRES_SHARED(Locks::mutator_lock_) {
40*795d594fSAndroid Build Coastguard Worker if (CheckReferenceMapVisitor::VisitFrame()) {
41*795d594fSAndroid Build Coastguard Worker return true;
42*795d594fSAndroid Build Coastguard Worker }
43*795d594fSAndroid Build Coastguard Worker ArtMethod* m = GetMethod();
44*795d594fSAndroid Build Coastguard Worker std::string_view m_name(m->GetName());
45*795d594fSAndroid Build Coastguard Worker
46*795d594fSAndroid Build Coastguard Worker // Given the method name and the number of times the method has been called,
47*795d594fSAndroid Build Coastguard Worker // we know the Dex registers with live reference values. Assert that what we
48*795d594fSAndroid Build Coastguard Worker // find is what is expected.
49*795d594fSAndroid Build Coastguard Worker if (m_name == "$noinline$f") {
50*795d594fSAndroid Build Coastguard Worker if (gJava_StackWalk_refmap_calls == 1) {
51*795d594fSAndroid Build Coastguard Worker CHECK_EQ(1U, GetDexPc());
52*795d594fSAndroid Build Coastguard Worker CHECK_REGS_ARE_REFERENCES(1);
53*795d594fSAndroid Build Coastguard Worker } else {
54*795d594fSAndroid Build Coastguard Worker CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
55*795d594fSAndroid Build Coastguard Worker CHECK_EQ(5U, GetDexPc());
56*795d594fSAndroid Build Coastguard Worker CHECK_REGS_ARE_REFERENCES(1);
57*795d594fSAndroid Build Coastguard Worker }
58*795d594fSAndroid Build Coastguard Worker found_f_ = true;
59*795d594fSAndroid Build Coastguard Worker } else if (m_name == "$noinline$g") {
60*795d594fSAndroid Build Coastguard Worker if (gJava_StackWalk_refmap_calls == 1) {
61*795d594fSAndroid Build Coastguard Worker CHECK_EQ(0xcU, GetDexPc());
62*795d594fSAndroid Build Coastguard Worker CHECK_REGS_ARE_REFERENCES(0, 2); // Note that v1 is not in the minimal root set
63*795d594fSAndroid Build Coastguard Worker } else {
64*795d594fSAndroid Build Coastguard Worker CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
65*795d594fSAndroid Build Coastguard Worker CHECK_EQ(0xcU, GetDexPc());
66*795d594fSAndroid Build Coastguard Worker CHECK_REGS_ARE_REFERENCES(0, 2);
67*795d594fSAndroid Build Coastguard Worker }
68*795d594fSAndroid Build Coastguard Worker found_g_ = true;
69*795d594fSAndroid Build Coastguard Worker } else if (m_name == "shlemiel") {
70*795d594fSAndroid Build Coastguard Worker if (gJava_StackWalk_refmap_calls == 1) {
71*795d594fSAndroid Build Coastguard Worker CHECK_EQ(0x380U, GetDexPc());
72*795d594fSAndroid Build Coastguard Worker CHECK_REGS_ARE_REFERENCES(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
73*795d594fSAndroid Build Coastguard Worker } else {
74*795d594fSAndroid Build Coastguard Worker CHECK_EQ(gJava_StackWalk_refmap_calls, 2);
75*795d594fSAndroid Build Coastguard Worker CHECK_EQ(0x380U, GetDexPc());
76*795d594fSAndroid Build Coastguard Worker CHECK_REGS_ARE_REFERENCES(2, 4, 5, 7, 8, 9, 10, 11, 13, 14, 15, 16, 17, 18, 19, 21, 25);
77*795d594fSAndroid Build Coastguard Worker }
78*795d594fSAndroid Build Coastguard Worker found_shlemiel_ = true;
79*795d594fSAndroid Build Coastguard Worker }
80*795d594fSAndroid Build Coastguard Worker
81*795d594fSAndroid Build Coastguard Worker return true;
82*795d594fSAndroid Build Coastguard Worker }
83*795d594fSAndroid Build Coastguard Worker
~TestReferenceMapVisitor()84*795d594fSAndroid Build Coastguard Worker ~TestReferenceMapVisitor() {
85*795d594fSAndroid Build Coastguard Worker }
86*795d594fSAndroid Build Coastguard Worker
87*795d594fSAndroid Build Coastguard Worker bool found_f_ = false;
88*795d594fSAndroid Build Coastguard Worker bool found_g_ = false;
89*795d594fSAndroid Build Coastguard Worker bool found_shlemiel_ = false;
90*795d594fSAndroid Build Coastguard Worker };
91*795d594fSAndroid Build Coastguard Worker
Java_Main_testStackWalk(JNIEnv *,jobject,jint count)92*795d594fSAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Java_Main_testStackWalk(JNIEnv*, jobject, jint count) {
93*795d594fSAndroid Build Coastguard Worker ScopedObjectAccess soa(Thread::Current());
94*795d594fSAndroid Build Coastguard Worker CHECK_EQ(count, 0);
95*795d594fSAndroid Build Coastguard Worker gJava_StackWalk_refmap_calls++;
96*795d594fSAndroid Build Coastguard Worker
97*795d594fSAndroid Build Coastguard Worker // Visitor
98*795d594fSAndroid Build Coastguard Worker TestReferenceMapVisitor mapper(soa.Self());
99*795d594fSAndroid Build Coastguard Worker mapper.WalkStack();
100*795d594fSAndroid Build Coastguard Worker CHECK(mapper.found_f_);
101*795d594fSAndroid Build Coastguard Worker CHECK(mapper.found_g_);
102*795d594fSAndroid Build Coastguard Worker CHECK(mapper.found_shlemiel_);
103*795d594fSAndroid Build Coastguard Worker
104*795d594fSAndroid Build Coastguard Worker return count + 1;
105*795d594fSAndroid Build Coastguard Worker }
106*795d594fSAndroid Build Coastguard Worker
107*795d594fSAndroid Build Coastguard Worker } // namespace art
108