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
19 */
20#include "Dalvik.h"
21#include "native/InternalNativePriv.h"
22
23/*
24 * Call the appropriate copy function given the circumstances.
25 */
26static void copy(void *dest, const void *src, size_t n, bool sameArray,
27        size_t elemSize)
28{
29    if (sameArray) {
30        /* Might overlap. */
31        if (elemSize == sizeof(Object*)) {
32            /*
33             * In addition to handling overlap properly, bcopy()
34             * guarantees atomic treatment of words. This is needed so
35             * that concurrent threads never see half-formed pointers
36             * or ints. The former is required for proper gc behavior,
37             * and the latter is also required for proper high-level
38             * language support.
39             *
40             * Note: bcopy()'s argument order is different than memcpy().
41             */
42            bcopy(src, dest, n);
43        } else {
44            memmove(dest, src, n);
45        }
46    } else {
47        memcpy(dest, src, n); /* Can't overlap; use faster function. */
48    }
49}
50
51/*
52 * public static void arraycopy(Object src, int srcPos, Object dest,
53 *      int destPos, int length)
54 *
55 * The description of this function is long, and describes a multitude
56 * of checks and exceptions.
57 */
58static void Dalvik_java_lang_System_arraycopy(const u4* args, JValue* pResult)
59{
60    ArrayObject* srcArray;
61    ArrayObject* dstArray;
62    ClassObject* srcClass;
63    ClassObject* dstClass;
64    int srcPos, dstPos, length;
65    char srcType, dstType;
66    bool srcPrim, dstPrim;
67    bool sameArray;
68
69    srcArray = (ArrayObject*) args[0];
70    srcPos = args[1];
71    dstArray = (ArrayObject*) args[2];
72    dstPos = args[3];
73    length = args[4];
74
75    sameArray = (srcArray == dstArray);
76
77    /* check for null or bad pointer */
78    if (!dvmValidateObject((Object*)srcArray) ||
79        !dvmValidateObject((Object*)dstArray))
80    {
81        assert(dvmCheckException(dvmThreadSelf()));
82        RETURN_VOID();
83    }
84    /* make sure it's an array */
85    if (!dvmIsArray(srcArray) || !dvmIsArray(dstArray)) {
86        dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
87            "source and destination must be arrays, but were %s and %s",
88            ((Object*)srcArray)->clazz->descriptor,
89            ((Object*)dstArray)->clazz->descriptor);
90        RETURN_VOID();
91    }
92
93    // avoid int overflow
94    if (srcPos < 0 || dstPos < 0 || length < 0 ||
95        srcPos > (int) srcArray->length - length ||
96        dstPos > (int) dstArray->length - length)
97    {
98        dvmThrowExceptionFmt("Ljava/lang/ArrayIndexOutOfBoundsException;",
99            "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
100            srcArray->length, srcPos, dstArray->length, dstPos, length);
101        RETURN_VOID();
102    }
103
104    srcClass = srcArray->obj.clazz;
105    dstClass = dstArray->obj.clazz;
106    srcType = srcClass->descriptor[1];
107    dstType = dstClass->descriptor[1];
108
109    /*
110     * If one of the arrays holds a primitive type, the other array must
111     * hold the same type.
112     */
113    srcPrim = (srcType != '[' && srcType != 'L');
114    dstPrim = (dstType != '[' && dstType != 'L');
115    if (srcPrim || dstPrim) {
116        int width;
117
118        if (srcPrim != dstPrim || srcType != dstType) {
119            dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
120                "source and destination arrays are incompatible: %s and %s",
121                srcClass->descriptor, dstClass->descriptor);
122            RETURN_VOID();
123        }
124
125        switch (srcClass->descriptor[1]) {
126        case 'B':
127        case 'Z':
128            width = 1;
129            break;
130        case 'C':
131        case 'S':
132            width = 2;
133            break;
134        case 'F':
135        case 'I':
136            width = 4;
137            break;
138        case 'D':
139        case 'J':
140            width = 8;
141            break;
142        default:        /* 'V' or something weird */
143            LOGE("Weird array type '%s'\n", srcClass->descriptor);
144            assert(false);
145            width = 0;
146            break;
147        }
148
149        if (false) LOGVV("arraycopy prim dst=%p %d src=%p %d len=%d\n",
150                dstArray->contents, dstPos * width,
151                srcArray->contents, srcPos * width,
152                length * width);
153        copy((u1*)dstArray->contents + dstPos * width,
154                (const u1*)srcArray->contents + srcPos * width,
155                length * width,
156                sameArray, width);
157    } else {
158        /*
159         * Neither class is primitive.  See if elements in "src" are instances
160         * of elements in "dst" (e.g. copy String to String or String to
161         * Object).
162         */
163        int width = sizeof(Object*);
164
165        if (srcClass->arrayDim == dstClass->arrayDim &&
166            dvmInstanceof(srcClass, dstClass))
167        {
168            /*
169             * "dst" can hold "src"; copy the whole thing.
170             */
171            if (false) LOGVV("arraycopy ref dst=%p %d src=%p %d len=%d\n",
172                dstArray->contents, dstPos * width,
173                srcArray->contents, srcPos * width,
174                length * width);
175            copy((u1*)dstArray->contents + dstPos * width,
176                    (const u1*)srcArray->contents + srcPos * width,
177                    length * width,
178                    sameArray, width);
179            dvmWriteBarrierArray(dstArray, dstPos, dstPos+length);
180        } else {
181            /*
182             * The arrays are not fundamentally compatible.  However, we may
183             * still be able to do this if the destination object is compatible
184             * (e.g. copy Object to String, but the Object being copied is
185             * actually a String).  We need to copy elements one by one until
186             * something goes wrong.
187             *
188             * Because of overlapping moves, what we really want to do is
189             * compare the types and count up how many we can move, then call
190             * memmove() to shift the actual data.  If we just start from the
191             * front we could do a smear rather than a move.
192             */
193            Object** srcObj;
194            Object** dstObj;
195            int copyCount;
196            ClassObject*   clazz = NULL;
197
198            srcObj = ((Object**) srcArray->contents) + srcPos;
199            dstObj = ((Object**) dstArray->contents) + dstPos;
200
201            if (length > 0 && srcObj[0] != NULL)
202            {
203                clazz = srcObj[0]->clazz;
204                if (!dvmCanPutArrayElement(clazz, dstClass))
205                    clazz = NULL;
206            }
207
208            for (copyCount = 0; copyCount < length; copyCount++)
209            {
210                if (srcObj[copyCount] != NULL &&
211                    srcObj[copyCount]->clazz != clazz &&
212                    !dvmCanPutArrayElement(srcObj[copyCount]->clazz, dstClass))
213                {
214                    /* can't put this element into the array */
215                    break;
216                }
217            }
218
219            if (false) LOGVV("arraycopy iref dst=%p %d src=%p %d count=%d of %d\n",
220                dstArray->contents, dstPos * width,
221                srcArray->contents, srcPos * width,
222                copyCount, length);
223            copy((u1*)dstArray->contents + dstPos * width,
224                    (const u1*)srcArray->contents + srcPos * width,
225                    copyCount * width,
226                    sameArray, width);
227            dvmWriteBarrierArray(dstArray, 0, copyCount);
228            if (copyCount != length) {
229                dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
230                    "source[%d] of type %s cannot be stored in destination array of type %s",
231                    copyCount, srcObj[copyCount]->clazz->descriptor,
232                    dstClass->descriptor);
233                RETURN_VOID();
234            }
235        }
236    }
237
238    RETURN_VOID();
239}
240
241/*
242 * static long currentTimeMillis()
243 *
244 * Current time, in miliseconds.  This doesn't need to be internal to the
245 * VM, but we're already handling java.lang.System here.
246 */
247static void Dalvik_java_lang_System_currentTimeMillis(const u4* args,
248    JValue* pResult)
249{
250    struct timeval tv;
251
252    UNUSED_PARAMETER(args);
253
254    gettimeofday(&tv, (struct timezone *) NULL);
255    long long when = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
256
257    RETURN_LONG(when);
258}
259
260/*
261 * static long nanoTime()
262 *
263 * Current monotonically-increasing time, in nanoseconds.  This doesn't
264 * need to be internal to the VM, but we're already handling
265 * java.lang.System here.
266 */
267static void Dalvik_java_lang_System_nanoTime(const u4* args, JValue* pResult)
268{
269    UNUSED_PARAMETER(args);
270
271    u8 when = dvmGetRelativeTimeNsec();
272    RETURN_LONG(when);
273}
274
275/*
276 * static int identityHashCode(Object x)
277 *
278 * Returns that hash code that the default hashCode()
279 * method would return for "x", even if "x"s class
280 * overrides hashCode().
281 */
282static void Dalvik_java_lang_System_identityHashCode(const u4* args,
283    JValue* pResult)
284{
285    Object* thisPtr = (Object*) args[0];
286    RETURN_INT(dvmIdentityHashCode(thisPtr));
287}
288
289/*
290 * public static String mapLibraryName(String libname)
291 */
292static void Dalvik_java_lang_System_mapLibraryName(const u4* args,
293    JValue* pResult)
294{
295    StringObject* nameObj = (StringObject*) args[0];
296    StringObject* result = NULL;
297    char* name;
298    char* mappedName;
299
300    if (nameObj == NULL) {
301        dvmThrowException("Ljava/lang/NullPointerException;", NULL);
302        RETURN_VOID();
303    }
304
305    name = dvmCreateCstrFromString(nameObj);
306    mappedName = dvmCreateSystemLibraryName(name);
307    if (mappedName != NULL) {
308        result = dvmCreateStringFromCstr(mappedName);
309        dvmReleaseTrackedAlloc((Object*) result, NULL);
310    }
311
312    free(name);
313    free(mappedName);
314    RETURN_PTR(result);
315}
316
317const DalvikNativeMethod dvm_java_lang_System[] = {
318    { "arraycopy",          "(Ljava/lang/Object;ILjava/lang/Object;II)V",
319        Dalvik_java_lang_System_arraycopy },
320    { "currentTimeMillis",  "()J",
321        Dalvik_java_lang_System_currentTimeMillis },
322    { "nanoTime",  "()J",
323        Dalvik_java_lang_System_nanoTime },
324    { "identityHashCode",  "(Ljava/lang/Object;)I",
325        Dalvik_java_lang_System_identityHashCode },
326    { "mapLibraryName",     "(Ljava/lang/String;)Ljava/lang/String;",
327        Dalvik_java_lang_System_mapLibraryName },
328    { NULL, NULL, NULL },
329};
330