• 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