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 * Array objects. 18 */ 19 #include "Dalvik.h" 20 21 #include <stdlib.h> 22 #include <stddef.h> 23 24 #if WITH_HPROF && WITH_HPROF_STACK 25 #include "hprof/Hprof.h" 26 #endif 27 28 static ClassObject* createArrayClass(const char* descriptor, Object* loader); 29 static ClassObject* createPrimitiveClass(int idx); 30 31 static const char gPrimLetter[] = PRIM_TYPE_TO_LETTER; 32 33 /* 34 * Allocate space for a new array object. This is the lowest-level array 35 * allocation function. 36 * 37 * Pass in the array class and the width of each element. 38 * 39 * On failure, returns NULL with an exception raised. 40 */ dvmAllocArray(ClassObject * arrayClass,size_t length,size_t elemWidth,int allocFlags)41 ArrayObject* dvmAllocArray(ClassObject* arrayClass, size_t length, 42 size_t elemWidth, int allocFlags) 43 { 44 ArrayObject* newArray; 45 size_t size; 46 47 assert(arrayClass->descriptor[0] == '['); 48 49 if (length > 0x0fffffff) { 50 /* too large and (length * elemWidth) will overflow 32 bits */ 51 LOGE("Rejecting allocation of %u-element array\n", length); 52 dvmThrowBadAllocException("array size too large"); 53 return NULL; 54 } 55 56 size = offsetof(ArrayObject, contents); 57 size += length * elemWidth; 58 59 /* Note that we assume that the Array class does not 60 * override finalize(). 61 */ 62 newArray = dvmMalloc(size, allocFlags); 63 if (newArray != NULL) { 64 DVM_OBJECT_INIT(&newArray->obj, arrayClass); 65 newArray->length = length; 66 LOGVV("AllocArray: %s [%d] (%d)\n", 67 arrayClass->descriptor, (int) length, (int) size); 68 #if WITH_HPROF && WITH_HPROF_STACK 69 hprofFillInStackTrace(&newArray->obj); 70 #endif 71 dvmTrackAllocation(arrayClass, size); 72 } 73 /* the caller must call dvmReleaseTrackedAlloc */ 74 return newArray; 75 } 76 77 /* 78 * Create a new array, given an array class. The class may represent an 79 * array of references or primitives. 80 */ dvmAllocArrayByClass(ClassObject * arrayClass,size_t length,int allocFlags)81 ArrayObject* dvmAllocArrayByClass(ClassObject* arrayClass, 82 size_t length, int allocFlags) 83 { 84 const char* descriptor = arrayClass->descriptor; 85 86 assert(descriptor[0] == '['); /* must be array class */ 87 if (descriptor[1] != '[' && descriptor[1] != 'L') { 88 /* primitive array */ 89 assert(descriptor[2] == '\0'); 90 return dvmAllocPrimitiveArray(descriptor[1], length, allocFlags); 91 } else { 92 return dvmAllocArray(arrayClass, length, kObjectArrayRefWidth, 93 allocFlags); 94 } 95 } 96 97 /* 98 * Find the array class for "elemClassObj", which could itself be an 99 * array class. 100 */ dvmFindArrayClassForElement(ClassObject * elemClassObj)101 ClassObject* dvmFindArrayClassForElement(ClassObject* elemClassObj) 102 { 103 ClassObject* arrayClass; 104 105 assert(elemClassObj != NULL); 106 107 /* Simply prepend "[" to the descriptor. */ 108 int nameLen = strlen(elemClassObj->descriptor); 109 char className[nameLen + 2]; 110 111 className[0] = '['; 112 memcpy(className+1, elemClassObj->descriptor, nameLen+1); 113 arrayClass = dvmFindArrayClass(className, elemClassObj->classLoader); 114 115 return arrayClass; 116 } 117 118 /* 119 * Create a new array that holds references to members of the specified class. 120 * 121 * "elemClassObj" is the element type, and may itself be an array class. It 122 * may not be a primitive class. 123 * 124 * "allocFlags" determines whether the new object will be added to the 125 * "tracked alloc" table. 126 * 127 * This is less efficient than dvmAllocArray(), but occasionally convenient. 128 */ dvmAllocObjectArray(ClassObject * elemClassObj,size_t length,int allocFlags)129 ArrayObject* dvmAllocObjectArray(ClassObject* elemClassObj, size_t length, 130 int allocFlags) 131 { 132 ClassObject* arrayClass; 133 ArrayObject* newArray = NULL; 134 135 LOGVV("dvmAllocObjectArray: '%s' len=%d\n", 136 elemClassObj->descriptor, (int)length); 137 138 arrayClass = dvmFindArrayClassForElement(elemClassObj); 139 if (arrayClass != NULL) { 140 newArray = dvmAllocArray(arrayClass, length, kObjectArrayRefWidth, 141 allocFlags); 142 } 143 144 /* the caller must call dvmReleaseTrackedAlloc */ 145 return newArray; 146 } 147 148 /* 149 * Create a new array that holds primitive types. 150 * 151 * "type" is the primitive type letter, e.g. 'I' for int or 'J' for long. 152 * If the array class doesn't exist, it will be created. 153 */ dvmAllocPrimitiveArray(char type,size_t length,int allocFlags)154 ArrayObject* dvmAllocPrimitiveArray(char type, size_t length, int allocFlags) 155 { 156 ArrayObject* newArray; 157 ClassObject** pTypeClass; 158 int width; 159 160 switch (type) { 161 case 'I': 162 pTypeClass = &gDvm.classArrayInt; 163 width = 4; 164 break; 165 case 'C': 166 pTypeClass = &gDvm.classArrayChar; 167 width = 2; 168 break; 169 case 'B': 170 pTypeClass = &gDvm.classArrayByte; 171 width = 1; 172 break; 173 case 'Z': 174 pTypeClass = &gDvm.classArrayBoolean; 175 width = 1; /* special-case this? */ 176 break; 177 case 'F': 178 pTypeClass = &gDvm.classArrayFloat; 179 width = 4; 180 break; 181 case 'D': 182 pTypeClass = &gDvm.classArrayDouble; 183 width = 8; 184 break; 185 case 'S': 186 pTypeClass = &gDvm.classArrayShort; 187 width = 2; 188 break; 189 case 'J': 190 pTypeClass = &gDvm.classArrayLong; 191 width = 8; 192 break; 193 default: 194 LOGE("Unknown type '%c'\n", type); 195 assert(false); 196 return NULL; 197 } 198 199 if (*pTypeClass == NULL) { 200 char typeClassName[3] = "[x"; 201 202 typeClassName[1] = type; 203 204 *pTypeClass = dvmFindArrayClass(typeClassName, NULL); 205 if (*pTypeClass == NULL) { 206 LOGE("ERROR: failed to generate array class for '%s'\n", 207 typeClassName); 208 return NULL; 209 } 210 } 211 212 newArray = dvmAllocArray(*pTypeClass, length, width, allocFlags); 213 214 /* the caller must dvmReleaseTrackedAlloc if allocFlags==ALLOC_DEFAULT */ 215 return newArray; 216 } 217 218 /* 219 * Recursively create an array with multiple dimensions. Elements may be 220 * Objects or primitive types. 221 * 222 * The dimension we're creating is in dimensions[0], so when we recurse 223 * we advance the pointer. 224 */ dvmAllocMultiArray(ClassObject * arrayClass,int curDim,const int * dimensions)225 ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim, 226 const int* dimensions) 227 { 228 ArrayObject* newArray; 229 const char* elemName = arrayClass->descriptor + 1; // Advance past one '['. 230 231 LOGVV("dvmAllocMultiArray: class='%s' curDim=%d *dimensions=%d\n", 232 arrayClass->descriptor, curDim, *dimensions); 233 234 if (curDim == 0) { 235 if (*elemName == 'L' || *elemName == '[') { 236 LOGVV(" end: array class (obj) is '%s'\n", 237 arrayClass->descriptor); 238 newArray = dvmAllocArray(arrayClass, *dimensions, 239 kObjectArrayRefWidth, ALLOC_DEFAULT); 240 } else { 241 LOGVV(" end: array class (prim) is '%s'\n", 242 arrayClass->descriptor); 243 newArray = dvmAllocPrimitiveArray( 244 gPrimLetter[arrayClass->elementClass->primitiveType], 245 *dimensions, ALLOC_DEFAULT); 246 } 247 } else { 248 ClassObject* subArrayClass; 249 int i; 250 251 /* if we have X[][], find X[] */ 252 subArrayClass = dvmFindArrayClass(elemName, arrayClass->classLoader); 253 if (subArrayClass == NULL) { 254 /* not enough '['s on the initial class? */ 255 assert(dvmCheckException(dvmThreadSelf())); 256 return NULL; 257 } 258 assert(dvmIsArrayClass(subArrayClass)); 259 260 /* allocate the array that holds the sub-arrays */ 261 newArray = dvmAllocArray(arrayClass, *dimensions, kObjectArrayRefWidth, 262 ALLOC_DEFAULT); 263 if (newArray == NULL) { 264 assert(dvmCheckException(dvmThreadSelf())); 265 return NULL; 266 } 267 268 /* 269 * Create a new sub-array in every element of the array. 270 */ 271 for (i = 0; i < *dimensions; i++) { 272 ArrayObject* newSubArray; 273 newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1, 274 dimensions+1); 275 if (newSubArray == NULL) { 276 dvmReleaseTrackedAlloc((Object*) newArray, NULL); 277 assert(dvmCheckException(dvmThreadSelf())); 278 return NULL; 279 } 280 dvmSetObjectArrayElement(newArray, i, (Object *)newSubArray); 281 dvmReleaseTrackedAlloc((Object*) newSubArray, NULL); 282 } 283 } 284 285 /* caller must call dvmReleaseTrackedAlloc */ 286 return newArray; 287 } 288 289 290 /* 291 * Find an array class, by name (e.g. "[I"). 292 * 293 * If the array class doesn't exist, we generate it. 294 * 295 * If the element class doesn't exist, we return NULL (no exception raised). 296 */ dvmFindArrayClass(const char * descriptor,Object * loader)297 ClassObject* dvmFindArrayClass(const char* descriptor, Object* loader) 298 { 299 ClassObject* clazz; 300 301 assert(descriptor[0] == '['); 302 //LOGV("dvmFindArrayClass: '%s' %p\n", descriptor, loader); 303 304 clazz = dvmLookupClass(descriptor, loader, false); 305 if (clazz == NULL) { 306 LOGV("Array class '%s' %p not found; creating\n", descriptor, loader); 307 clazz = createArrayClass(descriptor, loader); 308 if (clazz != NULL) 309 dvmAddInitiatingLoader(clazz, loader); 310 } 311 312 return clazz; 313 } 314 315 /* 316 * Create an array class (i.e. the class object for the array, not the 317 * array itself). "descriptor" looks like "[C" or "[Ljava/lang/String;". 318 * 319 * If "descriptor" refers to an array of primitives, look up the 320 * primitive type's internally-generated class object. 321 * 322 * "loader" is the class loader of the class that's referring to us. It's 323 * used to ensure that we're looking for the element type in the right 324 * context. It does NOT become the class loader for the array class; that 325 * always comes from the base element class. 326 * 327 * Returns NULL with an exception raised on failure. 328 */ createArrayClass(const char * descriptor,Object * loader)329 static ClassObject* createArrayClass(const char* descriptor, Object* loader) 330 { 331 ClassObject* newClass = NULL; 332 ClassObject* elementClass = NULL; 333 int arrayDim; 334 u4 extraFlags; 335 336 assert(descriptor[0] == '['); 337 assert(gDvm.classJavaLangClass != NULL); 338 assert(gDvm.classJavaLangObject != NULL); 339 340 /* 341 * Identify the underlying element class and the array dimension depth. 342 */ 343 extraFlags = CLASS_ISARRAY; 344 if (descriptor[1] == '[') { 345 /* array of arrays; keep descriptor and grab stuff from parent */ 346 ClassObject* outer; 347 348 outer = dvmFindClassNoInit(&descriptor[1], loader); 349 if (outer != NULL) { 350 /* want the base class, not "outer", in our elementClass */ 351 elementClass = outer->elementClass; 352 arrayDim = outer->arrayDim + 1; 353 extraFlags |= CLASS_ISOBJECTARRAY; 354 } else { 355 assert(elementClass == NULL); /* make sure we fail */ 356 } 357 } else { 358 arrayDim = 1; 359 if (descriptor[1] == 'L') { 360 /* array of objects; strip off "[" and look up descriptor. */ 361 const char* subDescriptor = &descriptor[1]; 362 LOGVV("searching for element class '%s'\n", subDescriptor); 363 elementClass = dvmFindClassNoInit(subDescriptor, loader); 364 extraFlags |= CLASS_ISOBJECTARRAY; 365 } else { 366 /* array of a primitive type */ 367 elementClass = dvmFindPrimitiveClass(descriptor[1]); 368 } 369 } 370 371 if (elementClass == NULL) { 372 /* failed */ 373 assert(dvmCheckException(dvmThreadSelf())); 374 dvmFreeClassInnards(newClass); 375 dvmReleaseTrackedAlloc((Object*) newClass, NULL); 376 return NULL; 377 } 378 379 /* 380 * See if it's already loaded. Array classes are always associated 381 * with the class loader of their underlying element type -- an array 382 * of Strings goes with the loader for java/lang/String -- so we need 383 * to look for it there. (The caller should have checked for the 384 * existence of the class before calling here, but they did so with 385 * *their* class loader, not the element class' loader.) 386 * 387 * If we find it, the caller adds "loader" to the class' initiating 388 * loader list, which should prevent us from going through this again. 389 * 390 * This call is unnecessary if "loader" and "elementClass->classLoader" 391 * are the same, because our caller (dvmFindArrayClass) just did the 392 * lookup. (Even if we get this wrong we still have correct behavior, 393 * because we effectively do this lookup again when we add the new 394 * class to the hash table -- necessary because of possible races with 395 * other threads.) 396 */ 397 if (loader != elementClass->classLoader) { 398 LOGVV("--- checking for '%s' in %p vs. elem %p\n", 399 descriptor, loader, elementClass->classLoader); 400 newClass = dvmLookupClass(descriptor, elementClass->classLoader, false); 401 if (newClass != NULL) { 402 LOGV("--- we already have %s in %p, don't need in %p\n", 403 descriptor, elementClass->classLoader, loader); 404 return newClass; 405 } 406 } 407 408 409 /* 410 * Fill out the fields in the ClassObject. 411 * 412 * It is possible to execute some methods against arrays, because all 413 * arrays are instances of Object, so we need to set up a vtable. We 414 * can just point at the one in Object. 415 * 416 * Array classes are simple enough that we don't need to do a full 417 * link step. 418 */ 419 newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT); 420 if (newClass == NULL) 421 return NULL; 422 DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass); 423 dvmSetClassSerialNumber(newClass); 424 newClass->descriptorAlloc = strdup(descriptor); 425 newClass->descriptor = newClass->descriptorAlloc; 426 dvmSetFieldObject((Object *)newClass, 427 offsetof(ClassObject, super), 428 (Object *)gDvm.classJavaLangObject); 429 newClass->vtableCount = gDvm.classJavaLangObject->vtableCount; 430 newClass->vtable = gDvm.classJavaLangObject->vtable; 431 newClass->primitiveType = PRIM_NOT; 432 dvmSetFieldObject((Object *)newClass, 433 offsetof(ClassObject, elementClass), 434 (Object *)elementClass); 435 dvmSetFieldObject((Object *)newClass, 436 offsetof(ClassObject, classLoader), 437 (Object *)elementClass->classLoader); 438 newClass->arrayDim = arrayDim; 439 newClass->status = CLASS_INITIALIZED; 440 #if WITH_HPROF && WITH_HPROF_STACK 441 hprofFillInStackTrace(newClass); 442 #endif 443 444 /* don't need to set newClass->objectSize */ 445 446 /* 447 * All arrays have java/lang/Cloneable and java/io/Serializable as 448 * interfaces. We need to set that up here, so that stuff like 449 * "instanceof" works right. 450 * 451 * Note: The GC could run during the call to dvmFindSystemClassNoInit(), 452 * so we need to make sure the class object is GC-valid while we're in 453 * there. Do this by clearing the interface list so the GC will just 454 * think that the entries are null. 455 * 456 * TODO? 457 * We may want to cache these two classes to avoid the lookup, though 458 * it's not vital -- we only do it when creating an array class, not 459 * every time we create an array. Better yet, create a single, global 460 * copy of "interfaces" and "iftable" somewhere near the start and 461 * just point to those (and remember not to free them for arrays). 462 */ 463 newClass->interfaceCount = 2; 464 newClass->interfaces = (ClassObject**)dvmLinearAlloc(newClass->classLoader, 465 sizeof(ClassObject*) * 2); 466 memset(newClass->interfaces, 0, sizeof(ClassObject*) * 2); 467 newClass->interfaces[0] = 468 dvmFindSystemClassNoInit("Ljava/lang/Cloneable;"); 469 newClass->interfaces[1] = 470 dvmFindSystemClassNoInit("Ljava/io/Serializable;"); 471 dvmLinearReadOnly(newClass->classLoader, newClass->interfaces); 472 if (newClass->interfaces[0] == NULL || newClass->interfaces[1] == NULL) { 473 LOGE("Unable to create array class '%s': missing interfaces\n", 474 descriptor); 475 dvmFreeClassInnards(newClass); 476 dvmThrowException("Ljava/lang/InternalError;", "missing array ifaces"); 477 dvmReleaseTrackedAlloc((Object*) newClass, NULL); 478 return NULL; 479 } 480 /* 481 * We assume that Cloneable/Serializable don't have superinterfaces -- 482 * normally we'd have to crawl up and explicitly list all of the 483 * supers as well. These interfaces don't have any methods, so we 484 * don't have to worry about the ifviPool either. 485 */ 486 newClass->iftableCount = 2; 487 newClass->iftable = (InterfaceEntry*) dvmLinearAlloc(newClass->classLoader, 488 sizeof(InterfaceEntry) * 2); 489 memset(newClass->iftable, 0, sizeof(InterfaceEntry) * 2); 490 newClass->iftable[0].clazz = newClass->interfaces[0]; 491 newClass->iftable[1].clazz = newClass->interfaces[1]; 492 dvmLinearReadOnly(newClass->classLoader, newClass->iftable); 493 494 /* 495 * Inherit access flags from the element. Arrays can't be used as a 496 * superclass or interface, so we want to add "final" and remove 497 * "interface". 498 * 499 * Don't inherit any non-standard flags (e.g., CLASS_FINALIZABLE) 500 * from elementClass. We assume that the array class does not 501 * override finalize(). 502 */ 503 newClass->accessFlags = ((newClass->elementClass->accessFlags & 504 ~ACC_INTERFACE) | ACC_FINAL) & JAVA_FLAGS_MASK; 505 506 /* Set the flags we determined above. 507 * This must happen after accessFlags is set. 508 */ 509 SET_CLASS_FLAG(newClass, extraFlags); 510 511 if (!dvmAddClassToHash(newClass)) { 512 /* 513 * Another thread must have loaded the class after we 514 * started but before we finished. Discard what we've 515 * done and leave some hints for the GC. 516 */ 517 LOGI("WOW: somebody generated %s simultaneously\n", 518 newClass->descriptor); 519 520 /* Clean up the class before letting the 521 * GC get its hands on it. 522 */ 523 dvmFreeClassInnards(newClass); 524 525 /* Let the GC free the class. 526 */ 527 dvmReleaseTrackedAlloc((Object*) newClass, NULL); 528 529 /* Grab the winning class. 530 */ 531 newClass = dvmLookupClass(descriptor, elementClass->classLoader, false); 532 assert(newClass != NULL); 533 return newClass; 534 } 535 dvmReleaseTrackedAlloc((Object*) newClass, NULL); 536 537 LOGV("Created array class '%s' %p (access=0x%04x.%04x)\n", 538 descriptor, newClass->classLoader, 539 newClass->accessFlags >> 16, 540 newClass->accessFlags & JAVA_FLAGS_MASK); 541 542 return newClass; 543 } 544 545 /* 546 * Get a class we generated for the primitive types. 547 * 548 * These correspond to e.g. Integer.TYPE, and are used as the element 549 * class in arrays of primitives. 550 * 551 * "type" should be 'I', 'J', 'Z', etc. 552 * 553 * Returns NULL if the type doesn't correspond to a known primitive type. 554 */ dvmFindPrimitiveClass(char type)555 ClassObject* dvmFindPrimitiveClass(char type) 556 { 557 int idx; 558 559 switch (type) { 560 case 'Z': 561 idx = PRIM_BOOLEAN; 562 break; 563 case 'C': 564 idx = PRIM_CHAR; 565 break; 566 case 'F': 567 idx = PRIM_FLOAT; 568 break; 569 case 'D': 570 idx = PRIM_DOUBLE; 571 break; 572 case 'B': 573 idx = PRIM_BYTE; 574 break; 575 case 'S': 576 idx = PRIM_SHORT; 577 break; 578 case 'I': 579 idx = PRIM_INT; 580 break; 581 case 'J': 582 idx = PRIM_LONG; 583 break; 584 case 'V': 585 idx = PRIM_VOID; 586 break; 587 default: 588 LOGW("Unknown primitive type '%c'\n", type); 589 return NULL; 590 } 591 592 /* 593 * Create the primitive class if it hasn't already been, and add it 594 * to the table. 595 */ 596 if (gDvm.primitiveClass[idx] == NULL) { 597 ClassObject* primClass = createPrimitiveClass(idx); 598 dvmReleaseTrackedAlloc((Object*) primClass, NULL); 599 600 if (android_atomic_release_cas(0, (int) primClass, 601 (int*) &gDvm.primitiveClass[idx]) != 0) 602 { 603 /* 604 * Looks like somebody beat us to it. Free up the one we 605 * just created and use the other one. 606 */ 607 dvmFreeClassInnards(primClass); 608 } 609 } 610 611 return gDvm.primitiveClass[idx]; 612 } 613 614 /* 615 * Synthesize a primitive class. 616 * 617 * Just creates the class and returns it (does not add it to the class list). 618 */ createPrimitiveClass(int idx)619 static ClassObject* createPrimitiveClass(int idx) 620 { 621 ClassObject* newClass; 622 static const char* kClassDescriptors[PRIM_MAX] = { 623 "Z", "C", "F", "D", "B", "S", "I", "J", "V" 624 }; 625 626 assert(gDvm.classJavaLangClass != NULL); 627 assert(idx >= 0 && idx < PRIM_MAX); 628 629 /* 630 * Fill out a few fields in the ClassObject. 631 * 632 * Note that primitive classes do not sub-class java/lang/Object. This 633 * matters for "instanceof" checks. Also, we assume that the primitive 634 * class does not override finalize(). 635 */ 636 newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT); 637 if (newClass == NULL) 638 return NULL; 639 DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass); 640 dvmSetClassSerialNumber(newClass); 641 newClass->accessFlags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; 642 newClass->primitiveType = idx; 643 newClass->descriptorAlloc = NULL; 644 newClass->descriptor = kClassDescriptors[idx]; 645 //newClass->super = gDvm.classJavaLangObject; 646 newClass->status = CLASS_INITIALIZED; 647 #if WITH_HPROF && WITH_HPROF_STACK 648 hprofFillInStackTrace(newClass); 649 #endif 650 651 /* don't need to set newClass->objectSize */ 652 653 LOGVV("Created primitive class '%s'\n", kClassDescriptors[idx]); 654 655 return newClass; 656 } 657 658 /* 659 * Copy the entire contents of one array of objects to another. If the copy 660 * is impossible because of a type clash, we fail and return "false". 661 */ dvmCopyObjectArray(ArrayObject * dstArray,const ArrayObject * srcArray,ClassObject * dstElemClass)662 bool dvmCopyObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray, 663 ClassObject* dstElemClass) 664 { 665 Object** src = (Object**)srcArray->contents; 666 u4 length, count; 667 668 assert(srcArray->length == dstArray->length); 669 assert(dstArray->obj.clazz->elementClass == dstElemClass || 670 (dstArray->obj.clazz->elementClass == dstElemClass->elementClass && 671 dstArray->obj.clazz->arrayDim == dstElemClass->arrayDim+1)); 672 673 length = dstArray->length; 674 for (count = 0; count < length; count++) { 675 if (!dvmInstanceof(src[count]->clazz, dstElemClass)) { 676 LOGW("dvmCopyObjectArray: can't store %s in %s\n", 677 src[count]->clazz->descriptor, dstElemClass->descriptor); 678 return false; 679 } 680 dvmSetObjectArrayElement(dstArray, count, src[count]); 681 } 682 683 return true; 684 } 685 686 /* 687 * Copy the entire contents of an array of boxed primitives into an 688 * array of primitives. The boxed value must fit in the primitive (i.e. 689 * narrowing conversions are not allowed). 690 */ dvmUnboxObjectArray(ArrayObject * dstArray,const ArrayObject * srcArray,ClassObject * dstElemClass)691 bool dvmUnboxObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray, 692 ClassObject* dstElemClass) 693 { 694 Object** src = (Object**)srcArray->contents; 695 void* dst = (void*)dstArray->contents; 696 u4 count = dstArray->length; 697 PrimitiveType typeIndex = dstElemClass->primitiveType; 698 699 assert(typeIndex != PRIM_NOT); 700 assert(srcArray->length == dstArray->length); 701 702 while (count--) { 703 JValue result; 704 705 /* 706 * This will perform widening conversions as appropriate. It 707 * might make sense to be more restrictive and require that the 708 * primitive type exactly matches the box class, but it's not 709 * necessary for correctness. 710 */ 711 if (!dvmUnwrapPrimitive(*src, dstElemClass, &result)) { 712 LOGW("dvmCopyObjectArray: can't store %s in %s\n", 713 (*src)->clazz->descriptor, dstElemClass->descriptor); 714 return false; 715 } 716 717 /* would be faster with 4 loops, but speed not crucial here */ 718 switch (typeIndex) { 719 case PRIM_BOOLEAN: 720 case PRIM_BYTE: 721 { 722 u1* tmp = dst; 723 *tmp++ = result.b; 724 dst = tmp; 725 } 726 break; 727 case PRIM_CHAR: 728 case PRIM_SHORT: 729 { 730 u2* tmp = dst; 731 *tmp++ = result.s; 732 dst = tmp; 733 } 734 break; 735 case PRIM_FLOAT: 736 case PRIM_INT: 737 { 738 u4* tmp = dst; 739 *tmp++ = result.i; 740 dst = tmp; 741 } 742 break; 743 case PRIM_DOUBLE: 744 case PRIM_LONG: 745 { 746 u8* tmp = dst; 747 *tmp++ = result.j; 748 dst = tmp; 749 } 750 break; 751 default: 752 /* should not be possible to get here */ 753 dvmAbort(); 754 } 755 756 src++; 757 } 758 759 return true; 760 } 761 762 /* 763 * Returns the width, in bytes, required by elements in instances of 764 * the array class. 765 */ dvmArrayClassElementWidth(const ClassObject * arrayClass)766 size_t dvmArrayClassElementWidth(const ClassObject* arrayClass) 767 { 768 const char *descriptor; 769 770 assert(dvmIsArrayClass(arrayClass)); 771 772 if (dvmIsObjectArrayClass(arrayClass)) { 773 return sizeof(Object *); 774 } else { 775 descriptor = arrayClass->descriptor; 776 switch (descriptor[1]) { 777 case 'B': return 1; /* byte */ 778 case 'C': return 2; /* char */ 779 case 'D': return 8; /* double */ 780 case 'F': return 4; /* float */ 781 case 'I': return 4; /* int */ 782 case 'J': return 8; /* long */ 783 case 'S': return 2; /* short */ 784 case 'Z': return 1; /* boolean */ 785 } 786 } 787 LOGE("class %p has an unhandled descriptor '%s'", arrayClass, descriptor); 788 dvmDumpThread(dvmThreadSelf(), false); 789 dvmAbort(); 790 return 0; /* Quiet the compiler. */ 791 } 792 dvmArrayObjectSize(const ArrayObject * array)793 size_t dvmArrayObjectSize(const ArrayObject *array) 794 { 795 size_t size; 796 797 assert(array != NULL); 798 size = offsetof(ArrayObject, contents); 799 size += array->length * dvmArrayClassElementWidth(array->obj.clazz); 800 return size; 801 } 802 803 /* 804 * Add all primitive classes to the root set of objects. 805 TODO: do these belong to the root class loader? 806 */ dvmGcScanPrimitiveClasses()807 void dvmGcScanPrimitiveClasses() 808 { 809 int i; 810 811 for (i = 0; i < PRIM_MAX; i++) { 812 dvmMarkObject((Object *)gDvm.primitiveClass[i]); // may be NULL 813 } 814 } 815