/*
* 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.
*/
/*
* The VM wraps some additional data structures around the DexFile. These
* are defined here.
*/
#ifndef _DALVIK_DVMDEX
#define _DALVIK_DVMDEX
#include "libdex/DexFile.h"
/* extern */
struct ClassObject;
struct HashTable;
struct InstField;
struct Method;
struct StringObject;
/*
* Some additional VM data structures that are associated with the DEX file.
*/
typedef struct DvmDex {
/* pointer to the DexFile we're associated with */
DexFile* pDexFile;
/* clone of pDexFile->pHeader (it's used frequently enough) */
const DexHeader* pHeader;
/* interned strings; parallel to "stringIds" */
struct StringObject** pResStrings;
/* resolved classes; parallel to "typeIds" */
struct ClassObject** pResClasses;
/* resolved methods; parallel to "methodIds" */
struct Method** pResMethods;
/* resolved instance fields; parallel to "fieldIds" */
/* (this holds both InstField and StaticField) */
struct Field** pResFields;
/* interface method lookup cache */
struct AtomicCache* pInterfaceCache;
/* shared memory region with file contents */
MemMapping memMap;
} DvmDex;
/*
* Given a file descriptor for an open "optimized" DEX file, map it into
* memory and parse the contents.
*
* On success, returns 0 and sets "*ppDvmDex" to a newly-allocated DvmDex.
* On failure, returns a meaningful error code [currently just -1].
*/
int dvmDexFileOpenFromFd(int fd, DvmDex** ppDvmDex);
/*
* Open a partial DEX file. Only useful as part of the optimization process.
*/
int dvmDexFileOpenPartial(const void* addr, int len, DvmDex** ppDvmDex);
/*
* Free a DvmDex structure, along with any associated structures.
*/
void dvmDexFileFree(DvmDex* pDvmDex);
/*
* Change the 1- or 2-byte value at the specified address to a new value. If
* the location already has the new value, do nothing.
*
* This does not make any synchronization guarantees. The caller must
* ensure exclusivity vs. other callers.
*
* For the 2-byte call, the pointer should have 16-bit alignment.
*
* Returns "true" on success.
*/
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.
*/
INLINE struct StringObject* dvmDexGetResolvedString(const DvmDex* pDvmDex,
u4 stringIdx)
{
assert(stringIdx < pDvmDex->pHeader->stringIdsSize);
return pDvmDex->pResStrings[stringIdx];
}
INLINE struct ClassObject* dvmDexGetResolvedClass(const DvmDex* pDvmDex,
u4 classIdx)
{
assert(classIdx < pDvmDex->pHeader->typeIdsSize);
return pDvmDex->pResClasses[classIdx];
}
INLINE struct Method* dvmDexGetResolvedMethod(const DvmDex* pDvmDex,
u4 methodIdx)
{
assert(methodIdx < pDvmDex->pHeader->methodIdsSize);
return pDvmDex->pResMethods[methodIdx];
}
INLINE struct Field* dvmDexGetResolvedField(const DvmDex* pDvmDex,
u4 fieldIdx)
{
assert(fieldIdx < pDvmDex->pHeader->fieldIdsSize);
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)
{
assert(stringIdx < pDvmDex->pHeader->stringIdsSize);
pDvmDex->pResStrings[stringIdx] = str;
}
INLINE void dvmDexSetResolvedClass(DvmDex* pDvmDex, u4 classIdx,
struct ClassObject* clazz)
{
assert(classIdx < pDvmDex->pHeader->typeIdsSize);
pDvmDex->pResClasses[classIdx] = clazz;
}
INLINE void dvmDexSetResolvedMethod(DvmDex* pDvmDex, u4 methodIdx,
struct Method* method)
{
assert(methodIdx < pDvmDex->pHeader->methodIdsSize);
pDvmDex->pResMethods[methodIdx] = method;
}
INLINE void dvmDexSetResolvedField(DvmDex* pDvmDex, u4 fieldIdx,
struct Field* field)
{
assert(fieldIdx < pDvmDex->pHeader->fieldIdsSize);
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*/