summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDan Bornstein <danfuzz@android.com>2010-09-08 15:50:00 -0700
committerDan Bornstein <danfuzz@android.com>2010-09-09 11:34:19 -0700
commitd394371bd84bacc51e96e2d2eacb8549d9110b1e (patch)
tree92a09709a4d016139c0d275ece046f865a5bc036
parent2c81bdc3bb892d7d60855e14f61854f20a9f6cb8 (diff)
downloadandroid_dalvik-d394371bd84bacc51e96e2d2eacb8549d9110b1e.tar.gz
android_dalvik-d394371bd84bacc51e96e2d2eacb8549d9110b1e.tar.bz2
android_dalvik-d394371bd84bacc51e96e2d2eacb8549d9110b1e.zip
Remove the functionality in ReduceConstants.[ch].
It was a good experiment to try, but it was never made production-ready, and it doesn't look like it would be a net win at this point. We metaphorically pour out a beer in its honor. Change-Id: I7f6ac95f5b7c963df0a3015ed33595fa1a928636
-rw-r--r--dexdump/DexDump.c6
-rw-r--r--libdex/DexFile.h28
-rw-r--r--libdex/DexOptData.c155
-rw-r--r--vm/Dalvik.h1
-rw-r--r--vm/Dvm.mk4
-rw-r--r--vm/DvmDex.c14
-rw-r--r--vm/DvmDex.h178
-rw-r--r--vm/Init.c7
-rw-r--r--vm/analysis/DexPrepare.c26
-rw-r--r--vm/analysis/ReduceConstants.c1059
-rw-r--r--vm/analysis/ReduceConstants.h71
11 files changed, 3 insertions, 1546 deletions
diff --git a/dexdump/DexDump.c b/dexdump/DexDump.c
index 714a0f86c..636408afb 100644
--- a/dexdump/DexDump.c
+++ b/dexdump/DexDump.c
@@ -482,12 +482,6 @@ void dumpOptDirectory(const DexFile* pDexFile)
case kDexChunkRegisterMaps:
verboseStr = "register maps";
break;
- case kDexChunkReducingIndexMap:
- verboseStr = "'reducing' index map";
- break;
- case kDexChunkExpandingIndexMap:
- verboseStr = "'expanding' index map";
- break;
default:
verboseStr = "(unknown chunk type)";
break;
diff --git a/libdex/DexFile.h b/libdex/DexFile.h
index 279650f88..06dc8646f 100644
--- a/libdex/DexFile.h
+++ b/libdex/DexFile.h
@@ -167,9 +167,6 @@ enum {
kDexChunkClassLookup = 0x434c4b50, /* CLKP */
kDexChunkRegisterMaps = 0x524d4150, /* RMAP */
- kDexChunkReducingIndexMap = 0x5249584d, /* RIXM */
- kDexChunkExpandingIndexMap = 0x4549584d, /* EIXM */
-
kDexChunkEnd = 0x41454e44, /* AEND */
};
@@ -444,30 +441,6 @@ typedef struct DexClassLookup {
} DexClassLookup;
/*
- * Map constant pool indices from one form to another. Some or all of these
- * may be NULL.
- *
- * The map values are 16-bit unsigned values. If the values we map to
- * require a larger range, we omit the mapping for that category (which
- * requires that the lookup code recognize that the data will not be
- * there for all DEX files in all categories.)
- */
-typedef struct DexIndexMap {
- const u2* classMap; /* map, either expanding or reducing */
- u4 classFullCount; /* same as typeIdsSize */
- u4 classReducedCount; /* post-reduction count */
- const u2* methodMap;
- u4 methodFullCount;
- u4 methodReducedCount;
- const u2* fieldMap;
- u4 fieldFullCount;
- u4 fieldReducedCount;
- const u2* stringMap;
- u4 stringFullCount;
- u4 stringReducedCount;
-} DexIndexMap;
-
-/*
* Header added by DEX optimization pass. Values are always written in
* local byte and structure padding. The first field (magic + version)
* is guaranteed to be present and directly readable for all expected
@@ -523,7 +496,6 @@ typedef struct DexFile {
* included in the file.
*/
const DexClassLookup* pClassLookup;
- DexIndexMap indexMap;
const void* pRegisterMapPool; // RegisterMapClassPool
/* points to start of DEX file data */
diff --git a/libdex/DexOptData.c b/libdex/DexOptData.c
index 995b65529..10a4b5d29 100644
--- a/libdex/DexOptData.c
+++ b/libdex/DexOptData.c
@@ -45,130 +45,6 @@ u4 dexComputeOptChecksum(const DexOptHeader* pOptHeader)
return (u4) adler32(adler, start, end - start);
}
-/*
- * Parse out an index map entry, advancing "*pData" and reducing "*pSize".
- */
-static bool parseIndexMapEntry(const u1** pData, u4* pSize, bool expanding,
- u4* pFullCount, u4* pReducedCount, const u2** pMap)
-{
- const u4* wordPtr = (const u4*) *pData;
- u4 size = *pSize;
- u4 mapCount;
-
- if (expanding) {
- if (size < 4)
- return false;
- mapCount = *pReducedCount = *wordPtr++;
- *pFullCount = (u4) -1;
- size -= sizeof(u4);
- } else {
- if (size < 8)
- return false;
- mapCount = *pFullCount = *wordPtr++;
- *pReducedCount = *wordPtr++;
- size -= sizeof(u4) * 2;
- }
-
- u4 mapSize = mapCount * sizeof(u2);
-
- if (size < mapSize)
- return false;
- *pMap = (const u2*) wordPtr;
- size -= mapSize;
-
- /* advance the pointer */
- const u1* ptr = (const u1*) wordPtr;
- ptr += (mapSize + 3) & ~0x3;
-
- /* update pass-by-reference values */
- *pData = (const u1*) ptr;
- *pSize = size;
-
- return true;
-}
-
-/*
- * Set up some pointers into the mapped data.
- *
- * See analysis/ReduceConstants.c for the data layout description.
- */
-static bool parseIndexMap(DexFile* pDexFile, const u1* data, u4 size,
- bool expanding)
-{
- if (!parseIndexMapEntry(&data, &size, expanding,
- &pDexFile->indexMap.classFullCount,
- &pDexFile->indexMap.classReducedCount,
- &pDexFile->indexMap.classMap))
- {
- return false;
- }
-
- if (!parseIndexMapEntry(&data, &size, expanding,
- &pDexFile->indexMap.methodFullCount,
- &pDexFile->indexMap.methodReducedCount,
- &pDexFile->indexMap.methodMap))
- {
- return false;
- }
-
- if (!parseIndexMapEntry(&data, &size, expanding,
- &pDexFile->indexMap.fieldFullCount,
- &pDexFile->indexMap.fieldReducedCount,
- &pDexFile->indexMap.fieldMap))
- {
- return false;
- }
-
- if (!parseIndexMapEntry(&data, &size, expanding,
- &pDexFile->indexMap.stringFullCount,
- &pDexFile->indexMap.stringReducedCount,
- &pDexFile->indexMap.stringMap))
- {
- return false;
- }
-
- if (expanding) {
- /*
- * The map includes the "reduced" counts; pull the original counts
- * out of the DexFile so that code has a consistent source.
- */
- assert(pDexFile->indexMap.classFullCount == (u4) -1);
- assert(pDexFile->indexMap.methodFullCount == (u4) -1);
- assert(pDexFile->indexMap.fieldFullCount == (u4) -1);
- assert(pDexFile->indexMap.stringFullCount == (u4) -1);
-
-#if 0 // TODO: not available yet -- do later or just skip this
- pDexFile->indexMap.classFullCount =
- pDexFile->pHeader->typeIdsSize;
- pDexFile->indexMap.methodFullCount =
- pDexFile->pHeader->methodIdsSize;
- pDexFile->indexMap.fieldFullCount =
- pDexFile->pHeader->fieldIdsSize;
- pDexFile->indexMap.stringFullCount =
- pDexFile->pHeader->stringIdsSize;
-#endif
- }
-
- LOGI("Class : %u %u %u\n",
- pDexFile->indexMap.classFullCount,
- pDexFile->indexMap.classReducedCount,
- pDexFile->indexMap.classMap[0]);
- LOGI("Method: %u %u %u\n",
- pDexFile->indexMap.methodFullCount,
- pDexFile->indexMap.methodReducedCount,
- pDexFile->indexMap.methodMap[0]);
- LOGI("Field : %u %u %u\n",
- pDexFile->indexMap.fieldFullCount,
- pDexFile->indexMap.fieldReducedCount,
- pDexFile->indexMap.fieldMap[0]);
- LOGI("String: %u %u %u\n",
- pDexFile->indexMap.stringFullCount,
- pDexFile->indexMap.stringReducedCount,
- pDexFile->indexMap.stringMap[0]);
-
- return true;
-}
-
/* (documented in header file) */
bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile)
{
@@ -176,7 +52,6 @@ bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile)
const void* pOptEnd = data + length;
const u4* pOpt = pOptStart;
u4 optLength = (const u1*) pOptEnd - (const u1*) pOptStart;
- u4 indexMapType = 0;
/*
* Make sure the opt data start is in range and aligned. This may
@@ -233,22 +108,6 @@ bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile)
case kDexChunkClassLookup:
pDexFile->pClassLookup = (const DexClassLookup*) pOptData;
break;
- case kDexChunkReducingIndexMap:
- LOGI("+++ found reducing index map, size=%u\n", size);
- if (!parseIndexMap(pDexFile, pOptData, size, false)) {
- LOGE("Failed parsing reducing index map\n");
- return false;
- }
- indexMapType = *pOpt;
- break;
- case kDexChunkExpandingIndexMap:
- LOGI("+++ found expanding index map, size=%u\n", size);
- if (!parseIndexMap(pDexFile, pOptData, size, true)) {
- LOGE("Failed parsing expanding index map\n");
- return false;
- }
- indexMapType = *pOpt;
- break;
case kDexChunkRegisterMaps:
LOGV("+++ found register maps, size=%u\n", size);
pDexFile->pRegisterMapPool = pOptData;
@@ -265,19 +124,5 @@ bool dexParseOptData(const u1* data, size_t length, DexFile* pDexFile)
pOpt = pNextOpt;
}
-#if 0 // TODO: propagate expected map type from the VM through the API
- /*
- * If we're configured to expect an index map, and we don't find one,
- * reject this DEX so we'll regenerate it. Also, if we found an
- * "expanding" map but we're not configured to use it, we have to fail
- * because the constants aren't usable without translation.
- */
- if (indexMapType != expectedIndexMapType) {
- LOGW("Incompatible index map configuration: found 0x%04x, need %d\n",
- indexMapType, DVM_REDUCE_CONSTANTS);
- return false;
- }
-#endif
-
return true;
}
diff --git a/vm/Dalvik.h b/vm/Dalvik.h
index 6418bf2c7..5779b08b7 100644
--- a/vm/Dalvik.h
+++ b/vm/Dalvik.h
@@ -30,7 +30,6 @@
#include "libdex/DexFile.h"
#include "libdex/DexProto.h"
#include "libdex/ZipArchive.h"
-#include "analysis/ReduceConstants.h"
#include "DvmDex.h"
#include "RawDexFile.h"
#include "Sync.h"
diff --git a/vm/Dvm.mk b/vm/Dvm.mk
index d5f5e27d8..85fc59806 100644
--- a/vm/Dvm.mk
+++ b/vm/Dvm.mk
@@ -32,9 +32,6 @@ LOCAL_CFLAGS += -Wall -Wextra -Wno-unused-parameter
# Optional features. These may impact the size or performance of the VM.
#
-# 0=full cache, 1/2=reduced, 3=no cache
-LOCAL_CFLAGS += -DDVM_RESOLVER_CACHE=0
-
ifeq ($(WITH_DEADLOCK_PREDICTION),true)
LOCAL_CFLAGS += -DWITH_DEADLOCK_PREDICTION
WITH_MONITOR_TRACKING := true
@@ -142,7 +139,6 @@ LOCAL_SRC_FILES := \
analysis/DexPrepare.c \
analysis/DexVerify.c \
analysis/Optimize.c \
- analysis/ReduceConstants.c \
analysis/RegisterMap.c \
analysis/VerifySubs.c \
interp/Interp.c.arm \
diff --git a/vm/DvmDex.c b/vm/DvmDex.c
index 02dd758a4..94422b328 100644
--- a/vm/DvmDex.c
+++ b/vm/DvmDex.c
@@ -57,20 +57,6 @@ static DvmDex* allocateAuxStructures(DexFile* pDexFile)
methodCount = pHeader->methodIdsSize;
fieldCount = pHeader->fieldIdsSize;
-#if (DVM_RESOLVER_CACHE == DVM_RC_REDUCING) || \
- (DVM_RESOLVER_CACHE == DVM_RC_EXPANDING)
- if (pDexFile->indexMap.stringReducedCount > 0)
- stringCount = pDexFile->indexMap.stringReducedCount;
- if (pDexFile->indexMap.classReducedCount > 0)
- classCount = pDexFile->indexMap.classReducedCount;
- if (pDexFile->indexMap.methodReducedCount > 0)
- methodCount = pDexFile->indexMap.methodReducedCount;
- if (pDexFile->indexMap.fieldReducedCount > 0)
- fieldCount = pDexFile->indexMap.fieldReducedCount;
-#elif (DVM_RESOLVER_CACHE == DVM_RC_NO_CACHE)
- stringCount = classCount = methodCount = fieldCount = 0;
-#endif
-
pDvmDex->pResStrings = (struct StringObject**)
calloc(stringCount, sizeof(struct StringObject*));
diff --git a/vm/DvmDex.h b/vm/DvmDex.h
index 803be1f00..f36940b9a 100644
--- a/vm/DvmDex.h
+++ b/vm/DvmDex.h
@@ -100,9 +100,6 @@ bool dvmDexChangeDex1(DvmDex* pDvmDex, u1* addr, u1 newVal);
bool dvmDexChangeDex2(DvmDex* pDvmDex, u2* addr, u2 newVal);
-#if DVM_RESOLVER_CACHE == DVM_RC_DISABLED
-/* 1:1 mapping */
-
/*
* Return the requested item if it has been resolved, or NULL if it hasn't.
*/
@@ -160,179 +157,4 @@ INLINE void dvmDexSetResolvedField(DvmDex* pDvmDex, u4 fieldIdx,
pDvmDex->pResFields[fieldIdx] = field;
}
-#elif DVM_RESOLVER_CACHE == DVM_RC_REDUCING
-/* reduce request to fit in a less-than-full-size cache table */
-
-/*
- * Return the requested item if it has been resolved, or NULL if it hasn't.
- *
- * If we have a mapping table defined for this category, but there's no
- * entry for this index, we always return NULL. Otherwise, we return the
- * entry. (To regain some performance we may want to assume that the
- * table exists when compiled in this mode -- avoids a null check but
- * prevents us from switching back and forth without rebuilding the VM.)
- *
- * We could save an integer compare here by ensuring that map[kNoIndexMapping]
- * always evalutes to NULL (e.g. set kNoIndexMapping = 0).
- */
-INLINE struct StringObject* dvmDexGetResolvedString(const DvmDex* pDvmDex,
- u4 stringIdx)
-{
- const DexIndexMap* pIndexMap = &pDvmDex->pDexFile->indexMap;
-
- assert(stringIdx < pDvmDex->pHeader->stringIdsSize);
- if (pIndexMap->stringReducedCount > 0) {
- stringIdx = pIndexMap->stringMap[stringIdx];
- if (stringIdx == kNoIndexMapping)
- return NULL;
- }
- return pDvmDex->pResStrings[stringIdx];
-}
-INLINE struct ClassObject* dvmDexGetResolvedClass(const DvmDex* pDvmDex,
- u4 classIdx)
-{
- const DexIndexMap* pIndexMap = &pDvmDex->pDexFile->indexMap;
-
- assert(classIdx < pDvmDex->pHeader->typeIdsSize);
- if (pIndexMap->classReducedCount > 0) {
- classIdx = pIndexMap->classMap[classIdx];
- if (classIdx == kNoIndexMapping)
- return NULL;
- }
- return pDvmDex->pResClasses[classIdx];
-}
-INLINE struct Method* dvmDexGetResolvedMethod(const DvmDex* pDvmDex,
- u4 methodIdx)
-{
- const DexIndexMap* pIndexMap = &pDvmDex->pDexFile->indexMap;
-
- assert(methodIdx < pDvmDex->pHeader->methodIdsSize);
- if (pIndexMap->methodReducedCount > 0) {
- methodIdx = pIndexMap->methodMap[methodIdx];
- if (methodIdx == kNoIndexMapping)
- return NULL;
- }
- return pDvmDex->pResMethods[methodIdx];
-}
-INLINE struct Field* dvmDexGetResolvedField(const DvmDex* pDvmDex,
- u4 fieldIdx)
-{
- const DexIndexMap* pIndexMap = &pDvmDex->pDexFile->indexMap;
-
- assert(fieldIdx < pDvmDex->pHeader->fieldIdsSize);
- if (pIndexMap->fieldReducedCount > 0) {
- fieldIdx = pIndexMap->fieldMap[fieldIdx];
- if (fieldIdx == kNoIndexMapping)
- return NULL;
- }
- return pDvmDex->pResFields[fieldIdx];
-}
-
-/*
- * Update the resolved item table. Resolution always produces the same
- * result, so we're not worried about atomicity here.
- */
-INLINE void dvmDexSetResolvedString(DvmDex* pDvmDex, u4 stringIdx,
- struct StringObject* str)
-{
- const DexIndexMap* pIndexMap = &pDvmDex->pDexFile->indexMap;
- u4 newIdx;
-
- assert(stringIdx < pDvmDex->pHeader->stringIdsSize);
- if (pIndexMap->stringReducedCount > 0) {
- newIdx = pIndexMap->stringMap[stringIdx];
- if (newIdx != kNoIndexMapping)
- pDvmDex->pResStrings[newIdx] = str;
- }
-}
-INLINE void dvmDexSetResolvedClass(DvmDex* pDvmDex, u4 classIdx,
- struct ClassObject* clazz)
-{
- const DexIndexMap* pIndexMap = &pDvmDex->pDexFile->indexMap;
- u4 newIdx;
-
- assert(classIdx < pDvmDex->pHeader->typeIdsSize);
- if (pIndexMap->classReducedCount > 0) {
- newIdx = pIndexMap->classMap[classIdx];
- if (newIdx != kNoIndexMapping)
- pDvmDex->pResClasses[newIdx] = clazz;
- }
-}
-INLINE void dvmDexSetResolvedMethod(DvmDex* pDvmDex, u4 methodIdx,
- struct Method* method)
-{
- const DexIndexMap* pIndexMap = &pDvmDex->pDexFile->indexMap;
- u4 newIdx;
-
- assert(methodIdx < pDvmDex->pHeader->methodIdsSize);
- if (pIndexMap->methodReducedCount > 0) {
- newIdx = pIndexMap->methodMap[methodIdx];
- if (newIdx != kNoIndexMapping)
- pDvmDex->pResMethods[newIdx] = method;
- }
-}
-INLINE void dvmDexSetResolvedField(DvmDex* pDvmDex, u4 fieldIdx,
- struct Field* field)
-{
- const DexIndexMap* pIndexMap = &pDvmDex->pDexFile->indexMap;
- u4 newIdx;
-
- assert(fieldIdx < pDvmDex->pHeader->fieldIdsSize);
- if (pIndexMap->fieldReducedCount > 0) {
- newIdx = pIndexMap->fieldMap[fieldIdx];
- if (newIdx != kNoIndexMapping)
- pDvmDex->pResFields[newIdx] = field;
- }
-}
-
-#elif DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
-
-#error "not implemented" /* TODO */
-
-#elif DVM_RESOLVER_CACHE == DVM_RC_NO_CACHE
-
-/*
- * There's no cache, so we always return NULL.
- */
-INLINE struct StringObject* dvmDexGetResolvedString(const DvmDex* pDvmDex,
- u4 stringIdx)
-{
- return NULL;
-}
-INLINE struct ClassObject* dvmDexGetResolvedClass(const DvmDex* pDvmDex,
- u4 classIdx)
-{
- return NULL;
-}
-INLINE struct Method* dvmDexGetResolvedMethod(const DvmDex* pDvmDex,
- u4 methodIdx)
-{
- return NULL;
-}
-INLINE struct Field* dvmDexGetResolvedField(const DvmDex* pDvmDex,
- u4 fieldIdx)
-{
- return NULL;
-}
-
-/*
- * Update the resolved item table. There is no table, so do nothing.
- */
-INLINE void dvmDexSetResolvedString(DvmDex* pDvmDex, u4 stringIdx,
- struct StringObject* str)
-{}
-INLINE void dvmDexSetResolvedClass(DvmDex* pDvmDex, u4 classIdx,
- struct ClassObject* clazz)
-{}
-INLINE void dvmDexSetResolvedMethod(DvmDex* pDvmDex, u4 methodIdx,
- struct Method* method)
-{}
-INLINE void dvmDexSetResolvedField(DvmDex* pDvmDex, u4 fieldIdx,
- struct Field* field)
-{}
-
-#else
-#error "huh?"
-#endif /*DVM_RESOLVER_CACHE==N*/
-
#endif /*_DALVIK_DVMDEX*/
diff --git a/vm/Init.c b/vm/Init.c
index 81a385ae0..f5a8b3c96 100644
--- a/vm/Init.c
+++ b/vm/Init.c
@@ -181,13 +181,6 @@ static void dvmUsage(const char* progName)
#ifdef PROFILE_FIELD_ACCESS
" profile_field_access"
#endif
-#if DVM_RESOLVER_CACHE == DVM_RC_REDUCING
- " resolver_cache_reducing"
-#elif DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
- " resolver_cache_expanding"
-#elif DVM_RESOLVER_CACHE == DVM_RC_NO_CACHE
- " resolver_cache_disabled"
-#endif
#if defined(WITH_JIT)
" jit"
#endif
diff --git a/vm/analysis/DexPrepare.c b/vm/analysis/DexPrepare.c
index e43042f24..11fd7be74 100644
--- a/vm/analysis/DexPrepare.c
+++ b/vm/analysis/DexPrepare.c
@@ -52,7 +52,7 @@ static void verifyAndOptimizeClass(DexFile* pDexFile, ClassObject* clazz,
static void updateChecksum(u1* addr, int len, DexHeader* pHeader);
static int writeDependencies(int fd, u4 modWhen, u4 crc);
static bool writeOptData(int fd, const DexClassLookup* pClassLookup,\
- const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder);
+ const RegisterMapBuilder* pRegMapBuilder);
static bool computeFileChecksum(int fd, off_t start, size_t length, u4* pSum);
@@ -475,7 +475,6 @@ bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
const char* fileName, u4 modWhen, u4 crc, bool isBootstrap)
{
DexClassLookup* pClassLookup = NULL;
- IndexMapSet* pIndexMapSet = NULL;
RegisterMapBuilder* pRegMapBuilder = NULL;
u4 headerFlags = 0;
@@ -544,15 +543,6 @@ bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
success = false;
} else {
/*
- * If configured to do so, scan the instructions, looking
- * for ways to reduce the size of the resolved-constant table.
- * This is done post-optimization, across the instructions
- * in all methods in all classes (even the ones that failed
- * to load).
- */
- pIndexMapSet = dvmRewriteConstants(pDvmDex);
-
- /*
* If configured to do so, generate register map output
* for all verified classes. The register maps were
* generated during verification, and will now be serialized.
@@ -635,7 +625,7 @@ bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
/*
* Append any optimized pre-computed data structures.
*/
- if (!writeOptData(fd, pClassLookup, pIndexMapSet, pRegMapBuilder)) {
+ if (!writeOptData(fd, pClassLookup, pRegMapBuilder)) {
LOGW("Failed writing opt data\n");
goto bail;
}
@@ -680,7 +670,6 @@ bool dvmContinueOptimization(int fd, off_t dexOffset, long dexLength,
//dvmRegisterMapDumpStats();
bail:
- dvmFreeIndexMapSet(pIndexMapSet);
dvmFreeRegisterMapBuilder(pRegMapBuilder);
free(pClassLookup);
return result;
@@ -1365,7 +1354,7 @@ static bool writeChunk(int fd, u4 type, const void* data, size_t size)
* so it can be used directly when the file is mapped for reading.
*/
static bool writeOptData(int fd, const DexClassLookup* pClassLookup,
- const IndexMapSet* pIndexMapSet, const RegisterMapBuilder* pRegMapBuilder)
+ const RegisterMapBuilder* pRegMapBuilder)
{
/* pre-computed class lookup hash table */
if (!writeChunk(fd, (u4) kDexChunkClassLookup,
@@ -1374,15 +1363,6 @@ static bool writeOptData(int fd, const DexClassLookup* pClassLookup,
return false;
}
- /* remapped constants (optional) */
- if (pIndexMapSet != NULL) {
- if (!writeChunk(fd, pIndexMapSet->chunkType,
- pIndexMapSet->chunkData, pIndexMapSet->chunkDataLen))
- {
- return false;
- }
- }
-
/* register maps (optional) */
if (pRegMapBuilder != NULL) {
if (!writeChunk(fd, (u4) kDexChunkRegisterMaps,
diff --git a/vm/analysis/ReduceConstants.c b/vm/analysis/ReduceConstants.c
deleted file mode 100644
index 69657e3e4..000000000
--- a/vm/analysis/ReduceConstants.c
+++ /dev/null
@@ -1,1059 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * Compress the range of "constant pool" indexes in instructions and
- * annotations to lower runtime RAM footprint.
- *
- * NOTE: this is an incomplete experimental feature. Do not try to use it.
- */
-#include "Dalvik.h"
-#include "libdex/InstrUtils.h"
-#include "libdex/OptInvocation.h"
-#include "libdex/DexClass.h"
-
-/*
-Overview
-
-When a class, method, field, or string constant is referred to from
-Dalvik bytecode, the reference takes the form of an integer index value.
-This value indexes into an array of type_id_item, method_id_item,
-field_id_item, or string_id_item in the DEX file. The first three
-themselves contain (directly or indirectly) indexes to strings that the
-resolver uses to convert the instruction stream index into a pointer to
-the appropriate object or struct.
-
-For example, an invoke-virtual instruction needs to specify which method
-is to be invoked. The method constant indexes into the method_id_item
-array, each entry of which has indexes that specify the defining class
-(type_id_item), method name (string_id_item), and method prototype
-(proto_id_item). The type_id_item just holds an index to a string_id_item,
-which holds the file offset to the string with the class name. The VM
-finds the class by name, then searches through the class' table of virtual
-methods to find one with a matching name and prototype.
-
-This process is fairly expensive, so after the first time it completes
-successfully, the VM records that the method index resolved to a specific
-Method struct. On subsequent execution, the VM just pulls the Method ptr
-out of the resolved-methods array. A similar approach is used with
-the indexes for classes, fields, and string constants.
-
-The problem with this approach is that we need to have a "resolved" entry
-for every possible class, method, field, and string constant in every
-DEX file, even if some of those aren't used from code. The DEX string
-constant table has entries for method prototypes and class names that are
-never used by the code, and "public static final" fields often turn into
-immediate constants. The resolution table entries are only 4 bytes each,
-but there are roughly 200,000 of them in the bootstrap classes alone.
-
-DEX optimization removes many index references by replacing virtual method
-indexes with vtable offsets and instance field indexes with byte offsets.
-In the earlier example, the method would be resolved at "dexopt" time, and
-the instruction rewritten as invoke-virtual-quick with the vtable offset.
-
-(There are comparatively few classes compared to other constant pool
-entries, and a much higher percentage (typically 60-70%) are used. The
-biggest gains come from the string pool.)
-
-Using the resolved-entity tables provides a substantial performance
-improvement, but results in applications allocating 1MB+ of tables that
-are 70% unused. The used and unused entries are freely intermixed,
-preventing effective sharing with the zygote process, and resulting in
-large numbers of private/dirty pages on the native heap as the tables
-populate on first use.
-
-The trick is to reduce the memory usage without decreasing performance.
-Using smaller resolved-entity tables can actually give us a speed boost,
-because we'll have a smaller "live" set of pages and make more effective
-use of the data cache.
-
-
-The approach we're going to use is to determine the set of indexes that
-could potentially be resolved, generate a mapping from the minimal set to
-the full set, and append the mapping to the DEX file. This is done at
-"dexopt" time, because we need to keep the changes in shared/read-only
-pages or we'll lose the benefits of doing the work.
-
-There are two ways to create and use the new mapping:
-
- (1) Write the entire full->minimal mapping to the ".odex" file. On every
- instruction that uses an index, use the mapping to determine the
- "compressed" constant value, and then use that to index into the
- resolved-entity tables on the heap. The instruction stream is unchanged,
- and the resolver can easily tell if a given index is cacheable.
-
- (2) Write the inverse miminal->full mapping to the ".odex" file, and
- rewrite the constants in the instruction stream. The interpreter is
- unchanged, and the resolver code uses the mapping to find the original
- data in the DEX.
-
-Approach #1 is easier and safer to implement, but it requires a table
-lookup every time we execute an instruction that includes a constant
-pool reference. This causes an unacceptable performance hit, chiefly
-because we're hitting semi-random memory pages and hosing the data cache.
-This is mitigated somewhat by DEX optimizations that replace the constant
-with a vtable index or field byte offset. Approach #1 also requires
-a larger map table, increasing the size of the DEX on disk. One nice
-property of approach #1 is that most of the DEX file is unmodified,
-so use of the mapping is a runtime decision.
-
-Approach #2 is preferred for performance reasons.
-
-
-The class/method/field/string resolver code has to handle indices from
-three sources: interpreted instructions, annotations, and exception
-"catch" lists. Sometimes these occur indirectly, e.g. we need to resolve
-the declaring class associated with fields and methods when the latter
-two are themselves resolved. Parsing and rewriting instructions is fairly
-straightforward, but annotations use a complex format with variable-width
-index values.
-
-We can safely rewrite index values in annotations if we guarantee that the
-new value is smaller than the original. This implies a two-pass approach:
-the first determines the set of indexes actually used, the second does the
-rewrite. Doing the rewrite in a single pass would be much harder.
-
-Instances of the "original" indices will still be found in the file; if
-we try to be all-inclusive we will include some stuff that doesn't need
-to be there (e.g. we don't generally need to cache the class name string
-index result, since once we have the class resolved we don't need to look
-it up by name through the resolver again). There is some potential for
-performance improvement by caching more than we strictly need, but we can
-afford to give up a little performance during class loading if it allows
-us to regain some memory.
-
-For safety and debugging, it's useful to distinguish the "compressed"
-constants in some way, e.g. setting the high bit when we rewrite them.
-In practice we don't have any free bits: indexes are usually 16-bit
-values, and we have more than 32,767 string constants in at least one of
-our core DEX files. Also, this does not work with constants embedded in
-annotations, because of the variable-width encoding.
-
-We should be safe if we can establish a clear distinction between sources
-of "original" and "compressed" indices. If the values get crossed up we
-can end up with elusive bugs. The easiest approach is to declare that
-only indices pulled from certain locations (the instruction stream and/or
-annotations) are compressed. This prevents us from adding indices in
-arbitrary locations to the compressed set, but should allow a reasonably
-robust implementation.
-
-
-Further implementation thoughts:
-
- - We don't have to do annotations in the first pass. At heart the
- resolved entity cache is a performance optimization, not necessary for
- correctness, and we're not making annotation performance a priority
- at this stage.
- - The most important "fast path" is instruction processing. Everything
- else can do additional work without having a measurable impact.
- However...
- - We need to keep an eye on uncached resolves to ensure that we haven't
- introduced noticeable performance losses. In particular, the use of
- runtime annotations with string constants may suffer if we don't include
- annotation rewriting in the solution.
- - We can have separate resolver functions for "original" and "compressed"
- indices. This way we don't have to add a flag argument to the resolver
- functions (which would require passing an additional parameter in from
- the interpreter).
- - The VM spec has some specific things to say about string constant
- equality and interning. Index compression should have no effect on
- that; we just change how long it takes to find the interned string in
- certain circumstances. The impact can be mitigated somewhat by
- improving the performance of the interned string table code.
- - This can make e.g. method resolution slower. The method_id_item has
- an index to a method name string, and we will no longer cache the
- result of resolving that string. This impacts resolution of any method
- with the same name as a previously-resolved method.
- - We may need to tweak the tools, particularly "dexdump", to show the
- translated values.
- - We can use 16-bit values in the mapping table, since we should have
- fewer than 2^16 remapped entries. If we overflow we can skip the remap
- for that table or for the entire DEX file. The resolver will need to
- check for the existence of the table to determine whether or not entries
- must be remapped. The cost of the extra check is acceptable for
- approach #2, since it's only at resolve time, but may be undesirable
- for approach #1.
-*/
-/*
-Output Formats
-
-There are two possible output formats, from which we choose based on how
-we plan to take advantage of the remapped constants. At most one of these
-will appear in the DEX.
-
-NOTE: if EIXM appears in the DEX, the VM *must* be configured with
-DVM_RESOLVER_CACHE=DVM_RC_EXPANDING (2). Otherwise the constants we
-pull from the instruction stream will be wrong and we will fail quickly.
-
-For approach #1: map from original indices to the reduced set.
-
- This includes the four "mapToNew" tables.
-
- Format (RIXM):
- u4 classCount // #of entries in classMap[]; == typeIdsSize
- u4 reducedClassCount // #of entries in remapped table (for alloc)
- u2 classMap[]
- u4 methodCount
- u4 reducedMethodCount
- u2 methodMap[]
- u4 fieldCount
- u4 reducedFieldCount
- u2 fieldMap[]
- u4 stringCount
- u4 reducedStringCount
- u2 stringMap[]
-
-For approach #2: map from the reduced set back to the originals.
-
- This includes the four "mapToOld" tables.
-
- Format (EIXM):
- u4 classCount // #of entries in classMap[]; post-reduction
- u2 classMap[]
- u4 methodCount
- u2 methodMap[]
- u4 fieldCount
- u2 fieldMap[]
- u4 stringCount
- u2 stringMap[]
-
-The arrays are padded so that the "count" values are always aligned on
-32-bit boundaries. All multi-byte values are in native host order.
-*/
-
-
-/*
- * Gather results from the post-optimization instruction scan.
- */
-typedef struct ScanResults {
- /* output */
- BitVector* usedClasses;
- BitVector* usedMethods;
- BitVector* usedFields;
- BitVector* usedStrings;
-} ScanResults;
-
-/* prototype for the for-all-methods function */
-typedef void (AllMethodsFunc)(DexFile* pDexFile, const char* classDescriptor,
- DexMethod* pDexMethod, void* arg);
-
-
-/*
- * Free scan results.
- */
-static void freeScanResults(ScanResults* pResults)
-{
- if (pResults == NULL)
- return;
-
- dvmFreeBitVector(pResults->usedClasses);
- dvmFreeBitVector(pResults->usedMethods);
- dvmFreeBitVector(pResults->usedFields);
- dvmFreeBitVector(pResults->usedStrings);
- free(pResults);
-}
-
-/*
- * Allocate storage for the results of the instruction scan.
- */
-static ScanResults* allocScanResults(const DexFile* pDexFile)
-{
- ScanResults* pResults;
- const DexHeader* pHeader = pDexFile->pHeader;
-
- pResults = (ScanResults*) calloc(1, sizeof(ScanResults));
- if (pResults == NULL)
- return NULL;
-
- pResults->usedClasses = dvmAllocBitVector(pHeader->typeIdsSize, false);
- pResults->usedMethods = dvmAllocBitVector(pHeader->methodIdsSize, false);
- pResults->usedFields = dvmAllocBitVector(pHeader->fieldIdsSize, false);
- pResults->usedStrings = dvmAllocBitVector(pHeader->stringIdsSize, false);
-
- if (pResults->usedClasses == NULL ||
- pResults->usedMethods == NULL ||
- pResults->usedFields == NULL ||
- pResults->usedStrings == NULL)
- {
- freeScanResults(pResults);
- return NULL;
- }
-
- return pResults;
-}
-
-/*
- * Call "func(method, arg)" on all methods in the specified class.
- *
- * Pass in a pointer to the class_data_item, positioned at the start of
- * the field data (i.e. just past the class data header).
- *
- * "classDescriptor" is for debug messages.
- */
-static void forAllMethodsInClass(DexFile* pDexFile, const u1** ppEncodedData,
- const DexClassDataHeader* pHeader, const char* classDescriptor,
- AllMethodsFunc func, void* arg)
-{
- int i;
-
- /*
- * Consume field data.
- */
- if (pHeader->staticFieldsSize != 0) {
- int count = (int) pHeader->staticFieldsSize;
- u4 lastIndex = 0;
- DexField field;
- for (i = 0; i < count; i++) {
- dexReadClassDataField(ppEncodedData, &field, &lastIndex);
- }
- }
- if (pHeader->instanceFieldsSize != 0) {
- int count = (int) pHeader->instanceFieldsSize;
- u4 lastIndex = 0;
- DexField field;
- for (i = 0; i < count; i++) {
- dexReadClassDataField(ppEncodedData, &field, &lastIndex);
- }
- }
-
- /*
- * Run through all methods.
- */
- if (pHeader->directMethodsSize != 0) {
- int count = (int) pHeader->directMethodsSize;
- u4 lastIndex = 0;
- DexMethod method;
-
- for (i = 0; i < count; i++) {
- dexReadClassDataMethod(ppEncodedData, &method, &lastIndex);
- (func)(pDexFile, classDescriptor, &method, arg);
- }
- }
- if (pHeader->virtualMethodsSize != 0) {
- int count = (int) pHeader->virtualMethodsSize;
- u4 lastIndex = 0;
- DexMethod method;
-
- for (i = 0; i < count; i++) {
- dexReadClassDataMethod(ppEncodedData, &method, &lastIndex);
- (func)(pDexFile, classDescriptor, &method, arg);
- }
- }
-}
-
-/*
- * Call "func(method, arg)" on all methods in all classes in DexFile.
- */
-static void forAllMethods(DexFile* pDexFile, AllMethodsFunc func, void* arg)
-{
- u4 count = pDexFile->pHeader->classDefsSize;
- u4 idx;
-
- for (idx = 0; idx < count; idx++) {
- const DexClassDef* pClassDef;
- DexClassDataHeader header;
- const u1* pEncodedData;
-
- pClassDef = dexGetClassDef(pDexFile, idx);
- pEncodedData = dexGetClassData(pDexFile, pClassDef);
-
- const char* classDescriptor;
- classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
-
- if (pEncodedData != NULL) {
- dexReadClassDataHeader(&pEncodedData, &header);
-
- forAllMethodsInClass(pDexFile, &pEncodedData, &header,
- classDescriptor, func, arg);
- } else {
- //printf("%s: no class data\n", classDescriptor);
- /* no class data, e.g. "marker interface" */
- }
- }
-}
-
-/*
- * Mark a class ID as referenced.
- */
-static void markClass(const u2* ptr, ScanResults* pResults)
-{
- u2 classIdx = *ptr;
- if (!dvmSetBit(pResults->usedClasses, classIdx)) {
- LOGE("Unable to mark class %d as in-use\n", classIdx);
- }
-}
-
-/*
- * Mark a method ID as referenced.
- */
-static void markMethod(const u2* ptr, ScanResults* pResults)
-{
- u2 methodIdx = *ptr;
- if (!dvmSetBit(pResults->usedMethods, methodIdx)) {
- LOGE("Unable to mark method %d as in-use\n", methodIdx);
- }
-}
-
-/*
- * Mark a field ID as referenced.
- */
-static void markField(const u2* ptr, ScanResults* pResults)
-{
- u2 fieldIdx = *ptr;
- if (!dvmSetBit(pResults->usedFields, fieldIdx)) {
- LOGE("Unable to mark field %d as in-use\n", fieldIdx);
- }
-}
-
-/*
- * Mark a string constant as referenced.
- */
-static void markString(const u2* ptr, ScanResults* pResults)
-{
- u2 stringIdx = *ptr;
- if (!dvmSetBit(pResults->usedStrings, stringIdx)) {
- LOGE("Unable to mark string %d as in-use\n", stringIdx);
- }
-}
-
-/*
- * Mark a "jumbo" string constant as referenced.
- */
-static void markJumboString(u2* ptr, ScanResults* pResults)
-{
- u4 stringIdx;
-
- /* it's in native byte order, but might not be 32-bit aligned */
- memcpy(&stringIdx, ptr, sizeof(u4));
- if (!dvmSetBit(pResults->usedStrings, stringIdx)) {
- LOGE("Unable to mark string %d as in-use\n", stringIdx);
- }
-}
-
-/*
- * Remap a value in the instruction stream.
- */
-static inline void updateValue(u2* ptr, const IndexMapSet* pIndexMapSet,
- int whichMap)
-{
- const IndexMap* pMap = &pIndexMapSet->map[whichMap];
- if (pMap != NULL) {
- u2 newIdx = pMap->mapToNew[*ptr];
- assert(newIdx != kNoIndexMapping);
- *ptr = newIdx;
- }
-}
-static void updateClass(u2* ptr, const IndexMapSet* pIndexMapSet)
-{
- updateValue(ptr, pIndexMapSet, kMapClasses);
-}
-static void updateMethod(u2* ptr, const IndexMapSet* pIndexMapSet)
-{
- updateValue(ptr, pIndexMapSet, kMapMethods);
-}
-static void updateField(u2* ptr, const IndexMapSet* pIndexMapSet)
-{
- updateValue(ptr, pIndexMapSet, kMapFields);
-}
-static void updateString(u2* ptr, const IndexMapSet* pIndexMapSet)
-{
- updateValue(ptr, pIndexMapSet, kMapStrings);
-}
-static void updateJumboString(u2* ptr, const IndexMapSet* pIndexMapSet)
-{
- u4 stringIdx;
- u4 newIdx;
-
- /* it's in native byte order, but might not be 32-bit aligned */
- memcpy(&stringIdx, ptr, sizeof(stringIdx));
-
- /* get new value */
- newIdx = pIndexMapSet->map[kMapStrings].mapToNew[*ptr];
- assert(newIdx != kNoIndexMapping);
-
- /* copy it out */
- memcpy(ptr, &newIdx, sizeof(newIdx));
-}
-
-/*
- * Run through an instructions stream, marking constants as we see them.
- *
- * If "pResults" is non-NULL, we populate "pResults" with what we find,
- * making no changes to the instruction stream.
- *
- * If "pIndexMapSet" is non-NULL, we rewrite the constants in the
- * instruction stream.
- */
-static void markUsedConstantsFromInsns(u2* insns, u4 insnsSize,
- ScanResults* pResults, const IndexMapSet* pIndexMapSet)
-{
- //printf(" %p %u units\n", insns, insnsSize);
-
- while (insnsSize > 0) {
- int width;
- u2* pConst = insns + 1;
-
- switch (*insns & 0xff) {
- case OP_IGET:
- case OP_IGET_WIDE:
- case OP_IGET_OBJECT:
- case OP_IGET_BOOLEAN:
- case OP_IGET_BYTE:
- case OP_IGET_CHAR:
- case OP_IGET_SHORT:
- case OP_IPUT:
- case OP_IPUT_WIDE:
- case OP_IPUT_OBJECT:
- case OP_IPUT_BOOLEAN:
- case OP_IPUT_BYTE:
- case OP_IPUT_CHAR:
- case OP_IPUT_SHORT:
- case OP_SGET:
- case OP_SGET_WIDE:
- case OP_SGET_OBJECT:
- case OP_SGET_BOOLEAN:
- case OP_SGET_BYTE:
- case OP_SGET_CHAR:
- case OP_SGET_SHORT:
- case OP_SPUT:
- case OP_SPUT_WIDE:
- case OP_SPUT_OBJECT:
- case OP_SPUT_BOOLEAN:
- case OP_SPUT_BYTE:
- case OP_SPUT_CHAR:
- case OP_SPUT_SHORT:
- /* instanceop vA, vB, field@CCCC */
- /* staticop vAA, field@BBBB */
- if (pResults != NULL)
- markField(pConst, pResults);
- else
- updateField(pConst, pIndexMapSet);
- break;
-
- case OP_CONST_STRING:
- /* const-string vAA, string@BBBB */
- if (pResults != NULL)
- markString(pConst, pResults);
- else
- updateString(pConst, pIndexMapSet);
- break;
-
- case OP_CONST_STRING_JUMBO:
- /* const-string/jumbo vAA, string@BBBBBBBB */
- if (pResults != NULL)
- markJumboString(pConst, pResults);
- else
- updateJumboString(pConst, pIndexMapSet);
- break;
-
- case OP_CONST_CLASS:
- case OP_CHECK_CAST:
- case OP_NEW_INSTANCE:
- case OP_FILLED_NEW_ARRAY_RANGE:
- case OP_INSTANCE_OF:
- case OP_NEW_ARRAY:
- case OP_FILLED_NEW_ARRAY:
- /* const-class vAA, type@BBBB */
- /* check-cast vAA, type@BBBB */
- /* new-instance vAA, type@BBBB */
- /* filled-new-array/range {vCCCC .. vNNNN}, type@BBBB */
- /* instance-of vA, vB, type@CCCC */
- /* new-array vA, vB, type@CCCC */
- /* filled-new-array {vD, vE, vF, vG, vA}, type@CCCC */
- if (pResults != NULL)
- markClass(pConst, pResults);
- else
- updateClass(pConst, pIndexMapSet);
- break;
-
- case OP_INVOKE_VIRTUAL:
- case OP_INVOKE_SUPER:
- case OP_INVOKE_DIRECT:
- case OP_INVOKE_STATIC:
- case OP_INVOKE_INTERFACE:
- case OP_INVOKE_VIRTUAL_RANGE:
- case OP_INVOKE_SUPER_RANGE:
- case OP_INVOKE_DIRECT_RANGE:
- case OP_INVOKE_STATIC_RANGE:
- case OP_INVOKE_INTERFACE_RANGE:
- /* invoke-kind {vD, vE, vF, vG, vA}, meth@CCCC */
- /* invoke-kind/range {vCCCC .. vNNNN}, meth@BBBB */
- if (pResults != NULL)
- markMethod(pConst, pResults);
- else
- updateMethod(pConst, pIndexMapSet);
- break;
-
- default:
- // ignore this instruction
- ;
- }
-
- width = dexGetInstrOrTableWidthAbs(gDvm.instrWidth, insns);
- assert(width > 0 && width <= (int)insnsSize);
-
- insns += width;
- insnsSize -= width;
- }
-}
-
-/*
- * This is an AllMethodsFunc implementation.
- *
- * Run through the instructions in this method, setting bits in the "pResults"
- * struct as we locate constants.
- */
-static void markUsedConstants(DexFile* pDexFile, const char* classDescriptor,
- DexMethod* pDexMethod, void* arg)
-{
- ScanResults* pResults = (ScanResults*) arg;
- const DexCode* pDexCode = dexGetCode(pDexFile, pDexMethod);
-
- if (false) {
- const DexMethodId* pMethodId;
- const char* methodName;
- pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
- methodName = dexStringById(pDexFile, pMethodId->nameIdx);
- printf(" %s.%s\n", classDescriptor, methodName);
- }
-
- if (pDexCode != NULL) {
- u2* insns = (u2*) pDexCode->insns;
- u4 insnsSize = pDexCode->insnsSize;
- markUsedConstantsFromInsns(insns, insnsSize, pResults, NULL);
- } else {
- //printf(" (no code)\n");
- }
-}
-
-/*
- * This is an AllMethodsFunc implementation.
- *
- * Run through the instructions in this method, altering the constants used.
- */
-#if DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
-static void updateUsedConstants(DexFile* pDexFile, const char* classDescriptor,
- DexMethod* pDexMethod, void* arg)
-{
- const IndexMapSet* pIndexMapSet = (const IndexMapSet*) arg;
- const DexCode* pDexCode = dexGetCode(pDexFile, pDexMethod);
-
- if (false) {
- const DexMethodId* pMethodId;
- const char* methodName;
- pMethodId = dexGetMethodId(pDexFile, pDexMethod->methodIdx);
- methodName = dexStringById(pDexFile, pMethodId->nameIdx);
- printf(" %s.%s\n", classDescriptor, methodName);
- }
-
- if (pDexCode != NULL) {
- u2* insns = (u2*) pDexCode->insns;
- u4 insnsSize = pDexCode->insnsSize;
- markUsedConstantsFromInsns(insns, insnsSize, NULL, pIndexMapSet);
- } else {
- //printf(" (no code)\n");
- }
-}
-#endif
-
-/*
- * Count up the bits and show a count.
- */
-static void showBitCount(const char* label, int setCount, int maxCount)
-{
- printf("%s: %d of %d (%.1f%% unused)\n", label, setCount, maxCount,
- ((maxCount - setCount) * 100.0f) / maxCount);
-}
-
-/*
- * Print some debug info.
- */
-static void summarizeResults(DvmDex* pDvmDex, ScanResults* pResults)
-{
- DexFile* pDexFile = pDvmDex->pDexFile;
-#if 0
- int i;
-
- for (i = 0; i < (int) pDvmDex->pDexFile->pHeader->typeIdsSize; i++) {
- const DexTypeId* pDexTypeId;
- const char* classDescr;
-
- pDexTypeId = dexGetTypeId(pDexFile, i);
- classDescr = dexStringById(pDexFile, pDexTypeId->descriptorIdx);
-
- if (dvmIsBitSet(pResults->usedStrings, i))
- printf("used : %04x '%s'\n", i, classDescr);
- else
- printf("unused: %04x '%s'\n", i, classDescr);
- }
-#endif
-#if 0
- for (i = 0; i < (int) pDvmDex->pDexFile->pHeader->methodIdsSize; i++) {
- const DexMethodId* pDexMethodId;
- const DexTypeId* pDexTypeId;
- const char* classDescr;
- const char* methodName;
-
- pDexMethodId = dexGetMethodId(pDexFile, i);
- methodName = dexStringById(pDexFile, pDexMethodId->nameIdx);
-
- pDexTypeId = dexGetTypeId(pDexFile, pDexMethodId->classIdx);
- classDescr = dexStringById(pDexFile, pDexTypeId->descriptorIdx);
- if (dvmIsBitSet(pResults->usedMethods, i))
- printf("used : %s.%s\n", classDescr, methodName);
- else
- printf("unused: %s.%s\n", classDescr, methodName);
- }
-#endif
-#if 0
- for (i = 0; i < (int) pDvmDex->pDexFile->pHeader->fieldIdsSize; i++) {
- const DexFieldId* pDexFieldId;
- const DexTypeId* pDexTypeId;
- const char* classDescr;
- const char* fieldName;
-
- pDexFieldId = dexGetFieldId(pDexFile, i);
- fieldName = dexStringById(pDexFile, pDexFieldId->nameIdx);
-
- pDexTypeId = dexGetTypeId(pDexFile, pDexFieldId->classIdx);
- classDescr = dexStringById(pDexFile, pDexTypeId->descriptorIdx);
- if (dvmIsBitSet(pResults->usedFields, i))
- printf("used : %s.%s\n", classDescr, fieldName);
- else
- printf("unused: %s.%s\n", classDescr, fieldName);
- }
-#endif
-#if 0
- for (i = 0; i < (int) pDvmDex->pDexFile->pHeader->stringIdsSize; i++) {
- const char* str;
-
- str = dexStringById(pDexFile, i);
-
- if (dvmIsBitSet(pResults->usedStrings, i))
- printf("used : %04x '%s'\n", i, str);
- else
- printf("unused: %04x '%s'\n", i, str);
- }
-#endif
-
- int totalMax, totalSet;
- int setCount;
-
- totalMax = totalSet = 0;
-
- setCount = dvmCountSetBits(pResults->usedClasses);
- showBitCount("classes", setCount, pDexFile->pHeader->typeIdsSize);
- totalSet += setCount;
- totalMax += pDexFile->pHeader->typeIdsSize;
-
- setCount = dvmCountSetBits(pResults->usedMethods);
- showBitCount("methods", setCount, pDexFile->pHeader->methodIdsSize);
- totalSet += setCount;
- totalMax += pDexFile->pHeader->methodIdsSize;
-
- setCount = dvmCountSetBits(pResults->usedFields);
- showBitCount("fields", setCount, pDexFile->pHeader->fieldIdsSize);
- totalSet += setCount;
- totalMax += pDexFile->pHeader->fieldIdsSize;
-
- setCount = dvmCountSetBits(pResults->usedStrings);
- showBitCount("strings", setCount, pDexFile->pHeader->stringIdsSize);
- totalSet += setCount;
- totalMax += pDexFile->pHeader->stringIdsSize;
-
- printf("TOTAL %d of %d (%.1f%% unused -- %.1fK)\n", totalSet, totalMax,
- ((totalMax - totalSet) * 100.0f) / totalMax,
- (totalMax - totalSet) / 256.0f);
-}
-
-/*
- * Fill out an index map set entry.
- *
- * If we can't fit the map into our base type, we don't create the map.
- *
- * Returns "false" if allocation fails.
- */
-static bool constructIndexMap(int totalCount, const BitVector* pBits,
- IndexMap* pMap)
-{
- const int kMaxIndex = 65534; // 65535, a/k/a -1, is special
- int setCount;
-
- setCount = dvmCountSetBits(pBits);
- if (setCount < 0 || setCount > kMaxIndex)
- return true;
-
- u2* mapToOld = (u2*) malloc(setCount * sizeof(u2));
- u2* mapToNew = (u2*) malloc(totalCount * sizeof(u2));
- if (mapToOld == NULL || mapToNew == NULL) {
- free(mapToOld);
- free(mapToNew);
- return false;
- }
-
- /* fill in both arrays */
- int entry, idx = 0;
- for (entry = 0; entry < totalCount; entry++) {
- if (dvmIsBitSet(pBits, entry)) {
- mapToNew[entry] = idx;
- mapToOld[idx] = entry;
- idx++;
- } else {
- mapToNew[entry] = kNoIndexMapping;
- }
- }
-
- if (idx != setCount) {
- LOGE("GLITCH: idx=%d setCount=%d\n", idx, setCount);
- dvmAbort();
- }
-
- /* success */
- pMap->mapToOld = mapToOld;
- pMap->mapToNew = mapToNew;
- pMap->origCount = totalCount;
- pMap->newCount = setCount;
-
- return true;
-}
-
-/*
- * Construct a "reducing" chunk, with maps that convert the constants in
- * instructions to their reduced value for the cache lookup.
- */
-static bool constructReducingDataChunk(IndexMapSet* pIndexMapSet)
-{
- int chunkLen = 0;
- int i;
-
- pIndexMapSet->chunkType = kDexChunkReducingIndexMap;
-
- /*
- * Compute space requirements and allocate storage.
- */
- for (i = 0; i < kNumIndexMaps; i++) {
- /* space for the "original" count */
- chunkLen += sizeof(u4);
-
- /* space for the "reduced" count */
- chunkLen += sizeof(u4);
-
- /* add data length, round up to 32-bit boundary */
- chunkLen += pIndexMapSet->map[i].origCount * sizeof(u2);
- chunkLen = (chunkLen + 3) & ~3;
- }
-
- pIndexMapSet->chunkDataLen = chunkLen;
- pIndexMapSet->chunkData = (u1*) calloc(1, chunkLen);
- if (pIndexMapSet->chunkData == NULL)
- return false;
-
- /*
- * Copy the data in.
- */
- u1* ptr = pIndexMapSet->chunkData;
- for (i = 0; i < kNumIndexMaps; i++) {
- u4* wordPtr = (u4*) ptr;
- int dataLen = pIndexMapSet->map[i].origCount * sizeof(u2);
-
- *wordPtr++ = pIndexMapSet->map[i].origCount;
- *wordPtr++ = pIndexMapSet->map[i].newCount;
- if (dataLen != 0)
- memcpy(wordPtr, pIndexMapSet->map[i].mapToNew, dataLen);
-
- /* advance pointer, maintaining 32-bit alignment */
- ptr = ((u1*) wordPtr) + dataLen;
- ptr = (u1*) (((int) ptr + 3) & ~3);
- }
-
- if (ptr - (u1*) pIndexMapSet->chunkData != chunkLen) {
- LOGE("GLITCH: expected len=%d, actual=%d\n",
- chunkLen, ptr - (u1*) pIndexMapSet->chunkData);
- dvmAbort();
- }
-
- return true;
-}
-
-/*
- * Construct an "expanding" chunk, with maps that convert instructions
- * with reduced constants back to their full original values.
- */
-#if DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
-static bool constructExpandingDataChunk(IndexMapSet* pIndexMapSet)
-{
- int chunkLen = 0;
- int i;
-
- pIndexMapSet->chunkType = kDexChunkExpandingIndexMap;
-
- /*
- * Compute space requirements and allocate storage.
- */
- for (i = 0; i < kNumIndexMaps; i++) {
- /* space for the length word */
- chunkLen += sizeof(u4);
-
- /* add data length, round up to 32-bit boundary */
- chunkLen += pIndexMapSet->map[i].newCount * sizeof(u2);
- chunkLen = (chunkLen + 3) & ~3;
- }
-
- pIndexMapSet->chunkDataLen = chunkLen;
- pIndexMapSet->chunkData = (u1*) calloc(1, chunkLen);
- if (pIndexMapSet->chunkData == NULL)
- return false;
-
- /*
- * Copy the data in.
- */
- u1* ptr = pIndexMapSet->chunkData;
- for (i = 0; i < kNumIndexMaps; i++) {
- u4* wordPtr = (u4*) ptr;
- int dataLen = pIndexMapSet->map[i].newCount * sizeof(u2);
-
- *wordPtr++ = pIndexMapSet->map[i].newCount;
- if (dataLen != 0)
- memcpy(wordPtr, pIndexMapSet->map[i].mapToOld, dataLen);
-
- /* advance pointer, maintaining 32-bit alignment */
- ptr = ((u1*) wordPtr) + dataLen;
- ptr = (u1*) (((int) ptr + 3) & ~3);
- }
-
- if (ptr - (u1*) pIndexMapSet->chunkData != chunkLen) {
- LOGE("GLITCH: expected len=%d, actual=%d\n",
- chunkLen, ptr - (u1*) pIndexMapSet->chunkData);
- dvmAbort();
- }
-
- return true;
-}
-#endif
-
-/*
- * Construct the "chunk" of data that will be appended to the optimized DEX
- * file.
- */
-static bool constructDataChunk(IndexMapSet* pIndexMapSet)
-{
- assert(sizeof(pIndexMapSet->map[0].mapToOld[0]) == sizeof(u2));
- assert(sizeof(pIndexMapSet->map[0].mapToNew[0]) == sizeof(u2));
-
-#if DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
- return constructExpandingDataChunk(pIndexMapSet);
-#else
- return constructReducingDataChunk(pIndexMapSet);
-#endif
-}
-
-/*
- * Allocate storage to hold the maps.
- */
-static IndexMapSet* createIndexMapSet(const DexFile* pDexFile,
- ScanResults* pResults)
-{
- IndexMapSet* pIndexMapSet;
- bool okay = true;
-
- pIndexMapSet = calloc(1, sizeof(*pIndexMapSet));
- if (pIndexMapSet == NULL)
- return NULL;
-
- okay = okay && constructIndexMap(pDexFile->pHeader->typeIdsSize,
- pResults->usedClasses, &pIndexMapSet->map[kMapClasses]);
- okay = okay && constructIndexMap(pDexFile->pHeader->methodIdsSize,
- pResults->usedMethods, &pIndexMapSet->map[kMapMethods]);
- okay = okay && constructIndexMap(pDexFile->pHeader->fieldIdsSize,
- pResults->usedFields, &pIndexMapSet->map[kMapFields]);
- okay = okay && constructIndexMap(pDexFile->pHeader->stringIdsSize,
- pResults->usedStrings, &pIndexMapSet->map[kMapStrings]);
-
- LOGVV("Constr: %d %d %d %d\n",
- pIndexMapSet->map[kMapClasses].mapToOld[0],
- pIndexMapSet->map[kMapMethods].mapToOld[0],
- pIndexMapSet->map[kMapFields].mapToOld[0],
- pIndexMapSet->map[kMapStrings].mapToOld[0]);
-
- okay = okay && constructDataChunk(pIndexMapSet);
-
- if (!okay) {
- dvmFreeIndexMapSet(pIndexMapSet);
- return NULL;
- }
-
- return pIndexMapSet;
-}
-
-/*
- * Free map storage.
- *
- * "pIndexMapSet" may be incomplete.
- */
-void dvmFreeIndexMapSet(IndexMapSet* pIndexMapSet)
-{
- int i;
-
- if (pIndexMapSet == NULL)
- return;
-
- for (i = 0; i < kNumIndexMaps; i++) {
- free(pIndexMapSet->map[i].mapToOld);
- free(pIndexMapSet->map[i].mapToNew);
- }
- free(pIndexMapSet->chunkData);
- free(pIndexMapSet);
-}
-
-/*
- * Rewrite constant indexes to reduce heap requirements.
- */
-IndexMapSet* dvmRewriteConstants(DvmDex* pDvmDex)
-{
-#if (DVM_RESOLVER_CACHE != DVM_RC_REDUCING) && \
- (DVM_RESOLVER_CACHE != DVM_RC_EXPANDING)
- /* nothing to do */
- return NULL;
-#endif
-
- /*
- * We're looking for instructions that use "constant pool" entries for
- * classes, methods, fields, and strings. Many field and method entries
- * are optimized away, and many string constants are never accessed from
- * code or annotations.
- */
- ScanResults* pResults = allocScanResults(pDvmDex->pDexFile);
- forAllMethods(pDvmDex->pDexFile, markUsedConstants, pResults);
-
- summarizeResults(pDvmDex, pResults);
-
- /*
- * Allocate and populate the index maps.
- */
- IndexMapSet* pIndexMapSet = createIndexMapSet(pDvmDex->pDexFile, pResults);
-#if DVM_RESOLVER_CACHE == DVM_RC_EXPANDING
- if (pIndexMapSet != NULL) {
- /*
- * Rewrite the constants to use the reduced set.
- */
- forAllMethods(pDvmDex->pDexFile, updateUsedConstants, pIndexMapSet);
- }
-#endif
-
- freeScanResults(pResults);
-
- return pIndexMapSet;
-}
diff --git a/vm/analysis/ReduceConstants.h b/vm/analysis/ReduceConstants.h
deleted file mode 100644
index 342e12531..000000000
--- a/vm/analysis/ReduceConstants.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-/*
- * DEX constant-reduction declarations.
- */
-#ifndef _DALVIK_REDUCECONSTANTS
-#define _DALVIK_REDUCECONSTANTS
-
-#define DVM_RC_DISABLED 0 /* no reduction, 1:1 map */
-#define DVM_RC_REDUCING 1 /* normal constants, reduced lookup table */
-#define DVM_RC_EXPANDING 2 /* reduced constants, expanded on resolve */
-#define DVM_RC_NO_CACHE 3 /* disable the cache (reduce to zero) */
-
-enum {
- kMapClasses = 0,
- kMapMethods = 1,
- kMapFields = 2,
- kMapStrings = 3,
-
- kNumIndexMaps
-};
-
-struct DvmDex;
-
-#define kNoIndexMapping ((u2) -1)
-
-/*
- * Map indices back to the original.
- */
-typedef struct IndexMap {
- int origCount; /* original size; describes range of entries in map */
- int newCount; /* reduced size */
- u2* mapToNew; /* sparse map, from "orig" to "new" */
- u2* mapToOld; /* dense map, from "new" back to "orig" */
-} IndexMap;
-typedef struct IndexMapSet {
- /* maps for the different sections */
- IndexMap map[kNumIndexMaps];
-
- /* data stream that gets appended to the optimized DEX file */
- u4 chunkType;
- int chunkDataLen;
- u1* chunkData;
-} IndexMapSet;
-
-/*
- * Constant pool compaction.
- *
- * The caller is responsible for freeing the returned structure by
- * calling dvmFreeIndexMap().
- */
-IndexMapSet* dvmRewriteConstants(struct DvmDex* pDvmDex);
-
-/* free an index map set */
-void dvmFreeIndexMapSet(IndexMapSet* indexMapSet);
-
-#endif /*_DALVIK_REDUCECONSTANTS*/