/* * Copyright (C) 2009 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. */ /* * Declaration of register map data structure and related functions. * * These structures should be treated as opaque through most of the VM. */ #ifndef _DALVIK_REGISTERMAP #define _DALVIK_REGISTERMAP #include "analysis/VerifySubs.h" #include "analysis/CodeVerify.h" /* * Format enumeration for RegisterMap data area. */ typedef enum RegisterMapFormat { kRegMapFormatUnknown = 0, kRegMapFormatNone, /* indicates no map data follows */ kRegMapFormatCompact8, /* compact layout, 8-bit addresses */ kRegMapFormatCompact16, /* compact layout, 16-bit addresses */ kRegMapFormatDifferential, /* compressed, differential encoding */ kRegMapFormatOnHeap = 0x80, /* bit flag, indicates allocation on heap */ } RegisterMapFormat; /* * This is a single variable-size structure. It may be allocated on the * heap or mapped out of a (post-dexopt) DEX file. * * 32-bit alignment of the structure is NOT guaranteed. This makes it a * little awkward to deal with as a structure; to avoid accidents we use * only byte types. Multi-byte values are little-endian. * * Size of (format==FormatNone): 1 byte * Size of (format==FormatCompact8): 4 + (1 + regWidth) * numEntries * Size of (format==FormatCompact16): 4 + (2 + regWidth) * numEntries */ struct RegisterMap { /* header */ u1 format; /* enum RegisterMapFormat; MUST be first entry */ u1 regWidth; /* bytes per register line, 1+ */ u1 numEntries[2]; /* number of entries */ /* raw data starts here; need not be aligned */ u1 data[1]; }; bool dvmRegisterMapStartup(void); void dvmRegisterMapShutdown(void); /* * Get the format. */ INLINE RegisterMapFormat dvmRegisterMapGetFormat(const RegisterMap* pMap) { return pMap->format & ~(kRegMapFormatOnHeap); } /* * Set the format. */ INLINE void dvmRegisterMapSetFormat(RegisterMap* pMap, RegisterMapFormat format) { pMap->format &= kRegMapFormatOnHeap; pMap->format |= format; } /* * Get the "on heap" flag. */ INLINE bool dvmRegisterMapGetOnHeap(const RegisterMap* pMap) { return (pMap->format & kRegMapFormatOnHeap) != 0; } /* * Get the register bit vector width, in bytes. */ INLINE u1 dvmRegisterMapGetRegWidth(const RegisterMap* pMap) { return pMap->regWidth; } /* * Set the register bit vector width, in bytes. */ INLINE void dvmRegisterMapSetRegWidth(RegisterMap* pMap, int regWidth) { pMap->regWidth = regWidth; } /* * Set the "on heap" flag. */ INLINE void dvmRegisterMapSetOnHeap(RegisterMap* pMap, bool val) { if (val) pMap->format |= kRegMapFormatOnHeap; else pMap->format &= ~(kRegMapFormatOnHeap); } /* * Get the number of entries in this map. */ INLINE u2 dvmRegisterMapGetNumEntries(const RegisterMap* pMap) { return pMap->numEntries[0] | (pMap->numEntries[1] << 8); } /* * Set the number of entries in this map. */ INLINE void dvmRegisterMapSetNumEntries(RegisterMap* pMap, u2 numEntries) { pMap->numEntries[0] = (u1) numEntries; pMap->numEntries[1] = numEntries >> 8; } /* * Retrieve the bit vector for the specified address. This is a pointer * to the bit data from an uncompressed map, or to a temporary copy of * data from a compressed map. * * The caller must call dvmReleaseRegisterMapLine() with the result. * * Returns NULL if not found. */ const u1* dvmRegisterMapGetLine(const RegisterMap* pMap, int addr); /* * Release "data". * * If "pMap" points to a compressed map from which we have expanded a * single line onto the heap, this will free "data"; otherwise, it does * nothing. * * TODO: decide if this is still a useful concept. */ INLINE void dvmReleaseRegisterMapLine(const RegisterMap* pMap, const u1* data) {} /* * A pool of register maps for methods associated with a single class. * * Each entry is a 4-byte method index followed by the 32-bit-aligned * RegisterMap. The size of the RegisterMap is determined by parsing * the map. The lack of an index reduces random access speed, but we * should be doing that rarely (during class load) and it saves space. * * These structures are 32-bit aligned. */ typedef struct RegisterMapMethodPool { u2 methodCount; /* chiefly used as a sanity check */ /* stream of per-method data starts here */ u4 methodData[1]; } RegisterMapMethodPool; /* * Header for the memory-mapped RegisterMap pool in the DEX file. * * The classDataOffset table provides offsets from the start of the * RegisterMapPool structure. There is one entry per class (including * interfaces, which can have static initializers). * * The offset points to a RegisterMapMethodPool. * * These structures are 32-bit aligned. */ typedef struct RegisterMapClassPool { u4 numClasses; /* offset table starts here, 32-bit aligned; offset==0 means no data */ u4 classDataOffset[1]; } RegisterMapClassPool; /* * Find the register maps for this class. (Used during class loading.) * If "pNumMaps" is non-NULL, it will return the number of maps in the set. * * Returns NULL if none is available. */ const void* dvmRegisterMapGetClassData(const DexFile* pDexFile, u4 classIdx, u4* pNumMaps); /* * Get the register map for the next method. "*pPtr" will be advanced past * the end of the map. (Used during class loading.) * * This should initially be called with the result from * dvmRegisterMapGetClassData(). */ const RegisterMap* dvmRegisterMapGetNext(const void** pPtr); /* * This holds some meta-data while we construct the set of register maps * for a DEX file. * * In particular, it keeps track of our temporary mmap region so we can * free it later. */ typedef struct RegisterMapBuilder { /* public */ void* data; size_t size; /* private */ MemMapping memMap; } RegisterMapBuilder; /* * Generate a register map set for all verified classes in "pDvmDex". */ RegisterMapBuilder* dvmGenerateRegisterMaps(DvmDex* pDvmDex); /* * Free the builder. */ void dvmFreeRegisterMapBuilder(RegisterMapBuilder* pBuilder); /* * Generate the register map for a previously-verified method. * * Returns a pointer to a newly-allocated RegisterMap. */ //RegisterMap* dvmGenerateRegisterMap(const Method* meth); /* * Various bits of data generated by the verifier, wrapped up in a package * for ease of use by the register map generator. */ typedef struct VerifierData { /* * The method we're working on. */ const Method* method; /* * Number of instructions in the method. */ int insnsSize; /* * Number of registers we track for each instruction. This is equal * to the method's declared "registersSize". (Does not include the * pending return value.) */ int insnRegCount; /* * Instruction widths and flags, one entry per code unit. */ InsnFlags* insnFlags; /* * Array of SRegType arrays, one entry per code unit. We only need * entries for code units that hold the start of an "interesting" * instruction. For register map generation, we're only interested * in GC points. */ RegType** addrRegs; } VerifierData; /* * Generate the register map for a method that has just been verified * (i.e. we're doing this as part of verification). * * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure. */ RegisterMap* dvmGenerateRegisterMapV(VerifierData* vdata); /* * Get the expanded form of the register map associated with the specified * method. May update method->registerMap, possibly freeing the previous * map. * * Returns NULL on failure (e.g. unable to expand map). * * NOTE: this function is not synchronized; external locking is mandatory. * (This is expected to be called at GC time.) */ const RegisterMap* dvmGetExpandedRegisterMap0(Method* method); INLINE const RegisterMap* dvmGetExpandedRegisterMap(Method* method) { const RegisterMap* curMap = method->registerMap; if (curMap == NULL) return NULL; RegisterMapFormat format = dvmRegisterMapGetFormat(curMap); if (format == kRegMapFormatCompact8 || format == kRegMapFormatCompact16) { return curMap; } else { return dvmGetExpandedRegisterMap0(method); } } /* dump stats gathered during register map creation process */ void dvmRegisterMapDumpStats(void); #endif /*_DALVIK_REGISTERMAP*/