Home | History | Annotate | Download | only in ReferenceMap
      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)
     51       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
     52       : StackVisitor(thread, NULL) {
     53   }
     54 
     55   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 
    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