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 "dex_file-inl.h"
22 #include "gc_map.h"
23 #include "mirror/art_method-inl.h"
24 #include "mirror/class-inl.h"
25 #include "mirror/object_array-inl.h"
26 #include "mirror/object-inl.h"
27 #include "scoped_thread_state_change.h"
28 #include "thread.h"
29 #include "jni.h"
30 #include "verifier/method_verifier.h"
31 
32 namespace art {
33 
34 #define IS_IN_REF_BITMAP(ref_bitmap, reg) \
35     (((reg) < m->GetCodeItem()->registers_size_) && \
36      ((*((ref_bitmap) + (reg)/8) >> ((reg) % 8) ) & 0x01))
37 
38 #define CHECK_REGS_CONTAIN_REFS(...)     \
39   do {                                   \
40     int t[] = {__VA_ARGS__};             \
41     int t_size = sizeof(t) / sizeof(*t);      \
42     for (int i = 0; i < t_size; ++i)          \
43       CHECK(IS_IN_REF_BITMAP(ref_bitmap, t[i])) \
44           << "Error: Reg @ " << i << "-th argument is not in GC map"; \
45   } while (false)
46 
47 struct ReferenceMap2Visitor : public StackVisitor {
48   explicit ReferenceMap2Visitor(Thread* thread)
SHARED_LOCKS_REQUIREDart::ReferenceMap2Visitor49       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
50       : StackVisitor(thread, NULL) {
51   }
52 
VisitFrameart::ReferenceMap2Visitor53   bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
54     mirror::ArtMethod* m = GetMethod();
55     if (!m || m->IsNative() || m->IsRuntimeMethod() || IsShadowFrame()) {
56       return true;
57     }
58     LOG(INFO) << "At " << PrettyMethod(m, false);
59 
60     NativePcOffsetToReferenceMap map(m->GetNativeGcMap(sizeof(void*)));
61 
62     if (m->IsCalleeSaveMethod()) {
63       LOG(WARNING) << "no PC for " << PrettyMethod(m);
64       return true;
65     }
66 
67     const uint8_t* ref_bitmap = NULL;
68     std::string m_name(m->GetName());
69 
70     // Given the method name and the number of times the method has been called,
71     // we know the Dex registers with live reference values. Assert that what we
72     // find is what is expected.
73     if (m_name.compare("f") == 0) {
74       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x03U)));
75       CHECK(ref_bitmap);
76       CHECK_REGS_CONTAIN_REFS(8);  // v8: this
77 
78       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x06U)));
79       CHECK(ref_bitmap);
80       CHECK_REGS_CONTAIN_REFS(8, 1);  // v8: this, v1: x
81 
82       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x08U)));
83       CHECK(ref_bitmap);
84       CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
85 
86       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x0cU)));
87       CHECK(ref_bitmap);
88       CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
89 
90       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x0eU)));
91       CHECK(ref_bitmap);
92       CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
93 
94       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x10U)));
95       CHECK(ref_bitmap);
96       CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
97 
98       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x13U)));
99       CHECK(ref_bitmap);
100       // v2 is added because of the instruction at DexPC 0024. Object merges with 0 is Object. See:
101       //   0024: move-object v3, v2
102       //   0025: goto 0013
103       // Detaled dex instructions for ReferenceMap.java are at the end of this function.
104       // CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1);  // v8: this, v3: y, v2: y, v1: x
105       // We eliminate the non-live registers at a return, so only v3 is live:
106       CHECK_REGS_CONTAIN_REFS(3);  // v3: y
107 
108       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x18U)));
109       CHECK(ref_bitmap);
110       CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
111 
112       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1aU)));
113       CHECK(ref_bitmap);
114       CHECK_REGS_CONTAIN_REFS(8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
115 
116       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1dU)));
117       CHECK(ref_bitmap);
118       CHECK_REGS_CONTAIN_REFS(8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
119 
120       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1fU)));
121       CHECK(ref_bitmap);
122       // v5 is removed from the root set because there is a "merge" operation.
123       // See 0015: if-nez v2, 001f.
124       CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
125 
126       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x21U)));
127       CHECK(ref_bitmap);
128       CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
129 
130       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x27U)));
131       CHECK(ref_bitmap);
132       CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
133 
134       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x29U)));
135       CHECK(ref_bitmap);
136       CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
137 
138       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x2cU)));
139       CHECK(ref_bitmap);
140       CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
141 
142       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x2fU)));
143       CHECK(ref_bitmap);
144       CHECK_REGS_CONTAIN_REFS(8, 4, 3, 2, 1);  // v8: this, v4: ex, v3: y, v2: y, v1: x
145 
146       ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x32U)));
147       CHECK(ref_bitmap);
148       CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1, 0);  // v8: this, v3: y, v2: y, v1: x, v0: ex
149     }
150 
151     return true;
152   }
153 };
154 
155 // Dex instructions for the function 'f' in ReferenceMap.java
156 // Virtual methods   -
157 //    #0              : (in LReferenceMap;)
158 //      name          : 'f'
159 //      type          : '()Ljava/lang/Object;'
160 //      access        : 0x0000 ()
161 //      code          -
162 //      registers     : 9
163 //      ins           : 1
164 //      outs          : 2
165 //      insns size    : 51 16-bit code units
166 //      |[0001e8] ReferenceMap.f:()Ljava/lang/Object;
167 //      |0000: const/4 v4, #int 2 // #2
168 //      |0001: const/4 v7, #int 0 // #0
169 //      |0002: const/4 v6, #int 1 // #1
170 //
171 // 0:[Unknown],1:[Unknown],2:[Unknown],3:[Unknown],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
172 //      |0003: new-array v1, v4, [Ljava/lang/Object;  // type@0007
173 //      |0005: const/4 v2, #int 0 // #0
174 
175 // 0:[Unknown],1:[Reference: java.lang.Object[]],2:[Zero],3:[Unknown],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
176 //      |0006: new-instance v3, Ljava/lang/Object;  // type@0003
177 
178 // [Unknown],1:[Reference: java.lang.Object[]],2:[Zero],3:[Uninitialized Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
179 //      |0008: +invoke-object-init/range {}, Ljava/lang/Object;.<init>:()V // method@0005
180 //      |000b: const/4 v4, #int 2 // #2
181 
182 // 0:[Unknown],1:[Reference: java.lang.Object[]],2:[Zero],3:[Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
183 //      |000c: aput-object v3, v1, v4
184 
185 // 0:[Unknown],1:[Reference: java.lang.Object[]],2:[Zero],3:[Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
186 //      |000e: aput-object v3, v1, v6
187 
188 // 0:[Unknown],1:[Reference: java.lang.Object[]],2:[Zero],3:[Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
189 //      |0010: +invoke-virtual-quick {v8, v7}, [000c] // vtable #000c
190 
191 // 0:[Conflict],1:[Conflict],2:[Conflict],3:[Reference: java.lang.Object],4:[Conflict],5:[Conflict],6:[Conflict],7:[Conflict],8:[Conflict],
192 //      |0013: return-object v3
193 //      |0014: move-exception v0
194 
195 // 0:[Reference: java.lang.Exception],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Conflict],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
196 //      |0015: if-nez v2, 001f // +000a
197 //      |0017: const/4 v4, #int 1 // #1
198 
199 // 0:[Reference: java.lang.Exception],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Conflict],4:[32-bit Constant: 1],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
200 //      |0018: new-instance v5, Ljava/lang/Object;  // type@0003
201 
202 // 0:[Reference: java.lang.Exception],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Conflict],4:[32-bit Constant: 1],5:[Uninitialized Reference: java.lang.Object],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
203 //      |001a: +invoke-object-init/range {}, Ljava/lang/Object;.<init>:()V // method@0005
204 
205 // 0:[Reference: java.lang.Exception],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Conflict],4:[32-bit Constant: 1],5:[Reference: java.lang.Object],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
206 //      |001d: aput-object v5, v1, v4
207 
208 // 0:[Reference: java.lang.Exception],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Conflict],4:[32-bit Constant: 2],5:[Conflict],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
209 //      |001f: aput-object v2, v1, v6
210 
211 // 0:[Reference: java.lang.Exception],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Conflict],4:[32-bit Constant: 2],5:[Conflict],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
212 //      |0021: +invoke-virtual-quick {v8, v7}, [000c] // vtable #000c
213 //      |0024: move-object v3, v2
214 
215 // 0:[Reference: java.lang.Exception],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Conflict],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
216 //      |0025: goto 0013 // -0012
217 //      |0026: move-exception v4
218 
219 // 0:[Conflict],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Conflict],4:[Reference: java.lang.Throwable],5:[Conflict],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
220 //      |0027: aput-object v2, v1, v6
221 
222 // 0:[Conflict],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Conflict],4:[Reference: java.lang.Throwable],5:[Conflict],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
223 //      |0029: +invoke-virtual-quick {v8, v7}, [000c] // vtable #000c
224 
225 // 0:[Conflict],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Conflict],4:[Reference: java.lang.Throwable],5:[Conflict],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
226 //      |002c: throw v4
227 //      |002d: move-exception v4
228 //      |002e: move-object v2, v3
229 
230 // 0:[Unknown],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Reference: java.lang.Object],4:[Reference: java.lang.Throwable],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
231 //      |002f: goto 0027 // -0008
232 //      |0030: move-exception v0
233 //      |0031: move-object v2, v3
234 
235 // 0:[Reference: java.lang.Exception],1:[Reference: java.lang.Object[]],2:[Reference: java.lang.Object],3:[Reference: java.lang.Object],4:[32-bit Constant: 2],5:[Unknown],6:[32-bit Constant: 1],7:[Zero],8:[Reference: ReferenceMap],
236 //      |0032: goto 0015 // -001d
237 //      catches       : 3
238 //        0x0006 - 0x000b
239 //          Ljava/lang/Exception; -> 0x0014
240 //          <any> -> 0x0026
241 //        0x000c - 0x000e
242 //          Ljava/lang/Exception; -> 0x0030
243 //          <any> -> 0x002d
244 //        0x0018 - 0x001f
245 //          <any> -> 0x0026
246 //      positions     :
247 //        0x0003 line=8
248 //        0x0005 line=9
249 //        0x0006 line=11
250 //        0x000b line=12
251 //        0x000e line=18
252 //        0x0010 line=19
253 //        0x0013 line=21
254 //        0x0014 line=13
255 //        0x0015 line=14
256 //        0x0017 line=15
257 //        0x001f line=18
258 //        0x0021 line=19
259 //        0x0025 line=20
260 //        0x0026 line=18
261 //        0x0029 line=19
262 //        0x002d line=18
263 //        0x0030 line=13
264 //      locals        :
265 //        0x0006 - 0x000b reg=2 y Ljava/lang/Object;
266 //        0x000b - 0x0013 reg=3 y Ljava/lang/Object;
267 //        0x0014 - 0x0015 reg=2 y Ljava/lang/Object;
268 //        0x0015 - 0x0026 reg=0 ex Ljava/lang/Exception;
269 //        0x002d - 0x0032 reg=3 y Ljava/lang/Object;
270 //        0x0005 - 0x0033 reg=1 x [Ljava/lang/Object;
271 //        0x0032 - 0x0033 reg=2 y Ljava/lang/Object;
272 //        0x0000 - 0x0033 reg=8 this LReferenceMap;
273 
Java_Main_refmap(JNIEnv *,jobject,jint count)274 extern "C" JNIEXPORT jint JNICALL Java_Main_refmap(JNIEnv*, jobject, jint count) {
275   // Visitor
276   ScopedObjectAccess soa(Thread::Current());
277   ReferenceMap2Visitor mapper(soa.Self());
278   mapper.WalkStack();
279 
280   return count + 1;
281 }
282 
283 }  // namespace art
284