2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Functions for dealing with method prototypes
27 * ===========================================================================
29 * ===========================================================================
33 * Make sure that the given cache can hold a string of the given length,
34 * including the final '\0' byte.
36 static void dexStringCacheAlloc(DexStringCache* pCache, size_t length) {
37 if (pCache->allocatedSize != 0) {
38 if (pCache->allocatedSize >= length) {
41 free((void*) pCache->value);
44 if (length <= sizeof(pCache->buffer)) {
45 pCache->value = pCache->buffer;
46 pCache->allocatedSize = 0;
48 pCache->value = malloc(length);
49 pCache->allocatedSize = length;
54 * Initialize the given DexStringCache. Use this function before passing
55 * one into any other function.
57 void dexStringCacheInit(DexStringCache* pCache) {
58 pCache->value = pCache->buffer;
59 pCache->allocatedSize = 0;
60 pCache->buffer[0] = '\0';
64 * Release the allocated contents of the given DexStringCache, if any.
65 * Use this function after your last use of a DexStringCache.
67 void dexStringCacheRelease(DexStringCache* pCache) {
68 if (pCache->allocatedSize != 0) {
69 free((void*) pCache->value);
70 pCache->value = pCache->buffer;
71 pCache->allocatedSize = 0;
76 * If the given DexStringCache doesn't already point at the given value,
77 * make a copy of it into the cache. This always returns a writable
78 * pointer to the contents (whether or not a copy had to be made). This
79 * function is intended to be used after making a call that at least
80 * sometimes doesn't populate a DexStringCache.
82 char* dexStringCacheEnsureCopy(DexStringCache* pCache, const char* value) {
83 if (value != pCache->value) {
84 size_t length = strlen(value) + 1;
85 dexStringCacheAlloc(pCache, length);
86 memcpy(pCache->value, value, length);
93 * Abandon the given DexStringCache, and return a writable copy of the
94 * given value (reusing the string cache's allocation if possible).
95 * The return value must be free()d by the caller. Use this instead of
96 * dexStringCacheRelease() if you want the buffer to survive past the
97 * scope of the DexStringCache.
99 char* dexStringCacheAbandon(DexStringCache* pCache, const char* value) {
100 if ((value == pCache->value) && (pCache->allocatedSize != 0)) {
101 char* result = pCache->value;
102 pCache->allocatedSize = 0;
103 pCache->value = pCache->buffer;
106 return strdup(value);
112 * ===========================================================================
114 * ===========================================================================
118 * Return the DexProtoId from the given DexProto. The DexProto must
119 * actually refer to a DexProtoId.
121 static inline const DexProtoId* getProtoId(const DexProto* pProto) {
122 return dexGetProtoId(pProto->dexFile, pProto->protoIdx);
126 * Get the short-form method descriptor for the given prototype. The
127 * prototype must be protoIdx-based.
129 const char* dexProtoGetShorty(const DexProto* pProto) {
130 const DexProtoId* protoId = getProtoId(pProto);
132 return dexStringById(pProto->dexFile, protoId->shortyIdx);
136 * Get the full method descriptor for the given prototype.
138 const char* dexProtoGetMethodDescriptor(const DexProto* pProto,
139 DexStringCache* pCache) {
140 const DexFile* dexFile = pProto->dexFile;
141 const DexProtoId* protoId = getProtoId(pProto);
142 const DexTypeList* typeList = dexGetProtoParameters(dexFile, protoId);
143 size_t length = 3; // parens and terminating '\0'
144 u4 paramCount = (typeList == NULL) ? 0 : typeList->size;
147 for (i = 0; i < paramCount; i++) {
148 u4 idx = dexTypeListGetIdx(typeList, i);
149 length += strlen(dexStringByTypeIdx(dexFile, idx));
152 length += strlen(dexStringByTypeIdx(dexFile, protoId->returnTypeIdx));
154 dexStringCacheAlloc(pCache, length);
156 char *at = (char*) pCache->value;
159 for (i = 0; i < paramCount; i++) {
160 u4 idx = dexTypeListGetIdx(typeList, i);
161 const char* desc = dexStringByTypeIdx(dexFile, idx);
168 strcpy(at, dexStringByTypeIdx(dexFile, protoId->returnTypeIdx));
169 return pCache->value;
173 * Get a copy of the descriptor string associated with the given prototype.
174 * The returned pointer must be free()ed by the caller.
176 char* dexProtoCopyMethodDescriptor(const DexProto* pProto) {
177 DexStringCache cache;
179 dexStringCacheInit(&cache);
180 return dexStringCacheAbandon(&cache,
181 dexProtoGetMethodDescriptor(pProto, &cache));
185 * Get the parameter descriptors for the given prototype. This is the
186 * concatenation of all the descriptors for all the parameters, in
187 * order, with no other adornment.
189 const char* dexProtoGetParameterDescriptors(const DexProto* pProto,
190 DexStringCache* pCache) {
191 DexParameterIterator iterator;
192 size_t length = 1; /* +1 for the terminating '\0' */
194 dexParameterIteratorInit(&iterator, pProto);
197 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
198 if (descriptor == NULL) {
202 length += strlen(descriptor);
205 dexParameterIteratorInit(&iterator, pProto);
207 dexStringCacheAlloc(pCache, length);
208 char *at = (char*) pCache->value;
211 const char* descriptor = dexParameterIteratorNextDescriptor(&iterator);
212 if (descriptor == NULL) {
216 strcpy(at, descriptor);
217 at += strlen(descriptor);
220 return pCache->value;
224 * Get the type descriptor for the return type of the given prototype.
226 const char* dexProtoGetReturnType(const DexProto* pProto) {
227 const DexProtoId* protoId = getProtoId(pProto);
228 return dexStringByTypeIdx(pProto->dexFile, protoId->returnTypeIdx);
232 * Get the parameter count of the given prototype.
234 size_t dexProtoGetParameterCount(const DexProto* pProto) {
235 const DexProtoId* protoId = getProtoId(pProto);
236 const DexTypeList* typeList =
237 dexGetProtoParameters(pProto->dexFile, protoId);
238 return (typeList == NULL) ? 0 : typeList->size;
242 * Compute the number of parameter words (u4 units) required by the
243 * given prototype. For example, if the method takes (int, long) and
244 * returns double, this would return 3 (one for the int, two for the
245 * long, and the return type isn't relevant).
247 int dexProtoComputeArgsSize(const DexProto* pProto) {
248 const char* shorty = dexProtoGetShorty(pProto);
251 /* Skip the return type. */
255 switch (*(shorty++)) {
273 * Common implementation for dexProtoCompare() and dexProtoCompareParameters().
275 static int protoCompare(const DexProto* pProto1, const DexProto* pProto2,
276 bool compareReturnType) {
278 if (pProto1 == pProto2) {
282 const DexFile* dexFile1 = pProto1->dexFile;
283 const DexProtoId* protoId1 = getProtoId(pProto1);
284 const DexTypeList* typeList1 =
285 dexGetProtoParameters(dexFile1, protoId1);
286 int paramCount1 = (typeList1 == NULL) ? 0 : typeList1->size;
288 const DexFile* dexFile2 = pProto2->dexFile;
289 const DexProtoId* protoId2 = getProtoId(pProto2);
290 const DexTypeList* typeList2 =
291 dexGetProtoParameters(dexFile2, protoId2);
292 int paramCount2 = (typeList2 == NULL) ? 0 : typeList2->size;
294 if (protoId1 == protoId2) {
299 // Compare return types.
301 if (compareReturnType) {
303 strcmp(dexStringByTypeIdx(dexFile1, protoId1->returnTypeIdx),
304 dexStringByTypeIdx(dexFile2, protoId2->returnTypeIdx));
311 // Compare parameters.
313 int minParam = (paramCount1 > paramCount2) ? paramCount2 : paramCount1;
316 for (i = 0; i < minParam; i++) {
317 u4 idx1 = dexTypeListGetIdx(typeList1, i);
318 u4 idx2 = dexTypeListGetIdx(typeList2, i);
320 strcmp(dexStringByTypeIdx(dexFile1, idx1),
321 dexStringByTypeIdx(dexFile2, idx2));
328 if (paramCount1 < paramCount2) {
330 } else if (paramCount1 > paramCount2) {
339 * Compare the two prototypes. The two prototypes are compared
340 * with the return type as the major order, then the first arguments,
341 * then second, etc. If two prototypes are identical except that one
342 * has extra arguments, then the shorter argument is considered the
343 * earlier one in sort order (similar to strcmp()).
345 int dexProtoCompare(const DexProto* pProto1, const DexProto* pProto2) {
346 return protoCompare(pProto1, pProto2, true);
350 * Compare the two prototypes. The two prototypes are compared
351 * with the first argument as the major order, then second, etc. If two
352 * prototypes are identical except that one has extra arguments, then the
353 * shorter argument is considered the earlier one in sort order (similar
356 int dexProtoCompareParameters(const DexProto* pProto1, const DexProto* pProto2){
357 return protoCompare(pProto1, pProto2, false);
362 * Helper for dexProtoCompareToDescriptor(), which gets the return type
363 * descriptor from a method descriptor string.
365 static const char* methodDescriptorReturnType(const char* descriptor) {
366 const char* result = strchr(descriptor, ')');
368 if (result == NULL) {
372 // The return type is the character just past the ')'.
377 * Helper for dexProtoCompareToDescriptor(), which indicates the end
378 * of an embedded argument type descriptor, which is also the
379 * beginning of the next argument type descriptor. Since this is for
380 * argument types, it doesn't accept 'V' as a valid type descriptor.
382 static const char* methodDescriptorNextType(const char* descriptor) {
383 // Skip any array references.
385 while (*descriptor == '[') {
389 switch (*descriptor) {
390 case 'B': case 'C': case 'D': case 'F':
391 case 'I': case 'J': case 'S': case 'Z': {
392 return descriptor + 1;
395 const char* result = strchr(descriptor + 1, ';');
396 if (result != NULL) {
397 // The type ends just past the ';'.
407 * Compare a prototype and a string method descriptor. The comparison
408 * is done as if the descriptor were converted to a prototype and compared
409 * with dexProtoCompare().
411 int dexProtoCompareToDescriptor(const DexProto* proto,
412 const char* descriptor) {
413 // First compare the return types.
415 int result = strcmp(dexProtoGetReturnType(proto),
416 methodDescriptorReturnType(descriptor));
422 // The return types match, so we have to check arguments.
424 DexParameterIterator iterator;
425 dexParameterIteratorInit(&iterator, proto);
428 assert (*descriptor == '(');
432 const char* protoDesc = dexParameterIteratorNextDescriptor(&iterator);
434 if (*descriptor == ')') {
435 // It's the end of the descriptor string.
436 if (protoDesc == NULL) {
437 // It's also the end of the prototype's arguments.
440 // The prototype still has more arguments.
445 if (protoDesc == NULL) {
447 * The prototype doesn't have arguments left, but the
448 * descriptor string does.
453 // Both prototype and descriptor have arguments. Compare them.
455 const char* nextDesc = methodDescriptorNextType(descriptor);
458 char c1 = *(protoDesc++);
459 char c2 = (descriptor < nextDesc) ? *(descriptor++) : '\0';
462 // This includes the case where the proto is shorter.
464 } else if (c1 > c2) {
465 // This includes the case where the desc is shorter.
467 } else if (c1 == '\0') {
468 // The two types are equal in length. (c2 necessarily == '\0'.)
474 * If we made it here, the two arguments matched, and
475 * descriptor == nextDesc.
482 * ===========================================================================
483 * Parameter Iterators
484 * ===========================================================================
488 * Initialize the given DexParameterIterator to be at the start of the
489 * parameters of the given prototype.
491 void dexParameterIteratorInit(DexParameterIterator* pIterator,
492 const DexProto* pProto) {
493 pIterator->proto = pProto;
494 pIterator->cursor = 0;
496 pIterator->parameters =
497 dexGetProtoParameters(pProto->dexFile, getProtoId(pProto));
498 pIterator->parameterCount = (pIterator->parameters == NULL) ? 0
499 : pIterator->parameters->size;
503 * Get the type_id index for the next parameter, if any. This returns
504 * kDexNoIndex if the last parameter has already been consumed.
506 u4 dexParameterIteratorNextIndex(DexParameterIterator* pIterator) {
507 int cursor = pIterator->cursor;
508 int parameterCount = pIterator->parameterCount;
510 if (cursor >= parameterCount) {
511 // The iteration is complete.
514 u4 idx = dexTypeListGetIdx(pIterator->parameters, cursor);
521 * Get the type descriptor for the next parameter, if any. This returns
522 * NULL if the last parameter has already been consumed.
524 const char* dexParameterIteratorNextDescriptor(
525 DexParameterIterator* pIterator) {
526 u4 idx = dexParameterIteratorNextIndex(pIterator);
528 if (idx == kDexNoIndex) {
532 return dexStringByTypeIdx(pIterator->proto->dexFile, idx);