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