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 /*
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 */
dvmFindInstanceField(const ClassObject * clazz,const char * fieldName,const char * signature)27 InstField* 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 */
dvmFindInstanceFieldHier(const ClassObject * clazz,const char * fieldName,const char * signature)61 InstField* 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 */
dvmFindStaticField(const ClassObject * clazz,const char * fieldName,const char * signature)85 StaticField* 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 */
dvmFindStaticFieldHier(const ClassObject * clazz,const char * fieldName,const char * signature)117 StaticField* 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 */
compareMethodHelper(Method * method,const char * methodName,const char * returnType,size_t argCount,const char ** argTypes)158 static 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 */
countArgsAndFindReturnType(const char * descriptor,const char ** pReturnType)208 static 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 */
copyTypes(char * buffer,const char ** argTypes,size_t argCount,const char * descriptor)281 static 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 */
findMethodInListByDescriptor(const ClassObject * clazz,bool findVirtual,bool isHier,const char * name,const char * descriptor)315 static 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 */
findMethodInListByProto(const ClassObject * clazz,bool findVirtual,bool isHier,const char * name,const DexProto * proto)371 static 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 */
dvmFindVirtualMethodByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)411 Method* 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 */
dvmFindVirtualMethodByName(const ClassObject * clazz,const char * methodName)432 Method* 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 */
dvmFindVirtualMethod(const ClassObject * clazz,const char * methodName,const DexProto * proto)454 Method* 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 */
dvmFindVirtualMethodHierByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)466 Method* 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 */
dvmFindVirtualMethodHier(const ClassObject * clazz,const char * methodName,const DexProto * proto)479 Method* 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 */
dvmFindDirectMethodByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)490 Method* 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 */
dvmFindDirectMethodHierByDescriptor(const ClassObject * clazz,const char * methodName,const char * descriptor)504 Method* 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 */
dvmFindDirectMethod(const ClassObject * clazz,const char * methodName,const DexProto * proto)516 Method* 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 */
dvmFindDirectMethodHier(const ClassObject * clazz,const char * methodName,const DexProto * proto)528 Method* 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 */
dvmGetVirtualizedMethod(const ClassObject * clazz,const Method * meth)542 const 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 */
dvmGetMethodSourceFile(const Method * meth)596 const 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 */
dvmDumpObject(const Object * obj)609 void 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
654