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 */
copy(void * dest,const void * src,size_t n,bool sameArray,size_t elemSize)26 static 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 */
Dalvik_java_lang_System_arraycopy(const u4 * args,JValue * pResult)58 static 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 */
Dalvik_java_lang_System_currentTimeMillis(const u4 * args,JValue * pResult)247 static 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 */
Dalvik_java_lang_System_nanoTime(const u4 * args,JValue * pResult)267 static 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 */
Dalvik_java_lang_System_identityHashCode(const u4 * args,JValue * pResult)282 static 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 */
Dalvik_java_lang_System_mapLibraryName(const u4 * args,JValue * pResult)292 static 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
317 const 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