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