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