Home | History | Annotate | Download | only in test
      1 /*
      2  * Copyright (C) 2009 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 /*
     18  * Test the indirect reference table implementation.
     19  */
     20 #include "Dalvik.h"
     21 
     22 #include <stdlib.h>
     23 
     24 #ifndef NDEBUG
     25 
     26 #define DBUG_MSG    LOGI
     27 
     28 /*
     29  * Basic add/get/delete tests in an unsegmented table.
     30  */
     31 static bool basicTest()
     32 {
     33     static const int kTableMax = 20;
     34     IndirectRefTable irt;
     35     IndirectRef iref0, iref1, iref2, iref3;
     36     IndirectRef manyRefs[kTableMax];
     37     ClassObject* clazz = dvmFindClass("Ljava/lang/Object;", NULL);
     38     Object* obj0 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
     39     Object* obj1 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
     40     Object* obj2 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
     41     Object* obj3 = dvmAllocObject(clazz, ALLOC_DONT_TRACK);
     42     const u4 cookie = IRT_FIRST_SEGMENT;
     43     bool result = false;
     44 
     45     if (!irt.init(kTableMax/2, kTableMax, kIndirectKindGlobal)) {
     46         return false;
     47     }
     48 
     49     iref0 = (IndirectRef) 0x11110;
     50     if (irt.remove(cookie, iref0)) {
     51         LOGE("unexpectedly successful removal");
     52         goto bail;
     53     }
     54 
     55     /*
     56      * Add three, check, remove in the order in which they were added.
     57      */
     58     DBUG_MSG("+++ START fifo\n");
     59     iref0 = irt.add(cookie, obj0);
     60     iref1 = irt.add(cookie, obj1);
     61     iref2 = irt.add(cookie, obj2);
     62     if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
     63         LOGE("trivial add1 failed");
     64         goto bail;
     65     }
     66 
     67     if (irt.get(iref0) != obj0 ||
     68             irt.get(iref1) != obj1 ||
     69             irt.get(iref2) != obj2) {
     70         LOGE("objects don't match expected values %p %p %p vs. %p %p %p",
     71                 irt.get(iref0), irt.get(iref1), irt.get(iref2),
     72                 obj0, obj1, obj2);
     73         goto bail;
     74     } else {
     75         DBUG_MSG("+++ obj1=%p --> iref1=%p\n", obj1, iref1);
     76     }
     77 
     78     if (!irt.remove(cookie, iref0) ||
     79             !irt.remove(cookie, iref1) ||
     80             !irt.remove(cookie, iref2))
     81     {
     82         LOGE("fifo deletion failed");
     83         goto bail;
     84     }
     85 
     86     /* table should be empty now */
     87     if (irt.capacity() != 0) {
     88         LOGE("fifo del not empty");
     89         goto bail;
     90     }
     91 
     92     /* get invalid entry (off the end of the list) */
     93     if (irt.get(iref0) != kInvalidIndirectRefObject) {
     94         LOGE("stale entry get succeeded unexpectedly");
     95         goto bail;
     96     }
     97 
     98     /*
     99      * Add three, remove in the opposite order.
    100      */
    101     DBUG_MSG("+++ START lifo\n");
    102     iref0 = irt.add(cookie, obj0);
    103     iref1 = irt.add(cookie, obj1);
    104     iref2 = irt.add(cookie, obj2);
    105     if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
    106         LOGE("trivial add2 failed");
    107         goto bail;
    108     }
    109 
    110     if (!irt.remove(cookie, iref2) ||
    111             !irt.remove(cookie, iref1) ||
    112             !irt.remove(cookie, iref0))
    113     {
    114         LOGE("lifo deletion failed");
    115         goto bail;
    116     }
    117 
    118     /* table should be empty now */
    119     if (irt.capacity() != 0) {
    120         LOGE("lifo del not empty");
    121         goto bail;
    122     }
    123 
    124     /*
    125      * Add three, remove middle / middle / bottom / top.  (Second attempt
    126      * to remove middle should fail.)
    127      */
    128     DBUG_MSG("+++ START unorder\n");
    129     iref0 = irt.add(cookie, obj0);
    130     iref1 = irt.add(cookie, obj1);
    131     iref2 = irt.add(cookie, obj2);
    132     if (iref0 == NULL || iref1 == NULL || iref2 == NULL) {
    133         LOGE("trivial add3 failed");
    134         goto bail;
    135     }
    136 
    137     if (irt.capacity() != 3) {
    138         LOGE("expected 3 entries, found %d", irt.capacity());
    139         goto bail;
    140     }
    141 
    142     if (!irt.remove(cookie, iref1) || irt.remove(cookie, iref1)) {
    143         LOGE("unorder deletion1 failed");
    144         goto bail;
    145     }
    146 
    147     /* get invalid entry (from hole) */
    148     if (irt.get(iref1) != kInvalidIndirectRefObject) {
    149         LOGE("hole get succeeded unexpectedly");
    150         goto bail;
    151     }
    152 
    153     if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
    154         LOGE("unorder deletion2 failed");
    155         goto bail;
    156     }
    157 
    158     /* table should be empty now */
    159     if (irt.capacity() != 0) {
    160         LOGE("unorder del not empty");
    161         goto bail;
    162     }
    163 
    164     /*
    165      * Add four entries.  Remove #1, add new entry, verify that table size
    166      * is still 4 (i.e. holes are getting filled).  Remove #1 and #3, verify
    167      * that we delete one and don't hole-compact the other.
    168      */
    169     DBUG_MSG("+++ START hole fill\n");
    170     iref0 = irt.add(cookie, obj0);
    171     iref1 = irt.add(cookie, obj1);
    172     iref2 = irt.add(cookie, obj2);
    173     iref3 = irt.add(cookie, obj3);
    174     if (iref0 == NULL || iref1 == NULL || iref2 == NULL || iref3 == NULL) {
    175         LOGE("trivial add4 failed");
    176         goto bail;
    177     }
    178     if (!irt.remove(cookie, iref1)) {
    179         LOGE("remove 1 of 4 failed");
    180         goto bail;
    181     }
    182     iref1 = irt.add(cookie, obj1);
    183     if (irt.capacity() != 4) {
    184         LOGE("hole not filled");
    185         goto bail;
    186     }
    187     if (!irt.remove(cookie, iref1) || !irt.remove(cookie, iref3)) {
    188         LOGE("remove 1/3 failed");
    189         goto bail;
    190     }
    191     if (irt.capacity() != 3) {
    192         LOGE("should be 3 after two deletions");
    193         goto bail;
    194     }
    195     if (!irt.remove(cookie, iref2) || !irt.remove(cookie, iref0)) {
    196         LOGE("remove 2/0 failed");
    197         goto bail;
    198     }
    199     if (irt.capacity() != 0) {
    200         LOGE("not empty after split remove");
    201         goto bail;
    202     }
    203 
    204     /*
    205      * Add an entry, remove it, add a new entry, and try to use the original
    206      * iref.  They have the same slot number but are for different objects.
    207      * With the extended checks in place, this should fail.
    208      */
    209     DBUG_MSG("+++ START switched\n");
    210     iref0 = irt.add(cookie, obj0);
    211     irt.remove(cookie, iref0);
    212     iref1 = irt.add(cookie, obj1);
    213     if (irt.remove(cookie, iref0)) {
    214         LOGE("mismatched del succeeded (%p vs %p)", iref0, iref1);
    215         goto bail;
    216     }
    217     if (!irt.remove(cookie, iref1)) {
    218         LOGE("switched del failed");
    219         goto bail;
    220     }
    221     if (irt.capacity() != 0) {
    222         LOGE("switching del not empty");
    223         goto bail;
    224     }
    225 
    226     /*
    227      * Same as above, but with the same object.  A more rigorous checker
    228      * (e.g. with slot serialization) will catch this.
    229      */
    230     DBUG_MSG("+++ START switched same object\n");
    231     iref0 = irt.add(cookie, obj0);
    232     irt.remove(cookie, iref0);
    233     iref1 = irt.add(cookie, obj0);
    234     if (iref0 != iref1) {
    235         /* try 0, should not work */
    236         if (irt.remove(cookie, iref0)) {
    237             LOGE("temporal del succeeded (%p vs %p)", iref0, iref1);
    238             goto bail;
    239         }
    240     }
    241     if (!irt.remove(cookie, iref1)) {
    242         LOGE("temporal cleanup failed");
    243         goto bail;
    244     }
    245     if (irt.capacity() != 0) {
    246         LOGE("temporal del not empty");
    247         goto bail;
    248     }
    249 
    250     DBUG_MSG("+++ START null lookup\n");
    251     if (irt.get(NULL) != kInvalidIndirectRefObject) {
    252         LOGE("null lookup succeeded");
    253         goto bail;
    254     }
    255 
    256     DBUG_MSG("+++ START stale lookup\n");
    257     iref0 = irt.add(cookie, obj0);
    258     irt.remove(cookie, iref0);
    259     if (irt.get(iref0) != kInvalidIndirectRefObject) {
    260         LOGE("stale lookup succeeded");
    261         goto bail;
    262     }
    263 
    264     /*
    265      * Test table overflow.
    266      */
    267     DBUG_MSG("+++ START overflow\n");
    268     int i;
    269     for (i = 0; i < kTableMax; i++) {
    270         manyRefs[i] = irt.add(cookie, obj0);
    271         if (manyRefs[i] == NULL) {
    272             LOGE("Failed adding %d of %d", i, kTableMax);
    273             goto bail;
    274         }
    275     }
    276     if (irt.add(cookie, obj0) != NULL) {
    277         LOGE("Table overflow succeeded");
    278         goto bail;
    279     }
    280     if (irt.capacity() != (size_t)kTableMax) {
    281         LOGE("Expected %d entries, found %d", kTableMax, irt.capacity());
    282         goto bail;
    283     }
    284     irt.dump("table with 20 entries, all filled");
    285     for (i = 0; i < kTableMax-1; i++) {
    286         if (!irt.remove(cookie, manyRefs[i])) {
    287             LOGE("multi-remove failed at %d", i);
    288             goto bail;
    289         }
    290     }
    291     irt.dump("table with 20 entries, 19 of them holes");
    292     /* because of removal order, should have 20 entries, 19 of them holes */
    293     if (irt.capacity() != (size_t)kTableMax) {
    294         LOGE("Expected %d entries (with holes), found %d",
    295                 kTableMax, irt.capacity());
    296         goto bail;
    297     }
    298     if (!irt.remove(cookie, manyRefs[kTableMax-1])) {
    299         LOGE("multi-remove final failed");
    300         goto bail;
    301     }
    302     if (irt.capacity() != 0) {
    303         LOGE("multi-del not empty");
    304         goto bail;
    305     }
    306 
    307     /* Done */
    308     DBUG_MSG("+++ basic test complete\n");
    309     result = true;
    310 
    311 bail:
    312     irt.destroy();
    313     return result;
    314 }
    315 
    316 /*
    317  * Some quick tests.
    318  */
    319 bool dvmTestIndirectRefTable()
    320 {
    321     if (!basicTest()) {
    322         LOGE("IRT basic test failed");
    323         return false;
    324     }
    325 
    326     return true;
    327 }
    328 
    329 #endif /*NDEBUG*/
    330