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