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