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