OSDN Git Service

am 486ac3c0: Removing inaccurate and unmaintained docs.
[android-x86/dalvik.git] / vm / native / java_lang_System.c
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 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;
117     ArrayObject* dstArray;
118     ClassObject* srcClass;
119     ClassObject* dstClass;
120     int srcPos, dstPos, length;
121     char srcType, dstType;
122     bool srcPrim, dstPrim;
123
124     srcArray = (ArrayObject*) args[0];
125     srcPos = args[1];
126     dstArray = (ArrayObject*) args[2];
127     dstPos = args[3];
128     length = args[4];
129
130     /* check for null or bad pointer */
131     if (!dvmValidateObject((Object*)srcArray) ||
132         !dvmValidateObject((Object*)dstArray))
133     {
134         assert(dvmCheckException(dvmThreadSelf()));
135         RETURN_VOID();
136     }
137
138     /* make sure it's an array */
139     if (!dvmIsArray(srcArray) || !dvmIsArray(dstArray)) {
140         dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
141             "source and destination must be arrays, but were %s and %s",
142             ((Object*)srcArray)->clazz->descriptor,
143             ((Object*)dstArray)->clazz->descriptor);
144         RETURN_VOID();
145     }
146
147     /* avoid int overflow */
148     if (srcPos < 0 || dstPos < 0 || length < 0 ||
149         srcPos > (int) srcArray->length - length ||
150         dstPos > (int) dstArray->length - length)
151     {
152         dvmThrowExceptionFmt("Ljava/lang/ArrayIndexOutOfBoundsException;",
153             "src.length=%d srcPos=%d dst.length=%d dstPos=%d length=%d",
154             srcArray->length, srcPos, dstArray->length, dstPos, length);
155         RETURN_VOID();
156     }
157
158     srcClass = srcArray->obj.clazz;
159     dstClass = dstArray->obj.clazz;
160     srcType = srcClass->descriptor[1];
161     dstType = dstClass->descriptor[1];
162
163     /*
164      * If one of the arrays holds a primitive type, the other array must
165      * hold the same type.
166      */
167     srcPrim = (srcType != '[' && srcType != 'L');
168     dstPrim = (dstType != '[' && dstType != 'L');
169     if (srcPrim || dstPrim) {
170         if (srcPrim != dstPrim || srcType != dstType) {
171             dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
172                 "source and destination arrays are incompatible: %s and %s",
173                 srcClass->descriptor, dstClass->descriptor);
174             RETURN_VOID();
175         }
176
177         if (false) LOGD("arraycopy prim[%c] dst=%p %d src=%p %d len=%d\n",
178             srcType, dstArray->contents, dstPos,
179             srcArray->contents, srcPos, length);
180
181         switch (srcType) {
182         case 'B':
183         case 'Z':
184             /* 1 byte per element */
185             memmove((u1*) dstArray->contents + dstPos,
186                 (const u1*) srcArray->contents + srcPos,
187                 length);
188             break;
189         case 'C':
190         case 'S':
191             /* 2 bytes per element */
192             move16((u1*) dstArray->contents + dstPos * 2,
193                 (const u1*) srcArray->contents + srcPos * 2,
194                 length * 2);
195             break;
196         case 'F':
197         case 'I':
198             /* 4 bytes per element */
199             move32((u1*) dstArray->contents + dstPos * 4,
200                 (const u1*) srcArray->contents + srcPos * 4,
201                 length * 4);
202             break;
203         case 'D':
204         case 'J':
205             /*
206              * 8 bytes per element.  We don't need to guarantee atomicity
207              * of the entire 64-bit word, so we can use the 32-bit copier.
208              */
209             move32((u1*) dstArray->contents + dstPos * 8,
210                 (const u1*) srcArray->contents + srcPos * 8,
211                 length * 8);
212             break;
213         default:        /* illegal array type */
214             LOGE("Weird array type '%s'\n", srcClass->descriptor);
215             dvmAbort();
216         }
217     } else {
218         /*
219          * Neither class is primitive.  See if elements in "src" are instances
220          * of elements in "dst" (e.g. copy String to String or String to
221          * Object).
222          */
223         const int width = sizeof(Object*);
224
225         if (srcClass->arrayDim == dstClass->arrayDim &&
226             dvmInstanceof(srcClass, dstClass))
227         {
228             /*
229              * "dst" can hold "src"; copy the whole thing.
230              */
231             if (false) LOGD("arraycopy ref dst=%p %d src=%p %d len=%d\n",
232                 dstArray->contents, dstPos * width,
233                 srcArray->contents, srcPos * width,
234                 length * width);
235             move32((u1*)dstArray->contents + dstPos * width,
236                 (const u1*)srcArray->contents + srcPos * width,
237                 length * width);
238             dvmWriteBarrierArray(dstArray, dstPos, dstPos+length);
239         } else {
240             /*
241              * The arrays are not fundamentally compatible.  However, we
242              * may still be able to do this if the destination object is
243              * compatible (e.g. copy Object[] to String[], but the Object
244              * being copied is actually a String).  We need to copy elements
245              * one by one until something goes wrong.
246              *
247              * Because of overlapping moves, what we really want to do
248              * is compare the types and count up how many we can move,
249              * then call move32() to shift the actual data.  If we just
250              * start from the front we could do a smear rather than a move.
251              */
252             Object** srcObj;
253             Object** dstObj;
254             int copyCount;
255             ClassObject*   clazz = NULL;
256
257             srcObj = ((Object**) srcArray->contents) + srcPos;
258             dstObj = ((Object**) dstArray->contents) + dstPos;
259
260             if (length > 0 && srcObj[0] != NULL)
261             {
262                 clazz = srcObj[0]->clazz;
263                 if (!dvmCanPutArrayElement(clazz, dstClass))
264                     clazz = NULL;
265             }
266
267             for (copyCount = 0; copyCount < length; copyCount++)
268             {
269                 if (srcObj[copyCount] != NULL &&
270                     srcObj[copyCount]->clazz != clazz &&
271                     !dvmCanPutArrayElement(srcObj[copyCount]->clazz, dstClass))
272                 {
273                     /* can't put this element into the array */
274                     break;
275                 }
276             }
277
278             if (false) LOGD("arraycopy iref dst=%p %d src=%p %d count=%d of %d\n",
279                 dstArray->contents, dstPos * width,
280                 srcArray->contents, srcPos * width,
281                 copyCount, length);
282             move32((u1*)dstArray->contents + dstPos * width,
283                 (const u1*)srcArray->contents + srcPos * width,
284                 copyCount * width);
285             dvmWriteBarrierArray(dstArray, 0, copyCount);
286             if (copyCount != length) {
287                 dvmThrowExceptionFmt("Ljava/lang/ArrayStoreException;",
288                     "source[%d] of type %s cannot be stored in destination array of type %s",
289                     copyCount, srcObj[copyCount]->clazz->descriptor,
290                     dstClass->descriptor);
291                 RETURN_VOID();
292             }
293         }
294     }
295
296     RETURN_VOID();
297 }
298
299 /*
300  * static long currentTimeMillis()
301  *
302  * Current time, in miliseconds.  This doesn't need to be internal to the
303  * VM, but we're already handling java.lang.System here.
304  */
305 static void Dalvik_java_lang_System_currentTimeMillis(const u4* args,
306     JValue* pResult)
307 {
308     struct timeval tv;
309
310     UNUSED_PARAMETER(args);
311
312     gettimeofday(&tv, (struct timezone *) NULL);
313     long long when = tv.tv_sec * 1000LL + tv.tv_usec / 1000;
314
315     RETURN_LONG(when);
316 }
317
318 /*
319  * static long nanoTime()
320  *
321  * Current monotonically-increasing time, in nanoseconds.  This doesn't
322  * need to be internal to the VM, but we're already handling
323  * java.lang.System here.
324  */
325 static void Dalvik_java_lang_System_nanoTime(const u4* args, JValue* pResult)
326 {
327     UNUSED_PARAMETER(args);
328
329     u8 when = dvmGetRelativeTimeNsec();
330     RETURN_LONG(when);
331 }
332
333 /*
334  * static int identityHashCode(Object x)
335  *
336  * Returns that hash code that the default hashCode()
337  * method would return for "x", even if "x"s class
338  * overrides hashCode().
339  */
340 static void Dalvik_java_lang_System_identityHashCode(const u4* args,
341     JValue* pResult)
342 {
343     Object* thisPtr = (Object*) args[0];
344     RETURN_INT(dvmIdentityHashCode(thisPtr));
345 }
346
347 /*
348  * public static String mapLibraryName(String libname)
349  */
350 static void Dalvik_java_lang_System_mapLibraryName(const u4* args,
351     JValue* pResult)
352 {
353     StringObject* nameObj = (StringObject*) args[0];
354     StringObject* result = NULL;
355     char* name;
356     char* mappedName;
357
358     if (nameObj == NULL) {
359         dvmThrowException("Ljava/lang/NullPointerException;", NULL);
360         RETURN_VOID();
361     }
362
363     name = dvmCreateCstrFromString(nameObj);
364     mappedName = dvmCreateSystemLibraryName(name);
365     if (mappedName != NULL) {
366         result = dvmCreateStringFromCstr(mappedName);
367         dvmReleaseTrackedAlloc((Object*) result, NULL);
368     }
369
370     free(name);
371     free(mappedName);
372     RETURN_PTR(result);
373 }
374
375 const DalvikNativeMethod dvm_java_lang_System[] = {
376     { "arraycopy",          "(Ljava/lang/Object;ILjava/lang/Object;II)V",
377         Dalvik_java_lang_System_arraycopy },
378     { "currentTimeMillis",  "()J",
379         Dalvik_java_lang_System_currentTimeMillis },
380     { "nanoTime",  "()J",
381         Dalvik_java_lang_System_nanoTime },
382     { "identityHashCode",  "(Ljava/lang/Object;)I",
383         Dalvik_java_lang_System_identityHashCode },
384     { "mapLibraryName",     "(Ljava/lang/String;)Ljava/lang/String;",
385         Dalvik_java_lang_System_mapLibraryName },
386     { NULL, NULL, NULL },
387 };