Home | History | Annotate | Download | only in native
      1 /*
      2  * Copyright (C) 2008 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  * java.lang.Class native methods
     19  */
     20 #include "Dalvik.h"
     21 #include "native/InternalNativePriv.h"
     22 
     23 /*
     24  * The VM makes guarantees about the atomicity of accesses to primitive
     25  * variables.  These guarantees also apply to elements of arrays.
     26  * In particular, 8-bit, 16-bit, and 32-bit accesses must be atomic and
     27  * must not cause "word tearing".  Accesses to 64-bit array elements must
     28  * either be atomic or treated as two 32-bit operations.  References are
     29  * always read and written atomically, regardless of the number of bits
     30  * used to represent them.
     31  *
     32  * We can't rely on standard libc functions like memcpy() and memmove()
     33  * in our implementation of System.arraycopy(), because they may copy
     34  * byte-by-byte (either for the full run or for "unaligned" parts at the
     35  * start or end).  We need to use functions that guarantee 16-bit or 32-bit
     36  * atomicity as appropriate.
     37  *
     38  * System.arraycopy() is heavily used, so having an efficient implementation
     39  * is important.  The bionic libc provides a platform-optimized memory move
     40  * function that should be used when possible.  If it's not available,
     41  * the trivial "reference implementation" versions below can be used until
     42  * a proper version can be written.
     43  *
     44  * For these functions, The caller must guarantee that dest/src are aligned
     45  * appropriately for the element type, and that n is a multiple of the
     46  * element size.
     47  */
     48 #ifdef __BIONIC__
     49 /* always present in bionic libc */
     50 #define HAVE_MEMMOVE_WORDS
     51 #endif
     52 
     53 #ifdef HAVE_MEMMOVE_WORDS
     54 extern "C" void _memmove_words(void* dest, const void* src, size_t n);
     55 #define move16 _memmove_words
     56 #define move32 _memmove_words
     57 #else
     58 static void move16(void* dest, const void* src, size_t n)
     59 {
     60     assert((((uintptr_t) dest | (uintptr_t) src | n) & 0x01) == 0);
     61 
     62     uint16_t* d = (uint16_t*) dest;
     63     const uint16_t* s = (uint16_t*) src;
     64 
     65     n /= sizeof(uint16_t);
     66 
     67     if (d < s) {
     68         /* copy forward */
     69         while (n--) {
     70             *d++ = *s++;
     71         }
     72     } else {
     73         /* copy backward */
     74         d += n;
     75         s += n;
     76         while (n--) {
     77             *--d = *--s;
     78         }
     79     }
     80 }
     81 
     82 static void move32(void* dest, const void* src, size_t n)
     83 {
     84     assert((((uintptr_t) dest | (uintptr_t) src | n) & 0x03) == 0);
     85 
     86     uint32_t* d = (uint32_t*) dest;
     87     const uint32_t* s = (uint32_t*) src;
     88 
     89     n /= sizeof(uint32_t);
     90 
     91     if (d < s) {
     92         /* copy forward */
     93         while (n--) {
     94             *d++ = *s++;
     95         }
     96     } else {
     97         /* copy backward */
     98         d += n;
     99         s += n;
    100         while (n--) {
    101             *--d = *--s;
    102         }
    103     }
    104 }
    105 #endif /*HAVE_MEMMOVE_WORDS*/
    106 
    107 /*
    108  * public static void arraycopy(Object src, int srcPos, Object dest,
    109  *      int destPos, int length)
    110  *
    111  * The description of this function is long, and describes a multitude
    112  * of checks and exceptions.
    113  */
    114 static void Dalvik_java_lang_System_arraycopy(const u4* args, JValue* pResult)
    115 {
    116     ArrayObject* srcArray = (ArrayObject*) args[0];
    117     int srcPos = args[1];
    118     ArrayObject* dstArray = (ArrayObject*) args[2];
    119     int dstPos = args[3];
    120     int length = args[4];
    121 
    122     /* Check for null pointers. */
    123     if (srcArray == NULL) {
    124         dvmThrowNullPointerException("src == null");
    125         RETURN_VOID();
    126     }
    127     if (dstArray == NULL) {
    128         dvmThrowNullPointerException("dst == null");
    129         RETURN_VOID();
    130     }
    131 
    132     /* Make sure source and destination are arrays. */
    133     if (!dvmIsArray(srcArray)) {
    134         dvmThrowArrayStoreExceptionNotArray(((Object*)srcArray)->clazz, "source");
    135         RETURN_VOID();
    136     }
    137     if (!dvmIsArray(dstArray)) {
    138         dvmThrowArrayStoreExceptionNotArray(((Object*)dstArray)->clazz, "destination");
    139         RETURN_VOID();
    140     }
    141 
    142     /* avoid int overflow */
    143     if (srcPos < 0 || dstPos < 0 || length < 0 ||
    144         srcPos > (int) srcArray->length - length ||
    145         dstPos > (int) dstArray->length - length)
    146     {
    147         dvmThrowExceptionFmt(gDvm.exArrayIndexOutOfBoundsException,
    148             "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
    149             srcArray->length, srcPos, dstArray->length, dstPos, length);
    150         RETURN_VOID();
    151     }
    152 
    153     ClassObject* srcClass = srcArray->clazz;
    154     ClassObject* dstClass = dstArray->clazz;
    155     char srcType = srcClass->descriptor[1];
    156     char dstType = dstClass->descriptor[1];
    157 
    158     /*
    159      * If one of the arrays holds a primitive type, the other array must
    160      * hold the same type.
    161      */
    162     bool srcPrim = (srcType != '[' && srcType != 'L');
    163     bool dstPrim = (dstType != '[' && dstType != 'L');
    164     if (srcPrim || dstPrim) {
    165         if (srcPrim != dstPrim || srcType != dstType) {
    166             dvmThrowArrayStoreExceptionIncompatibleArrays(srcClass, dstClass);
    167             RETURN_VOID();
    168         }
    169 
    170         if (false) ALOGD("arraycopy prim[%c] dst=%p %d src=%p %d len=%d",
    171             srcType, dstArray->contents, dstPos,
    172             srcArray->contents, srcPos, length);
    173 
    174         switch (srcType) {
    175         case 'B':
    176         case 'Z':
    177             /* 1 byte per element */
    178             memmove((u1*) dstArray->contents + dstPos,
    179                 (const u1*) srcArray->contents + srcPos,
    180                 length);
    181             break;
    182         case 'C':
    183         case 'S':
    184             /* 2 bytes per element */
    185             move16((u1*) dstArray->contents + dstPos * 2,
    186                 (const u1*) srcArray->contents + srcPos * 2,
    187                 length * 2);
    188             break;
    189         case 'F':
    190         case 'I':
    191             /* 4 bytes per element */
    192             move32((u1*) dstArray->contents + dstPos * 4,
    193                 (const u1*) srcArray->contents + srcPos * 4,
    194                 length * 4);
    195             break;
    196         case 'D':
    197         case 'J':
    198             /*
    199              * 8 bytes per element.  We don't need to guarantee atomicity
    200              * of the entire 64-bit word, so we can use the 32-bit copier.
    201              */
    202             move32((u1*) dstArray->contents + dstPos * 8,
    203                 (const u1*) srcArray->contents + srcPos * 8,
    204                 length * 8);
    205             break;
    206         default:        /* illegal array type */
    207             ALOGE("Weird array type '%s'", srcClass->descriptor);
    208             dvmAbort();
    209         }
    210     } else {
    211         /*
    212          * Neither class is primitive.  See if elements in "src" are instances
    213          * of elements in "dst" (e.g. copy String to String or String to
    214          * Object).
    215          */
    216         const int width = sizeof(Object*);
    217 
    218         if (srcClass->arrayDim == dstClass->arrayDim &&
    219             dvmInstanceof(srcClass, dstClass))
    220         {
    221             /*
    222              * "dst" can hold "src"; copy the whole thing.
    223              */
    224             if (false) ALOGD("arraycopy ref dst=%p %d src=%p %d len=%d",
    225                 dstArray->contents, dstPos * width,
    226                 srcArray->contents, srcPos * width,
    227                 length * width);
    228             move32((u1*)dstArray->contents + dstPos * width,
    229                 (const u1*)srcArray->contents + srcPos * width,
    230                 length * width);
    231             dvmWriteBarrierArray(dstArray, dstPos, dstPos+length);
    232         } else {
    233             /*
    234              * The arrays are not fundamentally compatible.  However, we
    235              * may still be able to do this if the destination object is
    236              * compatible (e.g. copy Object[] to String[], but the Object
    237              * being copied is actually a String).  We need to copy elements
    238              * one by one until something goes wrong.
    239              *
    240              * Because of overlapping moves, what we really want to do
    241              * is compare the types and count up how many we can move,
    242              * then call move32() to shift the actual data.  If we just
    243              * start from the front we could do a smear rather than a move.
    244              */
    245             Object** srcObj;
    246             int copyCount;
    247             ClassObject*   clazz = NULL;
    248 
    249             srcObj = ((Object**)(void*)srcArray->contents) + srcPos;
    250 
    251             if (length > 0 && srcObj[0] != NULL)
    252             {
    253                 clazz = srcObj[0]->clazz;
    254                 if (!dvmCanPutArrayElement(clazz, dstClass))
    255                     clazz = NULL;
    256             }
    257 
    258             for (copyCount = 0; copyCount < length; copyCount++)
    259             {
    260                 if (srcObj[copyCount] != NULL &&
    261                     srcObj[copyCount]->clazz != clazz &&
    262                     !dvmCanPutArrayElement(srcObj[copyCount]->clazz, dstClass))
    263                 {
    264                     /* can't put this element into the array */
    265                     break;
    266                 }
    267             }
    268 
    269             if (false) ALOGD("arraycopy iref dst=%p %d src=%p %d count=%d of %d",
    270                 dstArray->contents, dstPos * width,
    271                 srcArray->contents, srcPos * width,
    272                 copyCount, length);
    273             move32((u1*)dstArray->contents + dstPos * width,
    274                 (const u1*)srcArray->contents + srcPos * width,
    275                 copyCount * width);
    276             dvmWriteBarrierArray(dstArray, 0, copyCount);
    277             if (copyCount != length) {
    278                 dvmThrowArrayStoreExceptionIncompatibleArrayElement(srcPos + copyCount,
    279                         srcObj[copyCount]->clazz, dstClass);
    280                 RETURN_VOID();
    281             }
    282         }
    283     }
    284 
    285     RETURN_VOID();
    286 }
    287 
    288 /*
    289  * static long currentTimeMillis()
    290  *
    291  * Current time, in miliseconds.  This doesn't need to be internal to the
    292  * VM, but we're already handling java.lang.System here.
    293  */
    294 static void Dalvik_java_lang_System_currentTimeMillis(const u4* args,
    295     JValue* pResult)
    296 {
    297     struct timeval tv;
    298 
    299     UNUSED_PARAMETER(args);
    300 
    301     gettimeofday(&tv, (struct timezone *) NULL);
    302     long long when = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
    303 
    304     RETURN_LONG(when);
    305 }
    306 
    307 /*
    308  * static long nanoTime()
    309  *
    310  * Current monotonically-increasing time, in nanoseconds.  This doesn't
    311  * need to be internal to the VM, but we're already handling
    312  * java.lang.System here.
    313  */
    314 static void Dalvik_java_lang_System_nanoTime(const u4* args, JValue* pResult)
    315 {
    316     UNUSED_PARAMETER(args);
    317 
    318     u8 when = dvmGetRelativeTimeNsec();
    319     RETURN_LONG(when);
    320 }
    321 
    322 /*
    323  * static int identityHashCode(Object x)
    324  *
    325  * Returns that hash code that the default hashCode()
    326  * method would return for "x", even if "x"s class
    327  * overrides hashCode().
    328  */
    329 static void Dalvik_java_lang_System_identityHashCode(const u4* args,
    330     JValue* pResult)
    331 {
    332     Object* thisPtr = (Object*) args[0];
    333     RETURN_INT(dvmIdentityHashCode(thisPtr));
    334 }
    335 
    336 static void Dalvik_java_lang_System_mapLibraryName(const u4* args,
    337     JValue* pResult)
    338 {
    339     StringObject* nameObj = (StringObject*) args[0];
    340     StringObject* result = NULL;
    341     char* name;
    342     char* mappedName;
    343 
    344     if (nameObj == NULL) {
    345         dvmThrowNullPointerException("userLibName == null");
    346         RETURN_VOID();
    347     }
    348 
    349     name = dvmCreateCstrFromString(nameObj);
    350     mappedName = dvmCreateSystemLibraryName(name);
    351     if (mappedName != NULL) {
    352         result = dvmCreateStringFromCstr(mappedName);
    353         dvmReleaseTrackedAlloc((Object*) result, NULL);
    354     }
    355 
    356     free(name);
    357     free(mappedName);
    358     RETURN_PTR(result);
    359 }
    360 
    361 const DalvikNativeMethod dvm_java_lang_System[] = {
    362     { "arraycopy",          "(Ljava/lang/Object;ILjava/lang/Object;II)V",
    363         Dalvik_java_lang_System_arraycopy },
    364     { "currentTimeMillis",  "()J",
    365         Dalvik_java_lang_System_currentTimeMillis },
    366     { "identityHashCode",  "(Ljava/lang/Object;)I",
    367         Dalvik_java_lang_System_identityHashCode },
    368     { "mapLibraryName",     "(Ljava/lang/String;)Ljava/lang/String;",
    369         Dalvik_java_lang_System_mapLibraryName },
    370     { "nanoTime",  "()J",
    371         Dalvik_java_lang_System_nanoTime },
    372     { NULL, NULL, NULL },
    373 };
    374