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