• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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