summaryrefslogtreecommitdiff
path: root/vm/analysis/RegisterMap.h
blob: 7897d454bde4375b530774343b1adc8164964fed (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/*
 * 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 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*/