blob: c76ea53712032956f83b81a927a25c864f0c7d15 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
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
28static ClassObject* createArrayClass(const char* descriptor, Object* loader);
29static ClassObject* createPrimitiveClass(int idx);
30
31static 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 */
41ArrayObject* 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 */
81ArrayObject* 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 */
101ClassObject* dvmFindArrayClassForElement(ClassObject* elemClassObj)
102{
103 ClassObject* arrayClass;
104
105 assert(elemClassObj != NULL);
106
Barry Hayesfcccb3b2009-10-30 09:36:08 -0700107 /* Simply prepend "[" to the descriptor. */
108 int nameLen = strlen(elemClassObj->descriptor);
109 char className[nameLen + 2];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800110
Barry Hayesfcccb3b2009-10-30 09:36:08 -0700111 className[0] = '[';
112 memcpy(className+1, elemClassObj->descriptor, nameLen+1);
113 arrayClass = dvmFindArrayClass(className, elemClassObj->classLoader);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800114
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 */
129ArrayObject* 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 */
154ArrayObject* 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 */
225ArrayObject* 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 Object** contents;
250 int i;
251
252 /* if we have X[][], find X[] */
253 subArrayClass = dvmFindArrayClass(elemName, arrayClass->classLoader);
254 if (subArrayClass == NULL) {
255 /* not enough '['s on the initial class? */
256 assert(dvmCheckException(dvmThreadSelf()));
257 return NULL;
258 }
259 assert(dvmIsArrayClass(subArrayClass));
260
261 /* allocate the array that holds the sub-arrays */
262 newArray = dvmAllocArray(arrayClass, *dimensions, kObjectArrayRefWidth,
263 ALLOC_DEFAULT);
264 if (newArray == NULL) {
265 assert(dvmCheckException(dvmThreadSelf()));
266 return NULL;
267 }
268
269 /*
270 * Create a new sub-array in every element of the array.
271 */
272 contents = (Object**) newArray->contents;
273 for (i = 0; i < *dimensions; i++) {
274 ArrayObject* newSubArray;
275
276 newSubArray = dvmAllocMultiArray(subArrayClass, curDim-1,
277 dimensions+1);
278 if (newSubArray == NULL) {
279 dvmReleaseTrackedAlloc((Object*) newArray, NULL);
280 assert(dvmCheckException(dvmThreadSelf()));
281 return NULL;
282 }
283
284 *contents++ = (Object*) newSubArray;
285 dvmReleaseTrackedAlloc((Object*) newSubArray, NULL);
286 }
287 }
288
289 /* caller must call dvmReleaseTrackedAlloc */
290 return newArray;
291}
292
293
294/*
295 * Find an array class, by name (e.g. "[I").
296 *
297 * If the array class doesn't exist, we generate it.
298 *
299 * If the element class doesn't exist, we return NULL (no exception raised).
300 */
301ClassObject* dvmFindArrayClass(const char* descriptor, Object* loader)
302{
303 ClassObject* clazz;
304
305 assert(descriptor[0] == '[');
306 //LOGV("dvmFindArrayClass: '%s' %p\n", descriptor, loader);
307
308 clazz = dvmLookupClass(descriptor, loader, false);
309 if (clazz == NULL) {
310 LOGV("Array class '%s' %p not found; creating\n", descriptor, loader);
311 clazz = createArrayClass(descriptor, loader);
312 if (clazz != NULL)
313 dvmAddInitiatingLoader(clazz, loader);
314 }
315
316 return clazz;
317}
318
319/*
320 * Create an array class (i.e. the class object for the array, not the
321 * array itself). "descriptor" looks like "[C" or "[Ljava/lang/String;".
322 *
323 * If "descriptor" refers to an array of primitives, look up the
324 * primitive type's internally-generated class object.
325 *
326 * "loader" is the class loader of the class that's referring to us. It's
327 * used to ensure that we're looking for the element type in the right
328 * context. It does NOT become the class loader for the array class; that
329 * always comes from the base element class.
330 *
331 * Returns NULL with an exception raised on failure.
332 */
333static ClassObject* createArrayClass(const char* descriptor, Object* loader)
334{
335 ClassObject* newClass = NULL;
336 ClassObject* elementClass = NULL;
337 int arrayDim;
338 u4 extraFlags;
339
340 assert(descriptor[0] == '[');
341 assert(gDvm.classJavaLangClass != NULL);
342 assert(gDvm.classJavaLangObject != NULL);
343
344 /*
345 * Identify the underlying element class and the array dimension depth.
346 */
347 extraFlags = CLASS_ISARRAY;
348 if (descriptor[1] == '[') {
349 /* array of arrays; keep descriptor and grab stuff from parent */
350 ClassObject* outer;
351
352 outer = dvmFindClassNoInit(&descriptor[1], loader);
353 if (outer != NULL) {
354 /* want the base class, not "outer", in our elementClass */
355 elementClass = outer->elementClass;
356 arrayDim = outer->arrayDim + 1;
357 extraFlags |= CLASS_ISOBJECTARRAY;
358 } else {
359 assert(elementClass == NULL); /* make sure we fail */
360 }
361 } else {
362 arrayDim = 1;
363 if (descriptor[1] == 'L') {
364 /* array of objects; strip off "[" and look up descriptor. */
365 const char* subDescriptor = &descriptor[1];
366 LOGVV("searching for element class '%s'\n", subDescriptor);
367 elementClass = dvmFindClassNoInit(subDescriptor, loader);
368 extraFlags |= CLASS_ISOBJECTARRAY;
369 } else {
370 /* array of a primitive type */
371 elementClass = dvmFindPrimitiveClass(descriptor[1]);
372 }
373 }
374
375 if (elementClass == NULL) {
376 /* failed */
377 assert(dvmCheckException(dvmThreadSelf()));
378 dvmFreeClassInnards(newClass);
379 dvmReleaseTrackedAlloc((Object*) newClass, NULL);
380 return NULL;
381 }
382
383 /*
384 * See if it's already loaded. Array classes are always associated
385 * with the class loader of their underlying element type -- an array
386 * of Strings goes with the loader for java/lang/String -- so we need
387 * to look for it there. (The caller should have checked for the
388 * existence of the class before calling here, but they did so with
389 * *their* class loader, not the element class' loader.)
390 *
391 * If we find it, the caller adds "loader" to the class' initiating
392 * loader list, which should prevent us from going through this again.
393 *
394 * This call is unnecessary if "loader" and "elementClass->classLoader"
395 * are the same, because our caller (dvmFindArrayClass) just did the
396 * lookup. (Even if we get this wrong we still have correct behavior,
397 * because we effectively do this lookup again when we add the new
398 * class to the hash table -- necessary because of possible races with
399 * other threads.)
400 */
401 if (loader != elementClass->classLoader) {
402 LOGVV("--- checking for '%s' in %p vs. elem %p\n",
403 descriptor, loader, elementClass->classLoader);
404 newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
405 if (newClass != NULL) {
406 LOGV("--- we already have %s in %p, don't need in %p\n",
407 descriptor, elementClass->classLoader, loader);
408 return newClass;
409 }
410 }
411
412
413 /*
414 * Fill out the fields in the ClassObject.
415 *
416 * It is possible to execute some methods against arrays, because all
417 * arrays are instances of Object, so we need to set up a vtable. We
418 * can just point at the one in Object.
419 *
420 * Array classes are simple enough that we don't need to do a full
421 * link step.
422 */
423 newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
424 if (newClass == NULL)
425 return NULL;
426 DVM_OBJECT_INIT(&newClass->obj, gDvm.unlinkedJavaLangClass);
427 dvmSetClassSerialNumber(newClass);
428 newClass->descriptorAlloc = strdup(descriptor);
429 newClass->descriptor = newClass->descriptorAlloc;
430 newClass->super = gDvm.classJavaLangObject;
431 newClass->vtableCount = gDvm.classJavaLangObject->vtableCount;
432 newClass->vtable = gDvm.classJavaLangObject->vtable;
433 newClass->primitiveType = PRIM_NOT;
434 newClass->elementClass = elementClass;
435 newClass->classLoader = elementClass->classLoader;
436 newClass->arrayDim = arrayDim;
437 newClass->status = CLASS_INITIALIZED;
438#if WITH_HPROF && WITH_HPROF_STACK
439 hprofFillInStackTrace(newClass);
440#endif
441
442 /* don't need to set newClass->objectSize */
443
444 /*
445 * All arrays have java/lang/Cloneable and java/io/Serializable as
446 * interfaces. We need to set that up here, so that stuff like
447 * "instanceof" works right.
448 *
449 * Note: The GC could run during the call to dvmFindSystemClassNoInit(),
450 * so we need to make sure the class object is GC-valid while we're in
451 * there. Do this by clearing the interface list so the GC will just
452 * think that the entries are null.
453 *
454 * TODO?
455 * We may want to cache these two classes to avoid the lookup, though
456 * it's not vital -- we only do it when creating an array class, not
457 * every time we create an array. Better yet, create a single, global
458 * copy of "interfaces" and "iftable" somewhere near the start and
459 * just point to those (and remember not to free them for arrays).
460 */
461 newClass->interfaceCount = 2;
462 newClass->interfaces = (ClassObject**)dvmLinearAlloc(newClass->classLoader,
463 sizeof(ClassObject*) * 2);
464 memset(newClass->interfaces, 0, sizeof(ClassObject*) * 2);
465 newClass->interfaces[0] =
466 dvmFindSystemClassNoInit("Ljava/lang/Cloneable;");
467 newClass->interfaces[1] =
468 dvmFindSystemClassNoInit("Ljava/io/Serializable;");
469 dvmLinearReadOnly(newClass->classLoader, newClass->interfaces);
470 if (newClass->interfaces[0] == NULL || newClass->interfaces[1] == NULL) {
471 LOGE("Unable to create array class '%s': missing interfaces\n",
472 descriptor);
473 dvmFreeClassInnards(newClass);
474 dvmThrowException("Ljava/lang/InternalError;", "missing array ifaces");
475 dvmReleaseTrackedAlloc((Object*) newClass, NULL);
476 return NULL;
477 }
478 /*
479 * We assume that Cloneable/Serializable don't have superinterfaces --
480 * normally we'd have to crawl up and explicitly list all of the
481 * supers as well. These interfaces don't have any methods, so we
482 * don't have to worry about the ifviPool either.
483 */
484 newClass->iftableCount = 2;
485 newClass->iftable = (InterfaceEntry*) dvmLinearAlloc(newClass->classLoader,
486 sizeof(InterfaceEntry) * 2);
487 memset(newClass->iftable, 0, sizeof(InterfaceEntry) * 2);
488 newClass->iftable[0].clazz = newClass->interfaces[0];
489 newClass->iftable[1].clazz = newClass->interfaces[1];
490 dvmLinearReadOnly(newClass->classLoader, newClass->iftable);
491
492 /*
493 * Inherit access flags from the element. Arrays can't be used as a
494 * superclass or interface, so we want to add "final" and remove
495 * "interface".
496 *
497 * Don't inherit any non-standard flags (e.g., CLASS_FINALIZABLE)
498 * from elementClass. We assume that the array class does not
499 * override finalize().
500 */
501 newClass->accessFlags = ((newClass->elementClass->accessFlags &
502 ~ACC_INTERFACE) | ACC_FINAL) & JAVA_FLAGS_MASK;
503
504 /* Set the flags we determined above.
505 * This must happen after accessFlags is set.
506 */
507 SET_CLASS_FLAG(newClass, extraFlags);
508
509 if (!dvmAddClassToHash(newClass)) {
510 /*
511 * Another thread must have loaded the class after we
512 * started but before we finished. Discard what we've
513 * done and leave some hints for the GC.
514 */
515 LOGI("WOW: somebody generated %s simultaneously\n",
516 newClass->descriptor);
517
518 /* Clean up the class before letting the
519 * GC get its hands on it.
520 */
521 assert(newClass->obj.clazz == gDvm.unlinkedJavaLangClass);
522 dvmFreeClassInnards(newClass);
523
524 /* Let the GC free the class.
525 */
526 dvmReleaseTrackedAlloc((Object*) newClass, NULL);
527
528 /* Grab the winning class.
529 */
530 newClass = dvmLookupClass(descriptor, elementClass->classLoader, false);
531 assert(newClass != NULL);
532 return newClass;
533 }
534
535 /* make it available to the GC */
536 newClass->obj.clazz = gDvm.classJavaLangClass;
537 dvmReleaseTrackedAlloc((Object*) newClass, NULL);
538
539 LOGV("Created array class '%s' %p (access=0x%04x.%04x)\n",
540 descriptor, newClass->classLoader,
541 newClass->accessFlags >> 16,
542 newClass->accessFlags & JAVA_FLAGS_MASK);
543
544 return newClass;
545}
546
547/*
548 * Get a class we generated for the primitive types.
549 *
550 * These correspond to e.g. Integer.TYPE, and are used as the element
551 * class in arrays of primitives.
552 *
553 * "type" should be 'I', 'J', 'Z', etc.
554 *
555 * Returns NULL if the type doesn't correspond to a known primitive type.
556 */
557ClassObject* dvmFindPrimitiveClass(char type)
558{
559 int idx;
560
561 switch (type) {
562 case 'Z':
563 idx = PRIM_BOOLEAN;
564 break;
565 case 'C':
566 idx = PRIM_CHAR;
567 break;
568 case 'F':
569 idx = PRIM_FLOAT;
570 break;
571 case 'D':
572 idx = PRIM_DOUBLE;
573 break;
574 case 'B':
575 idx = PRIM_BYTE;
576 break;
577 case 'S':
578 idx = PRIM_SHORT;
579 break;
580 case 'I':
581 idx = PRIM_INT;
582 break;
583 case 'J':
584 idx = PRIM_LONG;
585 break;
586 case 'V':
587 idx = PRIM_VOID;
588 break;
589 default:
590 LOGW("Unknown primitive type '%c'\n", type);
591 return NULL;
592 }
593
594 /*
595 * Create the primitive class if it hasn't already been, and add it
596 * to the table.
597 */
598 if (gDvm.primitiveClass[idx] == NULL) {
599 ClassObject* primClass = createPrimitiveClass(idx);
600 dvmReleaseTrackedAlloc((Object*) primClass, NULL);
601
602 if (!ATOMIC_CMP_SWAP((int*) &gDvm.primitiveClass[idx],
603 0, (int) primClass))
604 {
605 /*
606 * Looks like somebody beat us to it. Free up the one we
607 * just created and use the other one.
608 */
609 dvmFreeClassInnards(primClass);
610 }
611 }
612
613 return gDvm.primitiveClass[idx];
614}
615
616/*
617 * Synthesize a primitive class.
618 *
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800619 * Just creates the class and returns it (does not add it to the class list).
620 */
621static ClassObject* createPrimitiveClass(int idx)
622{
623 ClassObject* newClass;
624 static const char* kClassDescriptors[PRIM_MAX] = {
625 "Z", "C", "F", "D", "B", "S", "I", "J", "V"
626 };
627
628 assert(gDvm.classJavaLangClass != NULL);
629 assert(idx >= 0 && idx < PRIM_MAX);
630
631 /*
632 * Fill out a few fields in the ClassObject.
633 *
634 * Note that primitive classes do not sub-class java/lang/Object. This
635 * matters for "instanceof" checks. Also, we assume that the primitive
636 * class does not override finalize().
637 */
638 newClass = (ClassObject*) dvmMalloc(sizeof(*newClass), ALLOC_DEFAULT);
639 if (newClass == NULL)
640 return NULL;
641 DVM_OBJECT_INIT(&newClass->obj, gDvm.classJavaLangClass);
642 dvmSetClassSerialNumber(newClass);
643 newClass->accessFlags = ACC_PUBLIC | ACC_FINAL | ACC_ABSTRACT;
644 newClass->primitiveType = idx;
645 newClass->descriptorAlloc = NULL;
646 newClass->descriptor = kClassDescriptors[idx];
647 //newClass->super = gDvm.classJavaLangObject;
648 newClass->status = CLASS_INITIALIZED;
649#if WITH_HPROF && WITH_HPROF_STACK
650 hprofFillInStackTrace(newClass);
651#endif
652
653 /* don't need to set newClass->objectSize */
654
655 LOGVV("Created primitive class '%s'\n", kClassDescriptors[idx]);
656
657 return newClass;
658}
659
660/*
661 * Copy the entire contents of one array of objects to another. If the copy
662 * is impossible because of a type clash, we fail and return "false".
663 */
664bool dvmCopyObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
665 ClassObject* dstElemClass)
666{
667 Object** src = (Object**)srcArray->contents;
668 Object** dst = (Object**)dstArray->contents;
669 u4 count = dstArray->length;
670
671 assert(srcArray->length == dstArray->length);
672 assert(dstArray->obj.clazz->elementClass == dstElemClass ||
673 (dstArray->obj.clazz->elementClass == dstElemClass->elementClass &&
674 dstArray->obj.clazz->arrayDim == dstElemClass->arrayDim+1));
675
676 while (count--) {
677 if (!dvmInstanceof((*src)->clazz, dstElemClass)) {
678 LOGW("dvmCopyObjectArray: can't store %s in %s\n",
679 (*src)->clazz->descriptor, dstElemClass->descriptor);
680 return false;
681 }
682 *dst++ = *src++;
683 }
684
685 return true;
686}
687
688/*
Andy McFadden4bc10cc2010-01-13 10:29:44 -0800689 * Copy the entire contents of an array of boxed primitives into an
690 * array of primitives. The boxed value must fit in the primitive (i.e.
691 * narrowing conversions are not allowed).
692 */
693bool dvmUnboxObjectArray(ArrayObject* dstArray, const ArrayObject* srcArray,
694 ClassObject* dstElemClass)
695{
696 Object** src = (Object**)srcArray->contents;
697 void* dst = (void*)dstArray->contents;
698 u4 count = dstArray->length;
699 PrimitiveType typeIndex = dstElemClass->primitiveType;
700
701 assert(typeIndex != PRIM_NOT);
702 assert(srcArray->length == dstArray->length);
703
704 while (count--) {
705 JValue result;
706
707 /*
708 * This will perform widening conversions as appropriate. It
709 * might make sense to be more restrictive and require that the
710 * primitive type exactly matches the box class, but it's not
711 * necessary for correctness.
712 */
713 if (!dvmUnwrapPrimitive(*src, dstElemClass, &result)) {
714 LOGW("dvmCopyObjectArray: can't store %s in %s\n",
715 (*src)->clazz->descriptor, dstElemClass->descriptor);
716 return false;
717 }
718
719 /* would be faster with 4 loops, but speed not crucial here */
720 switch (typeIndex) {
721 case PRIM_BOOLEAN:
722 case PRIM_BYTE:
723 {
724 u1* tmp = dst;
725 *tmp++ = result.b;
726 dst = tmp;
727 }
728 break;
729 case PRIM_CHAR:
730 case PRIM_SHORT:
731 {
732 u2* tmp = dst;
733 *tmp++ = result.s;
734 dst = tmp;
735 }
736 break;
737 case PRIM_FLOAT:
738 case PRIM_INT:
739 {
740 u4* tmp = dst;
741 *tmp++ = result.i;
742 dst = tmp;
743 }
744 break;
745 case PRIM_DOUBLE:
746 case PRIM_LONG:
747 {
748 u8* tmp = dst;
749 *tmp++ = result.j;
750 dst = tmp;
751 }
752 break;
753 default:
754 /* should not be possible to get here */
755 dvmAbort();
756 }
757
758 src++;
759 }
760
761 return true;
762}
763
Carl Shapiro1e714bb2010-03-16 03:26:49 -0700764static size_t arrayElementWidth(const ArrayObject *array)
765{
766 const char *descriptor;
767
768 if (dvmIsObjectArray(array)) {
769 return sizeof(Object *);
770 } else {
771 descriptor = array->obj.clazz->descriptor;
772 switch (descriptor[1]) {
773 case 'B': return 1; /* byte */
774 case 'C': return 2; /* char */
775 case 'D': return 8; /* double */
776 case 'F': return 4; /* float */
777 case 'I': return 4; /* int */
778 case 'J': return 8; /* long */
779 case 'S': return 2; /* short */
780 case 'Z': return 1; /* boolean */
781 }
782 }
783 LOGE("object %p has an unhandled descriptor '%s'", array, descriptor);
784 dvmDumpThread(dvmThreadSelf(), false);
785 dvmAbort();
786 return 0; /* Quiet the compiler. */
787}
788
789size_t dvmArrayObjectLength(const ArrayObject *array)
790{
791 size_t length;
792
793 length = offsetof(ArrayObject, contents);
794 length += array->length * arrayElementWidth(array);
795 return length;
796}
797
Andy McFadden4bc10cc2010-01-13 10:29:44 -0800798/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800799 * Add all primitive classes to the root set of objects.
800TODO: do these belong to the root class loader?
801 */
802void dvmGcScanPrimitiveClasses()
803{
804 int i;
805
806 for (i = 0; i < PRIM_MAX; i++) {
807 dvmMarkObject((Object *)gDvm.primitiveClass[i]); // may be NULL
808 }
809}