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 if (elemClassObj->arrayClass != NULL) { 108 arrayClass = elemClassObj->arrayClass; 109 LOGVV("using cached '%s' class for '%s'\n", 110 arrayClass->descriptor, elemClassObj->descriptor); 111 } else { 112 /* Simply prepend "[" to the descriptor. */ 113 int nameLen = strlen(elemClassObj->descriptor); 114 char className[nameLen + 2]; 115 116 className[0] = '['; 117 memcpy(className+1, elemClassObj->descriptor, nameLen+1); 118 arrayClass = dvmFindArrayClass(className, elemClassObj->classLoader); 119 if (arrayClass != NULL) 120 elemClassObj->arrayClass = arrayClass; 121 } 122 123 return arrayClass; 124 } 125 126 /* 127 * Create a new array that holds references to members of the specified class. 128 * 129 * "elemClassObj" is the element type, and may itself be an array class. It 130 * may not be a primitive class. 131 * 132 * "allocFlags" determines whether the new object will be added to the 133 * "tracked alloc" table. 134 * 135 * This is less efficient than dvmAllocArray(), but occasionally convenient. 136 */ dvmAllocObjectArray(ClassObject * elemClassObj,size_t length,int allocFlags)137 ArrayObject* dvmAllocObjectArray(ClassObject* elemClassObj, size_t length, 138 int allocFlags) 139 { 140 ClassObject* arrayClass; 141 ArrayObject* newArray = NULL; 142 143 LOGVV("dvmAllocObjectArray: '%s' len=%d\n", 144 elemClassObj->descriptor, (int)length); 145 146 arrayClass = dvmFindArrayClassForElement(elemClassObj); 147 if (arrayClass != NULL) { 148 newArray = dvmAllocArray(arrayClass, length, kObjectArrayRefWidth, 149 allocFlags); 150 } 151 152 /* the caller must call dvmReleaseTrackedAlloc */ 153 return newArray; 154 } 155 156 /* 157 * Create a new array that holds primitive types. 158 * 159 * "type" is the primitive type letter, e.g. 'I' for int or 'J' for long. 160 * If the array class doesn't exist, it will be created. 161 */ dvmAllocPrimitiveArray(char type,size_t length,int allocFlags)162 ArrayObject* dvmAllocPrimitiveArray(char type, size_t length, int allocFlags) 163 { 164 ArrayObject* newArray; 165 ClassObject** pTypeClass; 166 int width; 167 168 switch (type) { 169 case 'I': 170 pTypeClass = &gDvm.classArrayInt; 171 width = 4; 172 break; 173 case 'C': 174 pTypeClass = &gDvm.classArrayChar; 175 width = 2; 176 break; 177 case 'B': 178 pTypeClass = &gDvm.classArrayByte; 179 width = 1; 180 break; 181 case 'Z': 182 pTypeClass = &gDvm.classArrayBoolean; 183 width = 1; /* special-case this? */ 184 break; 185 case 'F': 186 pTypeClass = &gDvm.classArrayFloat; 187 width = 4; 188 break; 189 case 'D': 190 pTypeClass = &gDvm.classArrayDouble; 191 width = 8; 192 break; 193 case 'S': 194 pTypeClass = &gDvm.classArrayShort; 195 width = 2; 196 break; 197 case 'J': 198 pTypeClass = &gDvm.classArrayLong; 199 width = 8; 200 break; 201 default: 202 LOGE("Unknown type '%c'\n", type); 203 assert(false); 204 return NULL; 205 } 206 207 if (*pTypeClass == NULL) { 208 char typeClassName[3] = "[x"; 209 210 typeClassName[1] = type; 211 212 *pTypeClass = dvmFindArrayClass(typeClassName, NULL); 213 if (*pTypeClass == NULL) { 214 LOGE("ERROR: failed to generate array class for '%s'\n", 215 typeClassName); 216 return NULL; 217 } 218 } 219 220 newArray = dvmAllocArray(*pTypeClass, length, width, allocFlags); 221 222 /* the caller must dvmReleaseTrackedAlloc if allocFlags==ALLOC_DEFAULT */ 223 return newArray; 224 } 225 226 /* 227 * Recursively create an array with multiple dimensions. Elements may be 228 * Objects or primitive types. 229 * 230 * The dimension we're creating is in dimensions[0], so when we recurse 231 * we advance the pointer. 232 */ dvmAllocMultiArray(ClassObject * arrayClass,int curDim,const int * dimensions)233 ArrayObject* dvmAllocMultiArray(ClassObject* arrayClass, int curDim, 234 const int* dimensions) 235 { 236 ArrayObject* newArray; 237 const char* elemName = arrayClass->descriptor + 1; // Advance past one '['. 238 239 LOGVV("dvmAllocMultiArray: class='%s' curDim=%d *dimensions=%d\n", 240 arrayClass->descriptor, curDim, *dimensions); 241 242 if (curDim == 0) { 243 if (*elemName == 'L' || *elemName == '[') { 244 LOGVV(" end: array class (obj) is '%s'\n", 245 arrayClass->descriptor); 246 newArray = dvmAllocArray(arrayClass, *dimensions, 247 kObjectArrayRefWidth, ALLOC_DEFAULT); 248 } else { 249 LOGVV(" end: array class (prim) is '%s'\n", 250 arrayClass->descriptor); 251 newArray = dvmAllocPrimitiveArray( 252 gPrimLetter[arrayClass->elementClass->primitiveType], 253 *dimensions, ALLOC_DEFAULT); 254 } 255 } else { 256 ClassObject* subArrayClass; 257 Object** contents; 258 int i; 259 260 /* if we have X[][], find X[] */ 261 subArrayClass = dvmFindArrayClass(elemName, arrayClass->classLoader); 262 if (subArrayClass == NULL) { 263 /* not enough '['s on the initial class? */ 264 assert(dvmCheckException(dvmThreadSelf())); 265 return NULL; 266 } 267 assert(dvmIsArrayClass(subArrayClass)); 268 269 /* allocate the array that holds the sub-arrays */ 270 newArray = dvmAllocArray(arrayClass, *dimensions, kObjectArrayRefWidth, 271 ALLOC_DEFAULT); 272 if (newArray == NULL) { 273 assert(dvmCheckException(dvmThreadSelf())); 274 return NULL; 275 } 276 277 /* 278 * Create a new sub-array in every element of the array. 279 */ 280 contents = (Object**) newArray->contents; 281 for (i = 0; i < *dimensions; i++) { 282 ArrayObject* newSubArray; 283 284 newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1, 285 dimensions+1); 286 if (newSubArray == NULL) { 287 dvmReleaseTrackedAlloc((Object*) newArray, NULL); 288 assert(dvmCheckException(dvmThreadSelf())); 289 return NULL; 290 } 291 292 *contents++ = (Object*) newSubArray; 293 dvmReleaseTrackedAlloc((Object*) newSubArray, NULL); 294 } 295 } 296 297 /* caller must call dvmReleaseTrackedAlloc */ 298 return newArray; 299 } 300 301 302 /* 303 * Find an array class, by name (e.g. "[I"). 304 * 305 * If the array class doesn't exist, we generate it. 306 * 307 * If the element class doesn't exist, we return NULL (no exception raised). 308 */ dvmFindArrayClass(const char * descriptor,Object * loader)309 ClassObject* dvmFindArrayClass(const char* descriptor, Object* loader) 310 { 311 ClassObject* clazz; 312 313 assert(descriptor[0] == '['); 314 //LOGV("dvmFindArrayClass: '%s' %p\n", descriptor, loader); 315 316 clazz = dvmLookupClass(descriptor, loader, false); 317 if (clazz == NULL) { 318 LOGV("Array class '%s' %p not found; creating\n", descriptor, loader); 319 clazz = createArrayClass(descriptor, loader); 320 if (clazz != NULL) 321 dvmAddInitiatingLoader(clazz, loader); 322 } 323 324 return clazz; 325 } 326 327 /* 328 * Create an array class (i.e. the class object for the array, not the 329 * array itself). "descriptor" looks like "[C" or "[Ljava/lang/String;". 330 * 331 * If "descriptor" refers to an array of primitives, look up the 332 * primitive type's internally-generated class object. 333 * 334 * "loader" is the class loader of the class that's referring to us. It's 335 * used to ensure that we're looking for the element type in the right 336 * context. It does NOT become the class loader for the array class; that 337 * always comes from the base element class. 338 * 339 * Returns NULL with an exception raised on failure. 340 */ createArrayClass(const char * descriptor,Object * loader)341 static ClassObject* createArrayClass(const char* descriptor, Object* loader) 342 { 343 ClassObject* newClass = NULL; 344 ClassObject* elementClass = NULL; 345 int arrayDim; 346 u4 extraFlags; 347 348 assert(descriptor[0] == '['); 349 assert(gDvm.classJavaLangClass != NULL); 350 assert(gDvm.classJavaLangObject != NULL); 351 352 /* 353 * Identify the underlying element class and the array dimension depth. 354 */ 355 extraFlags = CLASS_ISARRAY; 356 if (descriptor[1] == '[') { 357 /* array of arrays; keep descriptor and grab stuff from parent */ 358 ClassObject* outer; 359 360 outer = dvmFindClassNoInit(&descriptor[1], loader); 361 if (outer != NULL) { 362 /* want the base class, not "outer", in our elementClass */ 363 elementClass = outer->elementClass; 364 arrayDim = outer->arrayDim + 1; 365 extraFlags |= CLASS_ISOBJECTARRAY; 366 } else { 367 assert(elementClass == NULL); /* make sure we fail */ 368 } 369 } else { 370 arrayDim = 1; 371 if (descriptor[1] == 'L') { 372 /* array of objects; strip off "[" and look up descriptor. */ 373 const char* subDescriptor = &descriptor[1]; 374 LOGVV("searching for element class '%s'\n", subDescriptor); 375 elementClass = dvmFindClassNoInit(subDescriptor, loader); 376 extraFlags |= CLASS_ISOBJECTARRAY; 377 } else { 378 /* array of a primitive type */ 379 elementClass = dvmFindPrimitiveClass(descriptor[1]); 380 } 381 } 382 383 if (elementClass == NULL) { 384 /* failed */ 385 assert(dvmCheckException(dvmThreadSelf())); 386 dvmFreeClassInnards(newClass); 387 dvmReleaseTrackedAlloc((Object*) newClass, NULL); 388 return NULL; 389 } 390 391 /* 392 * See if it's already loaded. Array classes are always associated 393 * with the class loader of their underlying element type -- an array 394 * of Strings goes with the loader for java/lang/String -- so we need 395 * to look for it there. (The caller should have checked for the 396 * existence of the class before calling here, but they did so with 397 * *their* class loader, not the element class' loader.) 398 * 399 * If we find it, the caller adds "loader" to the class' initiating 400 * loader list, which should prevent us from going through this again. 401 * 402 * This call is unnecessary if "loader" and "elementClass->classLoader" 403 * are the same, because our caller (dvmFindArrayClass) just did the 404 * lookup. (Even if we get this wrong we still have correct behavior, 405 * because we effectively do this lookup again when we add the new 406 * class to the hash table -- necessary because of possible races with 407 * other threads.) 408 */ 409 if (loader != elementClass->classLoader) { 410 LOGVV("--- checking for '%s' in %p vs. elem %p\n", 411 descriptor, loader, elementClass->classLoader); 412 newClass = dvmLookupClass(descriptor, elementClass->classLoader, false); 413 if (newClass != NULL) { 414 LOGV("--- we already have %s in %p, don't need in %p\n", 415 descriptor, elementClass->classLoader, loader); 416 return newClass; 417 } 418 } 419 420 421 /* 422 * Fill out the fields in the ClassObject. 423 * 424 * It is possible to execute some methods against arrays, because all 425 * arrays are instances of Object, so we need to set up a vtable. We 426 * can just point at the one in Object. 427 * 428 * Array classes are simple enough that we don't need to do a full 429 * link step. 430 */ 431 newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT); 432 if (newClass == NULL) 433 return NULL; 434 DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass); 435 dvmSetClassSerialNumber(newClass); 436 newClass->descriptorAlloc = strdup(descriptor); 437 newClass->descriptor = newClass->descriptorAlloc; 438 newClass->super = gDvm.classJavaLangObject; 439 newClass->vtableCount = gDvm.classJavaLangObject->vtableCount; 440 newClass->vtable = gDvm.classJavaLangObject->vtable; 441 newClass->primitiveType = PRIM_NOT; 442 newClass->elementClass = elementClass; 443 newClass->classLoader = elementClass->classLoader; 444 newClass->arrayDim = arrayDim; 445 newClass->status = CLASS_INITIALIZED; 446 #if WITH_HPROF && WITH_HPROF_STACK 447 hprofFillInStackTrace(newClass); 448 #endif 449 450 /* don't need to set newClass->objectSize */ 451 452 /* 453 * All arrays have java/lang/Cloneable and java/io/Serializable as 454 * interfaces. We need to set that up here, so that stuff like 455 * "instanceof" works right. 456 * 457 * Note: The GC could run during the call to dvmFindSystemClassNoInit(), 458 * so we need to make sure the class object is GC-valid while we're in 459 * there. Do this by clearing the interface list so the GC will just 460 * think that the entries are null. 461 * 462 * TODO? 463 * We may want to cache these two classes to avoid the lookup, though 464 * it's not vital -- we only do it when creating an array class, not 465 * every time we create an array. Better yet, create a single, global 466 * copy of "interfaces" and "iftable" somewhere near the start and 467 * just point to those (and remember not to free them for arrays). 468 */ 469 newClass->interfaceCount = 2; 470 newClass->interfaces = (ClassObject**)dvmLinearAlloc(newClass->classLoader, 471 sizeof(ClassObject*) * 2); 472 memset(newClass->interfaces, 0, sizeof(ClassObject*) * 2); 473 newClass->interfaces[0] = 474 dvmFindSystemClassNoInit("Ljava/lang/Cloneable;"); 475 newClass->interfaces[1] = 476 dvmFindSystemClassNoInit("Ljava/io/Serializable;"); 477 dvmLinearReadOnly(newClass->classLoader, newClass->interfaces); 478 if (newClass->interfaces[0] == NULL || newClass->interfaces[1] == NULL) { 479 LOGE("Unable to create array class '%s': missing interfaces\n", 480 descriptor); 481 dvmFreeClassInnards(newClass); 482 dvmThrowException("Ljava/lang/InternalError;", "missing array ifaces"); 483 dvmReleaseTrackedAlloc((Object*) newClass, NULL); 484 return NULL; 485 } 486 /* 487 * We assume that Cloneable/Serializable don't have superinterfaces -- 488 * normally we'd have to crawl up and explicitly list all of the 489 * supers as well. These interfaces don't have any methods, so we 490 * don't have to worry about the ifviPool either. 491 */ 492 newClass->iftableCount = 2; 493 newClass->iftable = (InterfaceEntry*) dvmLinearAlloc(newClass->classLoader, 494 sizeof(InterfaceEntry) * 2); 495 memset(newClass->iftable, 0, sizeof(InterfaceEntry) * 2); 496 newClass->iftable[0].clazz = newClass->interfaces[0]; 497 newClass->iftable[1].clazz = newClass->interfaces[1]; 498 dvmLinearReadOnly(newClass->classLoader, newClass->iftable); 499 500 /* 501 * Inherit access flags from the element. Arrays can't be used as a 502 * superclass or interface, so we want to add "final" and remove 503 * "interface". 504 * 505 * Don't inherit any non-standard flags (e.g., CLASS_FINALIZABLE) 506 * from elementClass. We assume that the array class does not 507 * override finalize(). 508 */ 509 newClass->accessFlags = ((newClass->elementClass->accessFlags & 510 ~ACC_INTERFACE) | ACC_FINAL) & JAVA_FLAGS_MASK; 511 512 /* Set the flags we determined above. 513 * This must happen after accessFlags is set. 514 */ 515 SET_CLASS_FLAG(newClass, extraFlags); 516 517 if (!dvmAddClassToHash(newClass)) { 518 /* 519 * Another thread must have loaded the class after we 520 * started but before we finished. Discard what we've 521 * done and leave some hints for the GC. 522 */ 523 LOGI("WOW: somebody generated %s simultaneously\n", 524 newClass->descriptor); 525 526 /* Clean up the class before letting the 527 * GC get its hands on it. 528 */ 529 assert(newClass->obj.clazz == gDvm.unlinkedJavaLangClass); 530 dvmFreeClassInnards(newClass); 531 532 /* Let the GC free the class. 533 */ 534 dvmReleaseTrackedAlloc((Object*) newClass, NULL); 535 536 /* Grab the winning class. 537 */ 538 newClass = dvmLookupClass(descriptor, elementClass->classLoader, false); 539 assert(newClass != NULL); 540 return newClass; 541 } 542 543 /* make it available to the GC */ 544 newClass->obj.clazz = gDvm.classJavaLangClass; 545 dvmReleaseTrackedAlloc((Object*) newClass, NULL); 546 547 LOGV("Created array class '%s' %p (access=0x%04x.%04x)\n", 548 descriptor, newClass->classLoader, 549 newClass->accessFlags >> 16, 550 newClass->accessFlags & JAVA_FLAGS_MASK); 551 552 return newClass; 553 } 554 555 /* 556 * Get a class we generated for the primitive types. 557 * 558 * These correspond to e.g. Integer.TYPE, and are used as the element 559 * class in arrays of primitives. 560 * 561 * "type" should be 'I', 'J', 'Z', etc. 562 * 563 * Returns NULL if the type doesn't correspond to a known primitive type. 564 */ dvmFindPrimitiveClass(char type)565 ClassObject* dvmFindPrimitiveClass(char type) 566 { 567 int idx; 568 569 switch (type) { 570 case 'Z': 571 idx = PRIM_BOOLEAN; 572 break; 573 case 'C': 574 idx = PRIM_CHAR; 575 break; 576 case 'F': 577 idx = PRIM_FLOAT; 578 break; 579 case 'D': 580 idx = PRIM_DOUBLE; 581 break; 582 case 'B': 583 idx = PRIM_BYTE; 584 break; 585 case 'S': 586 idx = PRIM_SHORT; 587 break; 588 case 'I': 589 idx = PRIM_INT; 590 break; 591 case 'J': 592 idx = PRIM_LONG; 593 break; 594 case 'V': 595 idx = PRIM_VOID; 596 break; 597 default: 598 LOGW("Unknown primitive type '%c'\n", type); 599 return NULL; 600 } 601 602 /* 603 * Create the primitive class if it hasn't already been, and add it 604 * to the table. 605 */ 606 if (gDvm.primitiveClass[idx] == NULL) { 607 ClassObject* primClass = createPrimitiveClass(idx); 608 dvmReleaseTrackedAlloc((Object*) primClass, NULL); 609 610 if (!ATOMIC_CMP_SWAP((int*) &gDvm.primitiveClass[idx], 611 0, (int) primClass)) 612 { 613 /* 614 * Looks like somebody beat us to it. Free up the one we 615 * just created and use the other one. 616 */ 617 dvmFreeClassInnards(primClass); 618 } 619 } 620 621 return gDvm.primitiveClass[idx]; 622 } 623 624 /* 625 * Synthesize a primitive class. 626 * 627 * The spec for java.lang.Class.isPrimitive describes the names to 628 * be used for these classes. 629 * 630 * Just creates the class and returns it (does not add it to the class list). 631 */ createPrimitiveClass(int idx)632 static ClassObject* createPrimitiveClass(int idx) 633 { 634 ClassObject* newClass; 635 static const char* kClassDescriptors[PRIM_MAX] = { 636 "Z", "C", "F", "D", "B", "S", "I", "J", "V" 637 }; 638 639 assert(gDvm.classJavaLangClass != NULL); 640 assert(idx >= 0 && idx < PRIM_MAX); 641 642 /* 643 * Fill out a few fields in the ClassObject. 644 * 645 * Note that primitive classes do not sub-class java/lang/Object. This 646 * matters for "instanceof" checks. Also, we assume that the primitive 647 * class does not override finalize(). 648 */ 649 newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT); 650 if (newClass == NULL) 651 return NULL; 652 DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass); 653 dvmSetClassSerialNumber(newClass); 654 newClass->accessFlags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT; 655 newClass->primitiveType = idx; 656 newClass->descriptorAlloc = NULL; 657 newClass->descriptor = kClassDescriptors[idx]; 658 //newClass->super = gDvm.classJavaLangObject; 659 newClass->status = CLASS_INITIALIZED; 660 #if WITH_HPROF && WITH_HPROF_STACK 661 hprofFillInStackTrace(newClass); 662 #endif 663 664 /* don't need to set newClass->objectSize */ 665 666 LOGVV("Created primitive class '%s'\n", kClassDescriptors[idx]); 667 668 return newClass; 669 } 670 671 /* 672 * Copy the entire contents of one array of objects to another. If the copy 673 * is impossible because of a type clash, we fail and return "false". 674 */ dvmCopyObjectArray(ArrayObject * dstArray,const ArrayObject * srcArray,ClassObject * dstElemClass)675 bool dvmCopyObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray, 676 ClassObject* dstElemClass) 677 { 678 Object** src = (Object**)srcArray->contents; 679 Object** dst = (Object**)dstArray->contents; 680 u4 count = dstArray->length; 681 682 assert(srcArray->length == dstArray->length); 683 assert(dstArray->obj.clazz->elementClass == dstElemClass || 684 (dstArray->obj.clazz->elementClass == dstElemClass->elementClass && 685 dstArray->obj.clazz->arrayDim == dstElemClass->arrayDim+1)); 686 687 while (count--) { 688 if (!dvmInstanceof((*src)->clazz, dstElemClass)) { 689 LOGW("dvmCopyObjectArray: can't store %s in %s\n", 690 (*src)->clazz->descriptor, dstElemClass->descriptor); 691 return false; 692 } 693 *dst++ = *src++; 694 } 695 696 return true; 697 } 698 699 /* 700 * Add all primitive classes to the root set of objects. 701 TODO: do these belong to the root class loader? 702 */ dvmGcScanPrimitiveClasses()703 void dvmGcScanPrimitiveClasses() 704 { 705 int i; 706 707 for (i = 0; i < PRIM_MAX; i++) { 708 dvmMarkObject((Object *)gDvm.primitiveClass[i]); // may be NULL 709 } 710 } 711 712