blob: 96493f7892afa17749ac44fbdc96452539ce63ef [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/*
18 * Operations on an Object.
19 */
20#include "Dalvik.h"
21
22/*
23 * Find a matching field, in the current class only.
24 *
25 * Returns NULL if the field can't be found. (Does not throw an exception.)
26 */
27InstField* dvmFindInstanceField(const ClassObject* clazz,
28 const char* fieldName, const char* signature)
29{
30 InstField* pField;
31 int i;
32
33 assert(clazz != NULL);
34
35 /*
36 * Find a field with a matching name and signature. The Java programming
37 * language does not allow you to have two fields with the same name
38 * and different types, but the Java VM spec does allow it, so we can't
39 * bail out early when the name matches.
40 */
41 pField = clazz->ifields;
42 for (i = 0; i < clazz->ifieldCount; i++, pField++) {
43 if (strcmp(fieldName, pField->field.name) == 0 &&
44 strcmp(signature, pField->field.signature) == 0)
45 {
46 return pField;
47 }
48 }
49
50 return NULL;
51}
52
53/*
54 * Find a matching field, in this class or a superclass.
55 *
56 * Searching through interfaces isn't necessary, because interface fields
57 * are inherently public/static/final.
58 *
59 * Returns NULL if the field can't be found. (Does not throw an exception.)
60 */
61InstField* dvmFindInstanceFieldHier(const ClassObject* clazz,
62 const char* fieldName, const char* signature)
63{
64 InstField* pField;
65
66 /*
67 * Search for a match in the current class.
68 */
69 pField = dvmFindInstanceField(clazz, fieldName, signature);
70 if (pField != NULL)
71 return pField;
72
73 if (clazz->super != NULL)
74 return dvmFindInstanceFieldHier(clazz->super, fieldName, signature);
75 else
76 return NULL;
77}
78
79
80/*
81 * Find a matching field, in this class or an interface.
82 *
83 * Returns NULL if the field can't be found. (Does not throw an exception.)
84 */
85StaticField* dvmFindStaticField(const ClassObject* clazz,
86 const char* fieldName, const char* signature)
87{
88 StaticField* pField;
89 int i;
90
91 assert(clazz != NULL);
92
Andy McFadden631444c2009-04-16 13:26:10 -070093 /*
94 * Find a field with a matching name and signature. As with instance
95 * fields, the VM allows you to have two fields with the same name so
96 * long as they have different types.
97 */
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080098 pField = clazz->sfields;
99 for (i = 0; i < clazz->sfieldCount; i++, pField++) {
Andy McFadden631444c2009-04-16 13:26:10 -0700100 if (strcmp(fieldName, pField->field.name) == 0 &&
101 strcmp(signature, pField->field.signature) == 0)
102 {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800103 return pField;
104 }
105 }
106
107 return NULL;
108}
109
110/*
111 * Find a matching field, in this class or a superclass.
112 *
113 * Returns NULL if the field can't be found. (Does not throw an exception.)
114 */
115StaticField* dvmFindStaticFieldHier(const ClassObject* clazz,
116 const char* fieldName, const char* signature)
117{
118 StaticField* pField;
119
120 /*
121 * Search for a match in the current class.
122 */
123 pField = dvmFindStaticField(clazz, fieldName, signature);
124 if (pField != NULL)
125 return pField;
126
127 /*
128 * See if it's in any of our interfaces. We don't check interfaces
129 * inherited from the superclass yet.
130 *
131 * (Note the set may have been stripped down because of redundancy with
132 * the superclass; see notes in createIftable.)
133 */
134 int i = 0;
135 if (clazz->super != NULL) {
136 assert(clazz->iftableCount >= clazz->super->iftableCount);
137 i = clazz->super->iftableCount;
138 }
139 for ( ; i < clazz->iftableCount; i++) {
140 ClassObject* iface = clazz->iftable[i].clazz;
141 pField = dvmFindStaticField(iface, fieldName, signature);
142 if (pField != NULL)
143 return pField;
144 }
145
146 if (clazz->super != NULL)
147 return dvmFindStaticFieldHier(clazz->super, fieldName, signature);
148 else
149 return NULL;
150}
151
152/*
153 * Compare the given name, return type, and argument types with the contents
154 * of the given method. This returns 0 if they are equal and non-zero if not.
155 */
156static inline int compareMethodHelper(Method* method, const char* methodName,
157 const char* returnType, size_t argCount, const char** argTypes)
158{
159 DexParameterIterator iterator;
160 const DexProto* proto;
161
162 if (strcmp(methodName, method->name) != 0) {
163 return 1;
164 }
165
166 proto = &method->prototype;
167
168 if (strcmp(returnType, dexProtoGetReturnType(proto)) != 0) {
169 return 1;
170 }
171
172 if (dexProtoGetParameterCount(proto) != argCount) {
173 return 1;
174 }
175
176 dexParameterIteratorInit(&iterator, proto);
177
178 for (/*argCount*/; argCount != 0; argCount--, argTypes++) {
179 const char* argType = *argTypes;
180 const char* paramType = dexParameterIteratorNextDescriptor(&iterator);
181
182 if (paramType == NULL) {
183 /* Param list ended early; no match */
184 break;
185 } else if (strcmp(argType, paramType) != 0) {
186 /* Types aren't the same; no match. */
187 break;
188 }
189 }
190
191 if (argCount == 0) {
192 /* We ran through all the given arguments... */
193 if (dexParameterIteratorNextDescriptor(&iterator) == NULL) {
194 /* ...and through all the method's arguments; success! */
195 return 0;
196 }
197 }
198
199 return 1;
200}
201
202/*
203 * Get the count of arguments in the given method descriptor string,
204 * and also find a pointer to the return type.
205 */
206static inline size_t countArgsAndFindReturnType(const char* descriptor,
207 const char** pReturnType)
208{
209 size_t count = 0;
210 bool bogus = false;
211 bool done = false;
212
213 assert(*descriptor == '(');
214 descriptor++;
215
216 while (!done) {
217 switch (*descriptor) {
218 case 'B': case 'C': case 'D': case 'F':
219 case 'I': case 'J': case 'S': case 'Z': {
220 count++;
221 break;
222 }
223 case '[': {
224 do {
225 descriptor++;
226 } while (*descriptor == '[');
227 /*
228 * Don't increment count, as it will be taken care of
229 * by the next iteration. Also, decrement descriptor
230 * to compensate for the increment below the switch.
231 */
232 descriptor--;
233 break;
234 }
235 case 'L': {
236 do {
237 descriptor++;
238 } while ((*descriptor != ';') && (*descriptor != '\0'));
239 count++;
240 if (*descriptor == '\0') {
241 /* Bogus descriptor. */
242 done = true;
243 bogus = true;
244 }
245 break;
246 }
247 case ')': {
248 /*
249 * Note: The loop will exit after incrementing descriptor
250 * one more time, so it then points at the return type.
251 */
252 done = true;
253 break;
254 }
255 default: {
256 /* Bogus descriptor. */
257 done = true;
258 bogus = true;
259 break;
260 }
261 }
262
263 descriptor++;
264 }
265
266 if (bogus) {
267 *pReturnType = NULL;
268 return 0;
269 }
270
271 *pReturnType = descriptor;
272 return count;
273}
274
275/*
276 * Copy the argument types into the given array using the given buffer
277 * for the contents.
278 */
279static inline void copyTypes(char* buffer, const char** argTypes,
280 size_t argCount, const char* descriptor)
281{
282 size_t i;
283 char c;
284
285 /* Skip the '('. */
286 descriptor++;
287
288 for (i = 0; i < argCount; i++) {
289 argTypes[i] = buffer;
290
291 /* Copy all the array markers and one extra character. */
292 do {
293 c = *(descriptor++);
294 *(buffer++) = c;
295 } while (c == '[');
296
297 if (c == 'L') {
298 /* Copy the rest of a class name. */
299 do {
300 c = *(descriptor++);
301 *(buffer++) = c;
302 } while (c != ';');
303 }
304
305 *(buffer++) = '\0';
306 }
307}
308
309/*
310 * Look for a match in the given class. Returns the match if found
311 * or NULL if not.
312 */
313static Method* findMethodInListByDescriptor(const ClassObject* clazz,
314 bool findVirtual, bool isHier, const char* name, const char* descriptor)
315{
316 const char* returnType;
317 size_t argCount = countArgsAndFindReturnType(descriptor, &returnType);
318
319 if (returnType == NULL) {
320 LOGW("Bogus method descriptor: %s\n", descriptor);
321 return NULL;
322 }
323
324 /*
325 * Make buffer big enough for all the argument type characters and
326 * one '\0' per argument. The "- 2" is because "returnType -
327 * descriptor" includes two parens.
328 */
329 char buffer[argCount + (returnType - descriptor) - 2];
330 const char* argTypes[argCount];
331
332 copyTypes(buffer, argTypes, argCount, descriptor);
333
334 while (clazz != NULL) {
335 Method* methods;
336 size_t methodCount;
337 size_t i;
338
339 if (findVirtual) {
340 methods = clazz->virtualMethods;
341 methodCount = clazz->virtualMethodCount;
342 } else {
343 methods = clazz->directMethods;
344 methodCount = clazz->directMethodCount;
345 }
346
347 for (i = 0; i < methodCount; i++) {
348 Method* method = &methods[i];
349 if (compareMethodHelper(method, name, returnType, argCount,
350 argTypes) == 0) {
351 return method;
352 }
353 }
354
355 if (! isHier) {
356 break;
357 }
358
359 clazz = clazz->super;
360 }
361
362 return NULL;
363}
364
365/*
366 * Look for a match in the given clazz. Returns the match if found
367 * or NULL if not.
368 */
369static Method* findMethodInListByProto(const ClassObject* clazz,
370 bool findVirtual, bool isHier, const char* name, const DexProto* proto)
371{
372 while (clazz != NULL) {
373 Method* methods;
374 size_t methodCount;
375 size_t i;
376
377 if (findVirtual) {
378 methods = clazz->virtualMethods;
379 methodCount = clazz->virtualMethodCount;
380 } else {
381 methods = clazz->directMethods;
382 methodCount = clazz->directMethodCount;
383 }
384
385 for (i = 0; i < methodCount; i++) {
386 Method* method = &methods[i];
387 if (dvmCompareNameProtoAndMethod(name, proto, method) == 0) {
388 return method;
389 }
390 }
391
392 if (! isHier) {
393 break;
394 }
395
396 clazz = clazz->super;
397 }
398
399 return NULL;
400}
401
402/*
403 * Find a "virtual" method in a class.
404 *
405 * Does not chase into the superclass.
406 *
407 * Returns NULL if the method can't be found. (Does not throw an exception.)
408 */
409Method* dvmFindVirtualMethodByDescriptor(const ClassObject* clazz,
410 const char* methodName, const char* descriptor)
411{
412 return findMethodInListByDescriptor(clazz, true, false,
413 methodName, descriptor);
414
415 // TODO? - throw IncompatibleClassChangeError if a match is
416 // found in the directMethods list, rather than NotFoundError.
417 // Note we could have been called by dvmFindVirtualMethodHier though.
418}
419
420
421/*
422 * Find a "virtual" method in a class, knowing only the name. This is
423 * only useful in limited circumstances, e.g. when searching for a member
424 * of an annotation class.
425 *
426 * Does not chase into the superclass.
427 *
428 * Returns NULL if the method can't be found. (Does not throw an exception.)
429 */
430Method* dvmFindVirtualMethodByName(const ClassObject* clazz,
431 const char* methodName)
432{
433 Method* methods = clazz->virtualMethods;
434 int methodCount = clazz->virtualMethodCount;
435 int i;
436
437 for (i = 0; i < methodCount; i++) {
438 if (strcmp(methods[i].name, methodName) == 0)
439 return &methods[i];
440 }
441
442 return NULL;
443}
444
445/*
446 * Find a "virtual" method in a class.
447 *
448 * Does not chase into the superclass.
449 *
450 * Returns NULL if the method can't be found. (Does not throw an exception.)
451 */
452Method* dvmFindVirtualMethod(const ClassObject* clazz, const char* methodName,
453 const DexProto* proto)
454{
455 return findMethodInListByProto(clazz, true, false, methodName, proto);
456}
457
458/*
459 * Find a "virtual" method in a class. If we don't find it, try the
460 * superclass.
461 *
462 * Returns NULL if the method can't be found. (Does not throw an exception.)
463 */
464Method* dvmFindVirtualMethodHierByDescriptor(const ClassObject* clazz,
465 const char* methodName, const char* descriptor)
466{
467 return findMethodInListByDescriptor(clazz, true, true,
468 methodName, descriptor);
469}
470
471/*
472 * Find a "virtual" method in a class. If we don't find it, try the
473 * superclass.
474 *
475 * Returns NULL if the method can't be found. (Does not throw an exception.)
476 */
477Method* dvmFindVirtualMethodHier(const ClassObject* clazz,
478 const char* methodName, const DexProto* proto)
479{
480 return findMethodInListByProto(clazz, true, true, methodName, proto);
481}
482
483/*
484 * Find a "direct" method (static, private, or "<*init>").
485 *
486 * Returns NULL if the method can't be found. (Does not throw an exception.)
487 */
488Method* dvmFindDirectMethodByDescriptor(const ClassObject* clazz,
489 const char* methodName, const char* descriptor)
490{
491 return findMethodInListByDescriptor(clazz, false, false,
492 methodName, descriptor);
493}
494
495/*
496 * Find a "direct" method. If we don't find it, try the superclass. This
497 * is only appropriate for static methods, but will work for all direct
498 * methods.
499 *
500 * Returns NULL if the method can't be found. (Does not throw an exception.)
501 */
502Method* dvmFindDirectMethodHierByDescriptor(const ClassObject* clazz,
503 const char* methodName, const char* descriptor)
504{
505 return findMethodInListByDescriptor(clazz, false, true,
506 methodName, descriptor);
507}
508
509/*
510 * Find a "direct" method (static or "<*init>").
511 *
512 * Returns NULL if the method can't be found. (Does not throw an exception.)
513 */
514Method* dvmFindDirectMethod(const ClassObject* clazz, const char* methodName,
515 const DexProto* proto)
516{
517 return findMethodInListByProto(clazz, false, false, methodName, proto);
518}
519
520/*
521 * Find a "direct" method in a class. If we don't find it, try the
522 * superclass.
523 *
524 * Returns NULL if the method can't be found. (Does not throw an exception.)
525 */
526Method* dvmFindDirectMethodHier(const ClassObject* clazz,
527 const char* methodName, const DexProto* proto)
528{
529 return findMethodInListByProto(clazz, false, true, methodName, proto);
530}
531
532/*
533 * We have a method pointer for a method in "clazz", but it might be
534 * pointing to a method in a derived class. We want to find the actual entry
535 * from the class' vtable. If "clazz" is an interface, we have to do a
536 * little more digging.
537 *
538 * (This is used for reflection and JNI "call method" calls.)
539 */
540const Method* dvmGetVirtualizedMethod(const ClassObject* clazz,
541 const Method* meth)
542{
543 Method* actualMeth;
544 int methodIndex;
545
546 assert(!dvmIsStaticMethod(meth));
547
548 if (dvmIsPrivateMethod(meth)) // no vtable entry for these
549 return meth;
550
551 /*
552 * If the method was declared in an interface, we need to scan through
553 * the class' list of interfaces for it, and find the vtable index
554 * from that.
555 *
556 * TODO: use the interface cache.
557 */
558 if (dvmIsInterfaceClass(meth->clazz)) {
559 int i;
560
561 for (i = 0; i < clazz->iftableCount; i++) {
562 if (clazz->iftable[i].clazz == meth->clazz)
563 break;
564 }
565 if (i == clazz->iftableCount) {
566 dvmThrowException("Ljava/lang/IncompatibleClassChangeError;",
567 "invoking method from interface not implemented by class");
568 return NULL;
569 }
570
571 methodIndex = clazz->iftable[i].methodIndexArray[meth->methodIndex];
572 } else {
573 methodIndex = meth->methodIndex;
574 }
575
576 assert(methodIndex >= 0 && methodIndex < clazz->vtableCount);
577 actualMeth = clazz->vtable[methodIndex];
578
579 /*
580 * Make sure there's code to execute.
581 */
582 if (dvmIsAbstractMethod(actualMeth)) {
583 dvmThrowException("Ljava/lang/AbstractMethodError;", NULL);
584 return NULL;
585 }
586 assert(!dvmIsMirandaMethod(actualMeth));
587
588 return actualMeth;
589}
590
591/*
592 * Get the source file for a method.
593 */
594const char* dvmGetMethodSourceFile(const Method* meth)
595{
596 /*
597 * TODO: A method's debug info can override the default source
598 * file for a class, so we should account for that possibility
599 * here.
600 */
601 return meth->clazz->sourceFile;
602}
603
604/*
605 * Dump some information about an object.
606 */
607void dvmDumpObject(const Object* obj)
608{
609 ClassObject* clazz;
610 int i;
611
612 if (obj == NULL || obj->clazz == NULL) {
613 LOGW("Null or malformed object not dumped\n");
614 return;
615 }
616
617 clazz = obj->clazz;
Andy McFadden686e1e22009-05-26 16:56:30 -0700618 LOGD("----- Object dump: %p (%s, %d bytes) -----\n",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800619 obj, clazz->descriptor, (int) clazz->objectSize);
620 //printHexDump(obj, clazz->objectSize);
Andy McFadden686e1e22009-05-26 16:56:30 -0700621 LOGD(" Fields:\n");
622 while (clazz != NULL) {
623 LOGD(" -- %s\n", clazz->descriptor);
624 for (i = 0; i < clazz->ifieldCount; i++) {
625 const InstField* pField = &clazz->ifields[i];
626 char type = pField->field.signature[0];
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800627
Andy McFadden686e1e22009-05-26 16:56:30 -0700628 if (type == 'F' || type == 'D') {
629 double dval;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800630
Andy McFadden686e1e22009-05-26 16:56:30 -0700631 if (type == 'F')
632 dval = dvmGetFieldFloat(obj, pField->byteOffset);
633 else
634 dval = dvmGetFieldDouble(obj, pField->byteOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800635
Andy McFadden686e1e22009-05-26 16:56:30 -0700636 LOGD(" %2d: '%s' '%s' af=%04x off=%d %.3f\n", i,
637 pField->field.name, pField->field.signature,
638 pField->field.accessFlags, pField->byteOffset, dval);
639 } else {
640 u8 lval;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800641
Andy McFadden686e1e22009-05-26 16:56:30 -0700642 if (type == 'J')
643 lval = dvmGetFieldLong(obj, pField->byteOffset);
644 else if (type == 'Z')
645 lval = dvmGetFieldBoolean(obj, pField->byteOffset);
646 else
647 lval = dvmGetFieldInt(obj, pField->byteOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800648
Andy McFadden686e1e22009-05-26 16:56:30 -0700649 LOGD(" %2d: '%s' '%s' af=%04x off=%d 0x%08llx\n", i,
650 pField->field.name, pField->field.signature,
651 pField->field.accessFlags, pField->byteOffset, lval);
652 }
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800653 }
Andy McFadden686e1e22009-05-26 16:56:30 -0700654
655 clazz = clazz->super;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800656 }
657}
658