• 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     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