• 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