1f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copyright (C) 2009 The Android Open Source Project
3f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
4f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
5f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * you may not use this file except in compliance with the License.
6f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * You may obtain a copy of the License at
7f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
8f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
9f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
10f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
12f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * See the License for the specific language governing permissions and
14f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * limitations under the License.
15f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
16f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
17f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
18f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This code generate "register maps" for Dalvik bytecode.  In a stack-based
19f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * VM we might call these "stack maps".  They are used to increase the
20f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * precision in the garbage collector when scanning references in the
21f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * interpreter thread stacks.
22f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
23f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "Dalvik.h"
241813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro#include "UniquePtr.h"
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "analysis/CodeVerify.h"
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "analysis/RegisterMap.h"
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "libdex/DexCatch.h"
28f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "libdex/InstrUtils.h"
29d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden#include "libdex/Leb128.h"
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stddef.h>
32f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
331d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/* double-check the compression */
34a66a01ad2a9e5c6aefc93d12a5c18d6bba570a3eAndy McFadden#define REGISTER_MAP_VERIFY     false
351d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
361d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/* verbose logging */
371d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden#define REGISTER_MAP_VERBOSE    false
381d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
39e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro//#define REGISTER_MAP_STATS
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// fwd
42f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void outputTypeVector(const RegType* regs, int insnRegCount, u1* data);
43f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool verifyMap(VerifierData* vdata, const RegisterMap* pMap);
44d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2);
45d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
46e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro#ifdef REGISTER_MAP_STATS
4799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic void computeMapStats(RegisterMap* pMap, const Method* method);
48e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro#endif
491d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFaddenstatic RegisterMap* compressMapDifferential(const RegisterMap* pMap,\
50d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const Method* meth);
51d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic RegisterMap* uncompressMapDifferential(const RegisterMap* pMap);
5299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
5399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
5499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Generate some statistics on the register maps we create and use.
5699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
5799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#define kMaxGcPointGap      50
5899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#define kUpdatePosnMinRegs  24
5999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#define kNumUpdatePosns     8
6099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#define kMaxDiffBits        20
61d862faa2ceae186da5518607505eb942d634ced9Carl Shapirostruct MapStats {
6299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
6399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Buckets measuring the distance between GC points.  This tells us how
6499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * many bits we need to encode the advancing program counter.  We ignore
6599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * some of the "long tail" entries.
6699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
6799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int gcPointGap[kMaxGcPointGap];
6899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
6999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
7099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Number of gaps.  Equal to (number of gcPoints - number of methods),
7199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * since the computation isn't including the initial gap.
7299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
7399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int gcGapCount;
7499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
7599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
7699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Number of gaps.
7799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
7899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int totalGcPointCount;
7999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
8099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
8199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * For larger methods (>= 24 registers), measure in which octant register
8299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * updates occur.  This should help us understand whether register
8399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * changes tend to cluster in the low regs even for large methods.
8499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
8599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int updatePosn[kNumUpdatePosns];
8699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
8799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
8899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * For all methods, count up the number of changes to registers < 16
8999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * and >= 16.
9099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
9199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int updateLT16;
9299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int updateGE16;
9399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
9499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
9599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Histogram of the number of bits that differ between adjacent entries.
9699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
9799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int numDiffBits[kMaxDiffBits];
981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
1001d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    /*
1011d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * Track the number of expanded maps, and the heap space required to
1021d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * hold them.
1031d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     */
1041d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int numExpandedMaps;
1051d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int totalExpandedMapSize;
106d862faa2ceae186da5518607505eb942d634ced9Carl Shapiro};
10799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
10899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
10999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
11099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Prepare some things.
11199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
1121e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirobool dvmRegisterMapStartup()
11399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
11499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
11599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    MapStats* pStats = calloc(1, sizeof(MapStats));
11699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    gDvm.registerMapStats = pStats;
11799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
11899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return true;
11999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
12099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
12199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
12299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Clean up.
12399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
1241e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmRegisterMapShutdown()
12599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
12699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
12799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    free(gDvm.registerMapStats);
12899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
12999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
13099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
13199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
13299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Write stats to log file.
13399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
1341e1433e78f560a01744e870c19c162ab88df9dc1Carl Shapirovoid dvmRegisterMapDumpStats()
13599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
13699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
13799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    MapStats* pStats = (MapStats*) gDvm.registerMapStats;
13899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int i, end;
13999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
14099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (end = kMaxGcPointGap-1; end >= 0; end--) {
14199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (pStats->gcPointGap[end] != 0)
14299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            break;
14399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
14499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
1454308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI("Register Map gcPointGap stats (diff count=%d, total=%d):",
14699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pStats->gcGapCount, pStats->totalGcPointCount);
14799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(pStats->gcPointGap[0] == 0);
14899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 1; i <= end; i++) {
1494308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI(" %2d %d", i, pStats->gcPointGap[i]);
15099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
15199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
15299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
15399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (end = kMaxDiffBits-1; end >= 0; end--) {
15499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (pStats->numDiffBits[end] != 0)
15599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            break;
15699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
15799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
1584308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI("Register Map bit difference stats:");
15999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 0; i <= end; i++) {
1604308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI(" %2d %d", i, pStats->numDiffBits[i]);
16199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
16299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
16399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
1644308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block    ALOGI("Register Map update position stats (lt16=%d ge16=%d):",
16599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pStats->updateLT16, pStats->updateGE16);
16699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 0; i < kNumUpdatePosns; i++) {
1674308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI(" %2d %d", i, pStats->updatePosn[i]);
16899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
16999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
17099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
17199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
17299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
17399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
17499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
17599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *      Map generation
17699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
17799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Generate the register map for a method that has just been verified
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (i.e. we're doing this as part of verification).
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * For type-precise determination we have all the data we need, so we
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * just need to encode it in some clever fashion.
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectRegisterMap* dvmGenerateRegisterMapV(VerifierData* vdata)
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
190d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    static const int kHeaderSize = offsetof(RegisterMap, data);
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    RegisterMap* pMap = NULL;
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    RegisterMap* pResult = NULL;
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    RegisterMapFormat format;
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u1 regWidth;
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u1* mapData;
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int i, bytesForAddr, gcPointCount;
197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int bufSize;
198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (vdata->method->registersSize >= 2048) {
200c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("ERROR: register map can't handle %d registers",
20199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            vdata->method->registersSize);
20299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        goto bail;
20399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    regWidth = (vdata->method->registersSize + 7) / 8;
20599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
206d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
207d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Decide if we need 8 or 16 bits to hold the address.  Strictly speaking
208d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * we only need 16 bits if we actually encode an address >= 256 -- if
209d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * the method has a section at the end without GC points (e.g. array
210d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * data) we don't need to count it.  The situation is unusual, and
211d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * detecting it requires scanning the entire method, so we don't bother.
212d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (vdata->insnsSize < 256) {
21499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        format = kRegMapFormatCompact8;
215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bytesForAddr = 1;
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
21799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        format = kRegMapFormatCompact16;
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bytesForAddr = 2;
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Count up the number of GC point instructions.
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * NOTE: this does not automatically include the first instruction,
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * since we don't count method entry as a GC point.
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcPointCount = 0;
228228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden    for (i = 0; i < (int) vdata->insnsSize; i++) {
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmInsnIsGcPoint(vdata->insnFlags, i))
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gcPointCount++;
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcPointCount >= 65536) {
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* we could handle this, but in practice we don't get near this */
234c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("ERROR: register map can't handle %d gc points in one method",
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gcPointCount);
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Allocate a buffer to hold the map data.
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
242d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    bufSize = kHeaderSize + gcPointCount * (bytesForAddr + regWidth);
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
24492c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("+++ grm: %s.%s (adr=%d gpc=%d rwd=%d bsz=%d)",
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        vdata->method->clazz->descriptor, vdata->method->name,
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bytesForAddr, gcPointCount, regWidth, bufSize);
247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap = (RegisterMap*) malloc(bufSize);
249d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetFormat(pMap, format);
250d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetOnHeap(pMap, true);
251d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetRegWidth(pMap, regWidth);
25299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    dvmRegisterMapSetNumEntries(pMap, gcPointCount);
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Populate it.
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    mapData = pMap->data;
258228a6b01918304f2cd1213c722e028a6e25252bbAndy McFadden    for (i = 0; i < (int) vdata->insnsSize; i++) {
259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmInsnIsGcPoint(vdata->insnFlags, i)) {
260319a33bf2d40e11a0074952d537584a0332b8e45Andy McFadden            assert(vdata->registerLines[i].regTypes != NULL);
26199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (format == kRegMapFormatCompact8) {
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *mapData++ = i;
26399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else /*kRegMapFormatCompact16*/ {
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *mapData++ = i & 0xff;
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *mapData++ = i >> 8;
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
267319a33bf2d40e11a0074952d537584a0332b8e45Andy McFadden            outputTypeVector(vdata->registerLines[i].regTypes,
268319a33bf2d40e11a0074952d537584a0332b8e45Andy McFadden                vdata->insnRegCount, mapData);
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            mapData += regWidth;
270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
27392c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("mapData=%p pMap=%p bufSize=%d", mapData, pMap, bufSize);
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(mapData - (const u1*) pMap == bufSize);
275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
276a66a01ad2a9e5c6aefc93d12a5c18d6bba570a3eAndy McFadden    if (REGISTER_MAP_VERIFY && !verifyMap(vdata, pMap))
277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
27899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
27999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    computeMapStats(pMap, vdata->method);
28099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2821d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    /*
2831d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * Try to compress the map.
2841d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     */
2851d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    RegisterMap* pCompMap;
286d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
2871d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    pCompMap = compressMapDifferential(pMap, vdata->method);
2881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (pCompMap != NULL) {
2891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (REGISTER_MAP_VERIFY) {
2901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /*
2911d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             * Expand the compressed map we just created, and compare it
2921d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             * to the original.  Abort the VM if it doesn't match up.
2931d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             */
2941d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            RegisterMap* pUncompMap;
295d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            pUncompMap = uncompressMapDifferential(pCompMap);
296d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            if (pUncompMap == NULL) {
297c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                ALOGE("Map failed to uncompress - %s.%s",
2981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    vdata->method->clazz->descriptor,
2991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    vdata->method->name);
300d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                free(pCompMap);
3011d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* bad - compression is broken or we're out of memory */
3021d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                dvmAbort();
303d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            } else {
304d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                if (compareMaps(pMap, pUncompMap) != 0) {
305c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                    ALOGE("Map comparison failed - %s.%s",
306d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                        vdata->method->clazz->descriptor,
307d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                        vdata->method->name);
3081d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    free(pCompMap);
3091d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    /* bad - compression is broken */
3101d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    dvmAbort();
311d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                }
312d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
3131d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* verify succeeded */
3141813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro                delete pUncompMap;
315d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            }
316d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
3171d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
3181d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (REGISTER_MAP_VERBOSE) {
319062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("Good compress on %s.%s",
3201d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                vdata->method->clazz->descriptor,
3211d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                vdata->method->name);
3221d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
3231d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        free(pMap);
3241d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        pMap = pCompMap;
3251d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    } else {
3261d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (REGISTER_MAP_VERBOSE) {
327062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("Unable to compress %s.%s (ent=%d rw=%d)",
3281d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                vdata->method->clazz->descriptor,
3291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                vdata->method->name,
3301d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                dvmRegisterMapGetNumEntries(pMap),
3311d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                dvmRegisterMapGetRegWidth(pMap));
3321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
333d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
334d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pResult = pMap;
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return pResult;
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release the storage held by a RegisterMap.
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmFreeRegisterMap(RegisterMap* pMap)
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pMap == NULL)
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
349d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    assert(dvmRegisterMapGetOnHeap(pMap));
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(pMap);
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Determine if the RegType value is a reference type.
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Ordinarily we include kRegTypeZero in the "is it a reference"
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * check.  There's no value in doing so here, because we know
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the register can't hold anything but zero.
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline bool isReferenceType(RegType type)
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return (type > kRegTypeMAX || type == kRegTypeUninit);
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Given a line of registers, output a bit vector that indicates whether
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * or not the register holds a reference type (which could be null).
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We use '1' to indicate it's a reference, '0' for anything else (numeric
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * value, uninitialized data, merge conflict).  Register 0 will be found
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * in the low bit of the first byte.
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void outputTypeVector(const RegType* regs, int insnRegCount, u1* data)
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u1 val = 0;
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int i;
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (i = 0; i < insnRegCount; i++) {
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        RegType type = *regs++;
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        val >>= 1;
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isReferenceType(type))
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            val |= 0x80;        /* set hi bit */
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((i & 0x07) == 7)
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *data++ = val;
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((i & 0x07) != 0) {
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* flush bits from last byte */
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        val >>= 8 - (i & 0x07);
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *data++ = val;
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
3951d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Print the map as a series of binary strings.
3961d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
3971d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Pass in method->registersSize if known, or -1 if not.
3981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden */
3991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFaddenstatic void dumpRegisterMap(const RegisterMap* pMap, int registersSize)
4001d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden{
4011d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const u1* rawMap = pMap->data;
4021d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const RegisterMapFormat format = dvmRegisterMapGetFormat(pMap);
4031d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const int numEntries = dvmRegisterMapGetNumEntries(pMap);
4041d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const int regWidth = dvmRegisterMapGetRegWidth(pMap);
4051d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int addrWidth;
4061d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4071d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    switch (format) {
4081d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    case kRegMapFormatCompact8:
4091d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        addrWidth = 1;
4101d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        break;
4111d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    case kRegMapFormatCompact16:
4121d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        addrWidth = 2;
4131d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        break;
4141d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    default:
4151d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        /* can't happen */
416c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Can only dump Compact8 / Compact16 maps (not %d)", format);
4171d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        return;
4181d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
4191d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4201d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (registersSize < 0)
4211d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        registersSize = 8 * regWidth;
4221d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    assert(registersSize <= regWidth * 8);
4231d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4241d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int ent;
4251d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    for (ent = 0; ent < numEntries; ent++) {
4261d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        int i, addr;
4271d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4281d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        addr = *rawMap++;
4291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (addrWidth > 1)
4301d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            addr |= (*rawMap++) << 8;
4311d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        const u1* dataStart = rawMap;
4331d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        u1 val = 0;
4341d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4351d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        /* create binary string */
4361d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        char outBuf[registersSize +1];
4371d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        for (i = 0; i < registersSize; i++) {
4381d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            val >>= 1;
4391d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if ((i & 0x07) == 0)
4401d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                val = *rawMap++;
4411d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4421d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            outBuf[i] = '0' + (val & 0x01);
4431d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
4441d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        outBuf[i] = '\0';
4451d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4461d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        /* back up and create hex dump */
4471d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        char hexBuf[regWidth * 3 +1];
4481d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        char* cp = hexBuf;
4491d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        rawMap = dataStart;
4501d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        for (i = 0; i < regWidth; i++) {
4511d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            sprintf(cp, " %02x", *rawMap++);
4521d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            cp += 3;
4531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
4541d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        hexBuf[i * 3] = '\0';
4551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
456062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("  %04x %s %s", addr, outBuf, hexBuf);
4571d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
4581d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden}
4591d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4601d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/*
461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Double-check the map.
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We run through all of the data in the map, and compare it to the original.
46499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Only works on uncompressed data.
465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool verifyMap(VerifierData* vdata, const RegisterMap* pMap)
467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
46899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const u1* rawMap = pMap->data;
4691d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const RegisterMapFormat format = dvmRegisterMapGetFormat(pMap);
4701d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const int numEntries = dvmRegisterMapGetNumEntries(pMap);
471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int ent;
47299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    bool dumpMap = false;
47399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
47499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (false) {
47599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const char* cd = "Landroid/net/http/Request;";
47699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const char* mn = "readResponse";
47799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (strcmp(vdata->method->clazz->descriptor, cd) == 0 &&
47899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            strcmp(vdata->method->name, mn) == 0)
47999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        {
48099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            char* desc;
48199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            desc = dexProtoCopyMethodDescriptor(&vdata->method->prototype);
4824308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI("Map for %s.%s %s", vdata->method->clazz->descriptor,
48399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                vdata->method->name, desc);
48499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            free(desc);
48599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
48699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            dumpMap = true;
48799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
48899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
49099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if ((vdata->method->registersSize + 7) / 8 != pMap->regWidth) {
491c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("GLITCH: registersSize=%d, regWidth=%d",
49299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            vdata->method->registersSize, pMap->regWidth);
49399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return false;
49499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
49599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
49699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (ent = 0; ent < numEntries; ent++) {
497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int addr;
498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
49999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        switch (format) {
50099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        case kRegMapFormatCompact8:
50199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr = *rawMap++;
502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
50399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        case kRegMapFormatCompact16:
50499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr = *rawMap++;
50599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr |= (*rawMap++) << 8;
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        default:
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* shouldn't happen */
509c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("GLITCH: bad format (%d)", format);
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmAbort();
51168e74fda779ca28ecb2b3af10d5193691603b3d0Ben Cheng            /* Make compiler happy */
51268e74fda779ca28ecb2b3af10d5193691603b3d0Ben Cheng            addr = 0;
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
515319a33bf2d40e11a0074952d537584a0332b8e45Andy McFadden        const RegType* regs = vdata->registerLines[addr].regTypes;
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (regs == NULL) {
517c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("GLITCH: addr %d has no data", addr);
518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
52199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        u1 val = 0;
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int i;
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (i = 0; i < vdata->method->registersSize; i++) {
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bool bitIsRef, regIsRef;
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            val >>= 1;
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((i & 0x07) == 0) {
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* load next byte of data */
53099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                val = *rawMap++;
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bitIsRef = val & 0x01;
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RegType type = regs[i];
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            regIsRef = isReferenceType(type);
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (bitIsRef != regIsRef) {
539c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                ALOGE("GLITCH: addr %d reg %d: bit=%d reg=%d(%d)",
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    addr, i, bitIsRef, regIsRef, type);
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return false;
542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /* rawMap now points to the address field of the next entry */
54699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
54799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
5481d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (dumpMap)
5491d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        dumpRegisterMap(pMap, vdata->method->registersSize);
5501d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
55199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return true;
55299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
55399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
55499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
55599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
55699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
55799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *      DEX generation & parsing
55899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
55999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
56099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
56199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
56299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Advance "ptr" to ensure 32-bit alignment.
56399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
56499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic inline u1* align32(u1* ptr)
56599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
56699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return (u1*) (((int) ptr + 3) & ~0x03);
56799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
56899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
56999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
57099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Compute the size, in bytes, of a register map.
57199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
57299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic size_t computeRegisterMapSize(const RegisterMap* pMap)
57399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
57499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    static const int kHeaderSize = offsetof(RegisterMap, data);
575d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1 format = dvmRegisterMapGetFormat(pMap);
57699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
57799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
57899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(pMap != NULL);
57999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
58099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    switch (format) {
58199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatNone:
58299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return 1;
58399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatCompact8:
58499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return kHeaderSize + (1 + pMap->regWidth) * numEntries;
58599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatCompact16:
58699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return kHeaderSize + (2 + pMap->regWidth) * numEntries;
587d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatDifferential:
588d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        {
589d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            /* kHeaderSize + decoded ULEB128 length */
590d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            const u1* ptr = pMap->data;
591d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            int len = readUnsignedLeb128(&ptr);
592d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            return len + (ptr - (u1*) pMap);
593d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
59499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    default:
595c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Bad register map format %d", format);
59699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
59799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return 0;
59899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
59999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
60099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
60199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
60299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Output the map for a single method, if it has one.
60399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
60499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Abstract and native methods have no map.  All others are expected to
60599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * have one, since we know the class verified successfully.
60699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
60799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * This strips the "allocated on heap" flag from the format byte, so that
60899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * direct-mapped maps are correctly identified as such.
60999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
61099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic bool writeMapForMethod(const Method* meth, u1** pPtr)
61199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
61299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (meth->registerMap == NULL) {
61399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (!dvmIsAbstractMethod(meth) && !dvmIsNativeMethod(meth)) {
614e8e1ddccd616e8226b7cc1e4e9fdb327429249e8Steve Block            ALOGW("Warning: no map available for %s.%s",
61599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                meth->clazz->descriptor, meth->name);
61699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            /* weird, but keep going */
61799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
61899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        *(*pPtr)++ = kRegMapFormatNone;
61999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return true;
62099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
62199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
62299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /* serialize map into the buffer */
62399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    size_t mapSize = computeRegisterMapSize(meth->registerMap);
62499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    memcpy(*pPtr, meth->registerMap, mapSize);
62599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
62699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /* strip the "on heap" flag out of the format byte, which is always first */
62799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(**pPtr == meth->registerMap->format);
62899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    **pPtr &= ~(kRegMapFormatOnHeap);
62999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
63099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    *pPtr += mapSize;
63199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
63299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return true;
63399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
63499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
63599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
63699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Write maps for all methods in the specified class to the buffer, which
63799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * can hold at most "length" bytes.  "*pPtr" will be advanced past the end
63899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * of the data we write.
63999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
64099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic bool writeMapsAllMethods(DvmDex* pDvmDex, const ClassObject* clazz,
64199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u1** pPtr, size_t length)
64299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
64399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    RegisterMapMethodPool* pMethodPool;
64499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u1* ptr = *pPtr;
64599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int i, methodCount;
64699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
64799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /* artificial limit */
64899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (clazz->virtualMethodCount + clazz->directMethodCount >= 65536) {
649c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Too many methods in %s", clazz->descriptor);
65099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return false;
65199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
65299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
65399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pMethodPool = (RegisterMapMethodPool*) ptr;
65499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    ptr += offsetof(RegisterMapMethodPool, methodData);
65599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    methodCount = 0;
65699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
65799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
65899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Run through all methods, direct then virtual.  The class loader will
65999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * traverse them in the same order.  (We could split them into two
66099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * distinct pieces, but there doesn't appear to be any value in doing
66199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * so other than that it makes class loading slightly less fragile.)
66299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *
66399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * The class loader won't know about miranda methods at the point
66499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * where it parses this, so we omit those.
66599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *
66699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * TODO: consider omitting all native/abstract definitions.  Should be
66799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * safe, though we lose the ability to sanity-check against the
66899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * method counts in the DEX file.
66999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
67099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 0; i < clazz->directMethodCount; i++) {
67199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const Method* meth = &clazz->directMethods[i];
67299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (dvmIsMirandaMethod(meth))
67399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            continue;
67499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (!writeMapForMethod(&clazz->directMethods[i], &ptr)) {
67599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            return false;
67699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
67799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        methodCount++;
67899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        //ptr = align32(ptr);
67999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
68099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
68199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 0; i < clazz->virtualMethodCount; i++) {
68299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const Method* meth = &clazz->virtualMethods[i];
68399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (dvmIsMirandaMethod(meth))
68499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            continue;
68599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (!writeMapForMethod(&clazz->virtualMethods[i], &ptr)) {
68699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            return false;
687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
68899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        methodCount++;
68999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        //ptr = align32(ptr);
690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
69299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pMethodPool->methodCount = methodCount;
69399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
69499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    *pPtr = ptr;
695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
69899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
69999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Write maps for all classes to the specified buffer, which can hold at
70099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * most "length" bytes.
70199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
70299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Returns the actual length used, or 0 on failure.
70399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
70499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic size_t writeMapsAllClasses(DvmDex* pDvmDex, u1* basePtr, size_t length)
70599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
70699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    DexFile* pDexFile = pDvmDex->pDexFile;
70799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4 count = pDexFile->pHeader->classDefsSize;
70899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    RegisterMapClassPool* pClassPool;
70999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4* offsetTable;
71099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u1* ptr = basePtr;
71199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4 idx;
71299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
71399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(gDvm.optimizing);
71499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
71599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pClassPool = (RegisterMapClassPool*) ptr;
71699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    ptr += offsetof(RegisterMapClassPool, classDataOffset);
71799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    offsetTable = (u4*) ptr;
71899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    ptr += count * sizeof(u4);
71999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
72099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pClassPool->numClasses = count;
72199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
72299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
72399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * We want an entry for every class, loaded or not.
72499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
72599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (idx = 0; idx < count; idx++) {
72699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const DexClassDef* pClassDef;
72799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const char* classDescriptor;
72899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        ClassObject* clazz;
72999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
73099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pClassDef = dexGetClassDef(pDexFile, idx);
73199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
73299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
73399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /*
73499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * All classes have been loaded into the bootstrap class loader.
73599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * If we can find it, and it was successfully pre-verified, we
73699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * run through its methods and add the register maps.
73799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         *
73899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * If it wasn't pre-verified then we know it can't have any
73999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * register maps.  Classes that can't be loaded or failed
74099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * verification get an empty slot in the index.
74199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         */
74299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        clazz = NULL;
74399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if ((pClassDef->accessFlags & CLASS_ISPREVERIFIED) != 0)
74499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            clazz = dvmLookupClass(classDescriptor, NULL, false);
74599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
74699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (clazz != NULL) {
74799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            offsetTable[idx] = ptr - basePtr;
74860fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGVV("%d -> offset %d (%p-%p)",
74999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                idx, offsetTable[idx], ptr, basePtr);
75099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
75199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (!writeMapsAllMethods(pDvmDex, clazz, &ptr,
75299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                    length - (ptr - basePtr)))
75399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            {
75499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                return 0;
75599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
75699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
75799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            ptr = align32(ptr);
75860fc806b679a3655c228b4093058c59941a49cfeDan Bornstein            LOGVV("Size %s (%d+%d methods): %d", clazz->descriptor,
75999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                clazz->directMethodCount, clazz->virtualMethodCount,
76099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                (ptr - basePtr) - offsetTable[idx]);
76199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        } else {
76292c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block            ALOGV("%4d NOT mapadding '%s'", idx, classDescriptor);
76399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            assert(offsetTable[idx] == 0);
76499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
76599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
76699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
76799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (ptr - basePtr >= (int)length) {
76899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /* a bit late */
769c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Buffer overrun");
77099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
77199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
77299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
77399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return ptr - basePtr;
77499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
77599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
77699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
77799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Generate a register map set for all verified classes in "pDvmDex".
77899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
77999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectRegisterMapBuilder* dvmGenerateRegisterMaps(DvmDex* pDvmDex)
78099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
78199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    RegisterMapBuilder* pBuilder;
78299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
78399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pBuilder = (RegisterMapBuilder*) calloc(1, sizeof(RegisterMapBuilder));
78499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (pBuilder == NULL)
78599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
78699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
78799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
78899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * We have a couple of options here:
78999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *  (1) Compute the size of the output, and malloc a buffer.
79099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *  (2) Create a "large-enough" anonymous mmap region.
79199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *
79299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * The nice thing about option #2 is that we don't have to traverse
79399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * all of the classes and methods twice.  The risk is that we might
79499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * not make the region large enough.  Since the pages aren't mapped
79599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * until used we can allocate a semi-absurd amount of memory without
79699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * worrying about the effect on the rest of the system.
79799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *
79899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * The basic encoding on the largest jar file requires about 1MB of
79999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * storage.  We map out 4MB here.  (TODO: guarantee that the last
80099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * page of the mapping is marked invalid, so we reliably fail if
80199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * we overrun.)
80299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
80399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (sysCreatePrivateMap(4 * 1024 * 1024, &pBuilder->memMap) != 0) {
80499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        free(pBuilder);
80599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
80699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
80799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
80899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
80999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Create the maps.
81099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
81199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    size_t actual = writeMapsAllClasses(pDvmDex, (u1*)pBuilder->memMap.addr,
81299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                                        pBuilder->memMap.length);
81399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (actual == 0) {
81499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmFreeRegisterMapBuilder(pBuilder);
81599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
81699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
81799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
81892c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    ALOGV("TOTAL size of register maps: %d", actual);
81999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
82099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pBuilder->data = pBuilder->memMap.addr;
82199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pBuilder->size = actual;
82299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return pBuilder;
82399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
82499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
82599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
82699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Free the builder.
82799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
82899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectvoid dvmFreeRegisterMapBuilder(RegisterMapBuilder* pBuilder)
82999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
83099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (pBuilder == NULL)
83199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return;
83299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
83399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    sysReleaseShmem(&pBuilder->memMap);
83499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    free(pBuilder);
83599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
83699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
83799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
83899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
83999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Find the data for the specified class.
84099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
84199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * If there's no register map data, or none for this class, we return NULL.
84299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
843d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenconst void* dvmRegisterMapGetClassData(const DexFile* pDexFile, u4 classIdx,
84499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4* pNumMaps)
84599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
84699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const RegisterMapClassPool* pClassPool;
84799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const RegisterMapMethodPool* pMethodPool;
84899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
84999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pClassPool = (const RegisterMapClassPool*) pDexFile->pRegisterMapPool;
85099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (pClassPool == NULL)
85199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
85299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
85399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (classIdx >= pClassPool->numClasses) {
854c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("bad class index (%d vs %d)", classIdx, pClassPool->numClasses);
85599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
85699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
85799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
85899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4 classOffset = pClassPool->classDataOffset[classIdx];
85999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (classOffset == 0) {
86092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("+++ no map for classIdx=%d", classIdx);
86199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
86299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
86399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
86499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pMethodPool =
86599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        (const RegisterMapMethodPool*) (((u1*) pClassPool) + classOffset);
86699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (pNumMaps != NULL)
86799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        *pNumMaps = pMethodPool->methodCount;
86899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return pMethodPool->methodData;
86999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
87099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
87199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
87299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * This advances "*pPtr" and returns its original value.
87399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
874d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenconst RegisterMap* dvmRegisterMapGetNext(const void** pPtr)
87599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
876fc75f3ed87b55d625b6054e18645da5cbdba31c6Carl Shapiro    const RegisterMap* pMap = (const RegisterMap*) *pPtr;
87799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
87899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    *pPtr = /*align32*/(((u1*) pMap) + computeRegisterMapSize(pMap));
879291c84f60853d30e1c0d79dd08c5e5164f588e26Dan Bornstein    LOGVV("getNext: %p -> %p (f=%#x w=%d e=%d)",
88099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pMap, *pPtr, pMap->format, pMap->regWidth,
88199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmRegisterMapGetNumEntries(pMap));
88299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return pMap;
88399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
88499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
88599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
88699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
88799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
88899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *      Utility functions
88999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
89099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
89199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
89299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
89399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Return the data for the specified address, or NULL if not found.
89499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
89599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * The result must be released with dvmReleaseRegisterMapLine().
89699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
897d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenconst u1* dvmRegisterMapGetLine(const RegisterMap* pMap, int addr)
89899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
89999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int addrWidth, lineWidth;
900d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1 format = dvmRegisterMapGetFormat(pMap);
90199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
90299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
90399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(numEntries > 0);
90499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
90599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    switch (format) {
90699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatNone:
90799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
90899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatCompact8:
90999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        addrWidth = 1;
91099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        break;
91199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatCompact16:
91299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        addrWidth = 2;
91399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        break;
91499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    default:
915c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Unknown format %d", format);
91699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
91799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
91899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
91999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
92099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    lineWidth = addrWidth + pMap->regWidth;
92199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
92299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
92399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Find the appropriate entry.  Many maps are very small, some are very
92499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * large.
92599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
92699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    static const int kSearchThreshold = 8;
927734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    const u1* data = NULL;
92899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int lineAddr;
92999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
93099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (numEntries < kSearchThreshold) {
93199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        int i;
93299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        data = pMap->data;
93399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        for (i = numEntries; i > 0; i--) {
93499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            lineAddr = data[0];
93599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (addrWidth > 1)
93699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                lineAddr |= data[1] << 8;
93799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (lineAddr == addr)
93899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                return data + addrWidth;
93999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
94099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            data += lineWidth;
94199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
942869898f16f414a63187cd736e375fe32aae41f0fAndy McFadden        assert(data == pMap->data + lineWidth * numEntries);
94399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    } else {
94499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        int hi, lo, mid;
94599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
94699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        lo = 0;
94799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        hi = numEntries -1;
94899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
94999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        while (hi >= lo) {
95099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            mid = (hi + lo) / 2;
95199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            data = pMap->data + lineWidth * mid;
95299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
95399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            lineAddr = data[0];
95499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (addrWidth > 1)
95599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                lineAddr |= data[1] << 8;
95699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
95799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (addr > lineAddr) {
95899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                lo = mid + 1;
95999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else if (addr < lineAddr) {
96099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                hi = mid - 1;
96199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else {
96299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                return data + addrWidth;
96399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
96499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
96599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
96699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
96799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return NULL;
96899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
96999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
970d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden/*
971d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Compare two register maps.
972d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
973d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Returns 0 if they're equal, nonzero if not.
974d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden */
975d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2)
976d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden{
977d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    size_t size1, size2;
978d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
979d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    size1 = computeRegisterMapSize(pMap1);
980d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    size2 = computeRegisterMapSize(pMap2);
981d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (size1 != size2) {
9824308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("compareMaps: size mismatch (%zd vs %zd)", size1, size2);
983d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return -1;
984d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
985d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
986d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (memcmp(pMap1, pMap2, size1) != 0) {
9874308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("compareMaps: content mismatch");
988d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return -1;
989d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
990d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
991d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    return 0;
992d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden}
993d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
994d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
995d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden/*
996d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Get the expanded form of the register map associated with the method.
997d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
998d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * If the map is already in one of the uncompressed formats, we return
999d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * immediately.  Otherwise, we expand the map and replace method's register
1000d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * map pointer, freeing it if it was allocated on the heap.
1001d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
10029faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden * NOTE: this function is not synchronized; external locking is mandatory
10039faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden * (unless we're in the zygote, where single-threaded access is guaranteed).
1004d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden */
1005d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenconst RegisterMap* dvmGetExpandedRegisterMap0(Method* method)
1006d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden{
1007d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const RegisterMap* curMap = method->registerMap;
1008d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    RegisterMap* newMap;
1009d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1010d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (curMap == NULL)
1011d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return NULL;
1012d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1013d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /* sanity check to ensure this isn't called w/o external locking */
10149faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden    /* (if we use this at a time other than during GC, fix/remove this test) */
1015d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (true) {
1016980ffb0243a1840ad0a93cfa06dfc02ca6f2d01cCarl Shapiro        if (!gDvm.zygote && dvmTryLockMutex(&gDvm.gcHeapLock) == 0) {
1017c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("GLITCH: dvmGetExpandedRegisterMap not called at GC time");
1018d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            dvmAbort();
1019d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1020d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1021d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1022d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    RegisterMapFormat format = dvmRegisterMapGetFormat(curMap);
1023d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    switch (format) {
1024d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatCompact8:
1025d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatCompact16:
10261d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (REGISTER_MAP_VERBOSE) {
10271d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (dvmRegisterMapGetOnHeap(curMap)) {
1028062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block                ALOGD("RegMap: already expanded: %s.%s",
10291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    method->clazz->descriptor, method->name);
10301d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            } else {
1031062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block                ALOGD("RegMap: stored w/o compression: %s.%s",
10321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    method->clazz->descriptor, method->name);
10331d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            }
1034d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1035d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return curMap;
1036d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatDifferential:
1037d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newMap = uncompressMapDifferential(curMap);
1038d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        break;
1039d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    default:
1040c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Unknown format %d in dvmGetExpandedRegisterMap", format);
1041d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        dvmAbort();
1042a915b67335c1ffd78927eecd7023fc3d08e3e93fAndy McFadden        newMap = NULL;      // make gcc happy
1043d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1044d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1045d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (newMap == NULL) {
1046c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Map failed to uncompress (fmt=%d) %s.%s",
1047d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            format, method->clazz->descriptor, method->name);
1048d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return NULL;
1049d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1050d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
10511d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden#ifdef REGISTER_MAP_STATS
10521d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    /*
10531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * Gather and display some stats.
10541d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     */
10551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    {
10561d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        MapStats* pStats = (MapStats*) gDvm.registerMapStats;
10571d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        pStats->numExpandedMaps++;
10581d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        pStats->totalExpandedMapSize += computeRegisterMapSize(newMap);
1059062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("RMAP: count=%d size=%d",
10601d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            pStats->numExpandedMaps, pStats->totalExpandedMapSize);
10611d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
10621d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden#endif
10631d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
106492c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block    IF_ALOGV() {
10659faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
106692c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("Expanding map -> %s.%s:%s",
10679faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden            method->clazz->descriptor, method->name, desc);
10689faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden        free(desc);
10699faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden    }
10709faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden
1071d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1072d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Update method, and free compressed map if it was sitting on the heap.
1073d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1074d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmSetRegisterMap(method, newMap);
1075d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1076d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (dvmRegisterMapGetOnHeap(curMap))
1077d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        dvmFreeRegisterMap((RegisterMap*) curMap);
1078d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1079d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    return newMap;
1080d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden}
1081d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
108299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
108399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
108499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
108599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *      Map compression
108699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
108799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
108899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
108999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
109099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectNotes on map compression
109199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
109299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectThe idea is to create a compressed form that will be uncompressed before
109399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectuse, with the output possibly saved in a cache.  This means we can use an
109499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectapproach that is unsuited for random access if we choose.
109599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
109699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectIn the event that a map simply does not work with our compression scheme,
109799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectit's reasonable to store the map without compression.  In the future we
109899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectmay want to have more than one compression scheme, and try each in turn,
109999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectretaining the best.  (We certainly want to keep the uncompressed form if it
110099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectturns out to be smaller or even slightly larger than the compressed form.)
110199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
110299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectEach entry consists of an address and a bit vector.  Adjacent entries are
110399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstrongly correlated, suggesting differential encoding.
110499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
110599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
110699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectIdeally we would avoid outputting adjacent entries with identical
110799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectbit vectors.  However, the register values at a given address do not
110899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectimply anything about the set of valid registers at subsequent addresses.
110999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectWe therefore cannot omit an entry.
111099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
111199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  If the thread stack has a PC at an address without a corresponding
111299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  entry in the register map, we must conservatively scan the registers in
111399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  that thread.  This can happen when single-stepping in the debugger,
111499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  because the debugger is allowed to invoke arbitrary methods when
111599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  a thread is stopped at a breakpoint.  If we can guarantee that a GC
111699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  thread scan will never happen while the debugger has that thread stopped,
111799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  then we can lift this restriction and simply omit entries that don't
111899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  change the bit vector from its previous state.
111999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
112099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectEach entry advances the address value by at least 1 (measured in 16-bit
112199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project"code units").  Looking at the bootclasspath entries, advancing by 2 units
112299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectis most common.  Advances by 1 unit are far less common than advances by
112399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project2 units, but more common than 5, and things fall off rapidly.  Gaps of
112499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectup to 220 code units appear in some computationally intensive bits of code,
112599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectbut are exceedingly rare.
112699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
112799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectIf we sum up the number of transitions in a couple of ranges in framework.jar:
112899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  [1,4]: 188998 of 218922 gaps (86.3%)
112999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  [1,7]: 211647 of 218922 gaps (96.7%)
113099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectUsing a 3-bit delta, with one value reserved as an escape code, should
113199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectyield good results for the address.
113299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
113399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectThese results would change dramatically if we reduced the set of GC
113499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectpoints by e.g. removing instructions like integer divide that are only
113599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectpresent because they can throw and cause an allocation.
113699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
113799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectWe also need to include an "initial gap", because the first few instructions
113899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectin a method may not be GC points.
113999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
114099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
114199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectBy observation, many entries simply repeat the previous bit vector, or
114299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectchange only one or two bits.  (This is with type-precise information;
114399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectthe rate of change of bits will be different if live-precise information
114499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectis factored in).
114599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
114699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectLooking again at adjacent entries in framework.jar:
114799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  0 bits changed: 63.0%
114899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  1 bit changed: 32.2%
114999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectAfter that it falls off rapidly, e.g. the number of entries with 2 bits
115099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectchanged is usually less than 1/10th of the number of entries with 1 bit
115199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectchanged.  A solution that allows us to encode 0- or 1- bit changes
115299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectefficiently will do well.
115399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
115499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectWe still need to handle cases where a large number of bits change.  We
115599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectprobably want a way to drop in a full copy of the bit vector when it's
115699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectsmaller than the representation of multiple bit changes.
115799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
115899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
115999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectThe bit-change information can be encoded as an index that tells the
116099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectdecoder to toggle the state.  We want to encode the index in as few bits
116199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectas possible, but we need to allow for fairly wide vectors (e.g. we have a
116299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectmethod with 175 registers).  We can deal with this in a couple of ways:
116399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project(1) use an encoding that assumes few registers and has an escape code
116499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectfor larger numbers of registers; or (2) use different encodings based
116599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projecton how many total registers the method has.  The choice depends to some
116699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectextent on whether methods with large numbers of registers tend to modify
116799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectthe first 16 regs more often than the others.
116899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
116999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectThe last N registers hold method arguments.  If the bytecode is expected
117099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectto be examined in a debugger, "dx" ensures that the contents of these
117199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectregisters won't change.  Depending upon the encoding format, we may be
117299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectable to take advantage of this.  We still have to encode the initial
117399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstate, but we know we'll never have to output a bit change for the last
117499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectN registers.
117599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
117699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectConsidering only methods with 16 or more registers, the "target octant"
117799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectfor register changes looks like this:
117899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  [ 43.1%, 16.4%, 6.5%, 6.2%, 7.4%, 8.8%, 9.7%, 1.8% ]
117999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectAs expected, there are fewer changes at the end of the list where the
118099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectarguments are kept, and more changes at the start of the list because
118199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectregister values smaller than 16 can be used in compact Dalvik instructions
118299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectand hence are favored for frequently-used values.  In general, the first
118399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectoctant is considerably more active than later entries, the last octant
118499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectis much less active, and the rest are all about the same.
118599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
118699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectLooking at all bit changes in all methods, 94% are to registers 0-15.  The
118799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectencoding will benefit greatly by favoring the low-numbered registers.
118899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
118999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
119099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectSome of the smaller methods have identical maps, and space could be
119199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectsaved by simply including a pointer to an earlier definition.  This would
119299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectbe best accomplished by specifying a "pointer" format value, followed by
119399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projecta 3-byte (or ULEB128) offset.  Implementing this would probably involve
119499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectgenerating a hash value for each register map and maintaining a hash table.
119599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
119699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectIn some cases there are repeating patterns in the bit vector that aren't
119799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectadjacent.  These could benefit from a dictionary encoding.  This doesn't
119899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectreally become useful until the methods reach a certain size though,
119999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectand managing the dictionary may incur more overhead than we want.
1200d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1201d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenLarge maps can be compressed significantly.  The trouble is that, when
1202d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenwe need to use them, we have to uncompress them onto the heap.  We may
1203d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenget a better trade-off between storage size and heap usage by refusing to
1204d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddencompress large maps, so that they can be memory mapped and used directly.
1205d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden(OTOH, only about 2% of the maps will ever actually be used.)
1206d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1207d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1208d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden----- differential format -----
1209d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1210d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden// common header
1211d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+00 1B format
1212d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+01 1B regWidth
1213d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+02 2B numEntries (little-endian)
1214d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+04 nB length in bytes of the data that follows, in ULEB128 format
1215d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden       (not strictly necessary; allows determination of size w/o full parse)
1216d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+05+ 1B initial address (0-127), high bit set if max addr >= 256
1217d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+06+ nB initial value for bit vector
1218d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1219d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden// for each entry
1220d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+00: CCCCBAAA
1221d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1222d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  AAA: address difference.  Values from 0 to 6 indicate an increment of 1
1223d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  to 7.  A value of 7 indicates that the address difference is large,
1224d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  and the next byte is a ULEB128-encoded difference value.
1225d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1226d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  B: determines the meaning of CCCC.
1227d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
12281d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden  CCCC: if B is 0, this is the number of the bit to toggle (0-15).
12291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden  If B is 1, this is a count of the number of changed bits (1-14).  A value
12301d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden  of 0 means that no bits were changed, and a value of 15 indicates
1231d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  that enough bits were changed that it required less space to output
1232d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  the entire bit vector.
1233d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1234d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+01: (optional) ULEB128-encoded address difference
1235d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1236d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+01+: (optional) one or more ULEB128-encoded bit numbers, OR the entire
1237d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  bit vector.
1238d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1239d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenThe most common situation is an entry whose address has changed by 2-4
1240d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddencode units, has no changes or just a single bit change, and the changed
1241d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenregister is less than 16.  We should therefore be able to encode a large
1242d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddennumber of entries with a single byte, which is half the size of the
1243d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenCompact8 encoding method.
124499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project*/
124599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
124699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
1247d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Compute some stats on an uncompressed register map.
124899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
1249e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro#ifdef REGISTER_MAP_STATS
125099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic void computeMapStats(RegisterMap* pMap, const Method* method)
125199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
125299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    MapStats* pStats = (MapStats*) gDvm.registerMapStats;
1253d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1 format = dvmRegisterMapGetFormat(pMap);
125499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
125599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const u1* rawMap = pMap->data;
125699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const u1* prevData = NULL;
125799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int ent, addr, prevAddr = -1;
125899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
125999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (ent = 0; ent < numEntries; ent++) {
126099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        switch (format) {
126199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        case kRegMapFormatCompact8:
126299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr = *rawMap++;
126399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            break;
126499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        case kRegMapFormatCompact16:
126599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr = *rawMap++;
126699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr |= (*rawMap++) << 8;
126799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            break;
126899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        default:
126999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            /* shouldn't happen */
1270c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block            ALOGE("GLITCH: bad format (%d)", format);
127199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            dvmAbort();
127299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
127399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
127499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const u1* dataStart = rawMap;
127599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
127699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pStats->totalGcPointCount++;
127799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
127899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /*
127999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * Gather "gap size" stats, i.e. the difference in addresses between
128099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * successive GC points.
128199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         */
128299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (prevData != NULL) {
128399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            assert(prevAddr >= 0);
128499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            int addrDiff = addr - prevAddr;
128599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
128699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (addrDiff < 0) {
1287c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                ALOGE("GLITCH: address went backward (0x%04x->0x%04x, %s.%s)",
128899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                    prevAddr, addr, method->clazz->descriptor, method->name);
128999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else if (addrDiff > kMaxGcPointGap) {
12901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                if (REGISTER_MAP_VERBOSE) {
12914308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block                    ALOGI("HEY: addrDiff is %d, max %d (0x%04x->0x%04x %s.%s)",
12921d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        addrDiff, kMaxGcPointGap, prevAddr, addr,
12931d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        method->clazz->descriptor, method->name);
12941d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                }
129599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                /* skip this one */
129699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else {
129799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                pStats->gcPointGap[addrDiff]++;
129899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
129999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            pStats->gcGapCount++;
130099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
130199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
130299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            /*
130399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * Compare bit vectors in adjacent entries.  We want to count
130499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * up the number of bits that differ (to see if we frequently
130599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * change 0 or 1 bits) and get a sense for which part of the
130699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * vector changes the most often (near the start, middle, end).
130799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             *
130899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * We only do the vector position quantization if we have at
130999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * least 16 registers in the method.
131099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             */
131199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            int numDiff = 0;
131299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            float div = (float) kNumUpdatePosns / method->registersSize;
131399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            int regByte;
131499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            for (regByte = 0; regByte < pMap->regWidth; regByte++) {
131599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                int prev, cur, bit;
131699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
131799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                prev = prevData[regByte];
131899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                cur = dataStart[regByte];
131999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
132099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                for (bit = 0; bit < 8; bit++) {
132199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                    if (((prev >> bit) & 1) != ((cur >> bit) & 1)) {
132299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        numDiff++;
132399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
132499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        int bitNum = regByte * 8 + bit;
132599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
132699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        if (bitNum < 16)
132799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            pStats->updateLT16++;
132899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        else
132999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            pStats->updateGE16++;
133099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
133199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        if (method->registersSize < 16)
133299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            continue;
133399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
133499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        if (bitNum >= method->registersSize) {
133599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            /* stuff off the end should be zero in both */
1336c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                            ALOGE("WEIRD: bit=%d (%d/%d), prev=%02x cur=%02x",
133799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                                bit, regByte, method->registersSize,
133899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                                prev, cur);
133999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            assert(false);
134099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        }
134199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        int idx = (int) (bitNum * div);
134299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        if (!(idx >= 0 && idx < kNumUpdatePosns)) {
1343c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block                            ALOGE("FAIL: bitNum=%d (of %d) div=%.3f idx=%d",
134499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                                bitNum, method->registersSize, div, idx);
134599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            assert(false);
134699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        }
134799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        pStats->updatePosn[idx]++;
134899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                    }
134999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                }
135099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
135199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
135299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (numDiff > kMaxDiffBits) {
13531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                if (REGISTER_MAP_VERBOSE) {
13544308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block                    ALOGI("WOW: numDiff is %d, max %d", numDiff, kMaxDiffBits);
13551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                }
135699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else {
135799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                pStats->numDiffBits[numDiff]++;
135899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
135999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
136099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
136199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /* advance to start of next line */
136299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        rawMap += pMap->regWidth;
136399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
136499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        prevAddr = addr;
136599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        prevData = dataStart;
136699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
136799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
1368e3c01dac83e6eea7f82fe81ed89cfbdd9791dbc9Carl Shapiro#endif
1369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
13711d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Compute the difference between two bit vectors.
13721d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
13731d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * If "lebOutBuf" is non-NULL, we output the bit indices in ULEB128 format
13741d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * as we go.  Otherwise, we just generate the various counts.
13751d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
13761d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * The bit vectors are compared byte-by-byte, so any unused bits at the
13771d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * end must be zero.
13781d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
13791d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Returns the number of bytes required to hold the ULEB128 output.
13801d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
13811d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * If "pFirstBitChanged" or "pNumBitsChanged" are non-NULL, they will
13821d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * receive the index of the first changed bit and the number of changed
13831d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * bits, respectively.
13841d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden */
13851d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFaddenstatic int computeBitDiff(const u1* bits1, const u1* bits2, int byteWidth,
13861d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int* pFirstBitChanged, int* pNumBitsChanged, u1* lebOutBuf)
13871d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden{
13881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int numBitsChanged = 0;
13891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int firstBitChanged = -1;
13901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int lebSize = 0;
13911d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int byteNum;
13921d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
13931d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    /*
13941d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * Run through the vectors, first comparing them at the byte level.  This
13951d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * will yield a fairly quick result if nothing has changed between them.
13961d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     */
13971d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    for (byteNum = 0; byteNum < byteWidth; byteNum++) {
13981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        u1 byte1 = *bits1++;
13991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        u1 byte2 = *bits2++;
14001d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (byte1 != byte2) {
14011d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /*
14021d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             * Walk through the byte, identifying the changed bits.
14031d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             */
14041d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            int bitNum;
14051d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            for (bitNum = 0; bitNum < 8; bitNum++) {
14061d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                if (((byte1 >> bitNum) & 0x01) != ((byte2 >> bitNum) & 0x01)) {
14071d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    int bitOffset = (byteNum << 3) + bitNum;
14081d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14091d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    if (firstBitChanged < 0)
14101d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        firstBitChanged = bitOffset;
14111d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    numBitsChanged++;
14121d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14131d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    if (lebOutBuf == NULL) {
14141d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        lebSize += unsignedLeb128Size(bitOffset);
14151d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    } else {
14161d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        u1* curBuf = lebOutBuf;
14171d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        lebOutBuf = writeUnsignedLeb128(lebOutBuf, bitOffset);
14181d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        lebSize += lebOutBuf - curBuf;
14191d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    }
14201d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                }
14211d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            }
14221d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
14231d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
14241d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14251d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (numBitsChanged > 0)
14261d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        assert(firstBitChanged >= 0);
14271d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14281d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (pFirstBitChanged != NULL)
14291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        *pFirstBitChanged = firstBitChanged;
14301d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (pNumBitsChanged != NULL)
14311d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        *pNumBitsChanged = numBitsChanged;
14321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14331d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    return lebSize;
14341d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden}
14351d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14361d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/*
1437d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Compress the register map with differential encoding.
1438d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
1439d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * "meth" is only needed for debug output.
1440d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
1441d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * On success, returns a newly-allocated RegisterMap.  If the map is not
1442d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * compatible for some reason, or fails to get smaller, this will return NULL.
1443d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden */
1444d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic RegisterMap* compressMapDifferential(const RegisterMap* pMap,
1445d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const Method* meth)
1446d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden{
1447d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    RegisterMap* pNewMap = NULL;
1448d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int origSize = computeRegisterMapSize(pMap);
1449d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1* tmpPtr;
1450d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int addrWidth, regWidth, numEntries;
1451d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    bool debug = false;
1452d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1453d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (false &&
14541d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        strcmp(meth->clazz->descriptor, "Landroid/text/StaticLayout;") == 0 &&
14551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        strcmp(meth->name, "generate") == 0)
1456d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    {
1457d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        debug = true;
1458d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1459d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1460d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1 format = dvmRegisterMapGetFormat(pMap);
1461d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    switch (format) {
1462d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatCompact8:
1463d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addrWidth = 1;
1464d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        break;
1465d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatCompact16:
1466d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addrWidth = 2;
1467d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        break;
1468d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    default:
1469c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("ERROR: can't compress map with format=%d", format);
14701813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        return NULL;
1471d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1472d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1473d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    regWidth = dvmRegisterMapGetRegWidth(pMap);
1474d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    numEntries = dvmRegisterMapGetNumEntries(pMap);
1475d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1476d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (debug) {
14774308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("COMPRESS: %s.%s aw=%d rw=%d ne=%d",
1478d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            meth->clazz->descriptor, meth->name,
1479d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            addrWidth, regWidth, numEntries);
14801d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        dumpRegisterMap(pMap, -1);
1481d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1482d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1483d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (numEntries <= 1) {
148492c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("Can't compress map with 0 or 1 entries");
14851813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        return NULL;
1486d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1487d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1488d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1489d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * We don't know how large the compressed data will be.  It's possible
1490d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * for it to expand and become larger than the original.  The header
1491d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * itself is variable-sized, so we generate everything into a temporary
1492d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * buffer and then copy it to form-fitting storage once we know how big
1493d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * it will be (and that it's smaller than the original).
1494d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     *
1495d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * If we use a size that is equal to the size of the input map plus
1496d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * a value longer than a single entry can possibly expand to, we need
1497d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * only check for overflow at the end of each entry.  The worst case
1498d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * for a single line is (1 + <ULEB8 address> + <full copy of vector>).
1499d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Addresses are 16 bits, so that's (1 + 3 + regWidth).
1500d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     *
1501d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * The initial address offset and bit vector will take up less than
1502d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * or equal to the amount of space required when uncompressed -- large
1503d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * initial offsets are rejected.
1504d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
15051813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    UniquePtr<u1[]> tmpBuf(new u1[origSize + (1 + 3 + regWidth)]);
15061813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    if (tmpBuf.get() == NULL)
15071813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        return NULL;
1508d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
15091813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    tmpPtr = tmpBuf.get();
1510d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1511d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* mapData = pMap->data;
1512d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* prevBits;
1513d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u2 addr, prevAddr;
1514d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1515d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    addr = *mapData++;
1516d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (addrWidth > 1)
1517d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addr |= (*mapData++) << 8;
1518d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1519d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (addr >= 128) {
152092c1f6f1b4249e4e379452ee7b49f027052bf4ceSteve Block        ALOGV("Can't compress map with starting address >= 128");
15211813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        return NULL;
1522d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1523d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1524d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1525d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Start by writing the initial address and bit vector data.  The high
1526d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * bit of the initial address is used to indicate the required address
1527d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * width (which the decoder can't otherwise determine without parsing
1528d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * the compressed data).
1529d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1530d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    *tmpPtr++ = addr | (addrWidth > 1 ? 0x80 : 0x00);
1531d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    memcpy(tmpPtr, mapData, regWidth);
1532d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1533d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    prevBits = mapData;
1534d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    prevAddr = addr;
1535d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1536d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    tmpPtr += regWidth;
1537d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    mapData += regWidth;
1538d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1539d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1540d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Loop over all following entries.
1541d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
15421813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    for (int entry = 1; entry < numEntries; entry++) {
1543d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        int addrDiff;
1544d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        u1 key;
1545d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1546d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        /*
1547d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden         * Pull out the address and figure out how to encode it.
1548d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden         */
1549d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addr = *mapData++;
1550d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        if (addrWidth > 1)
1551d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            addr |= (*mapData++) << 8;
1552d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
15531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (debug)
15544308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI(" addr=0x%04x ent=%d (aw=%d)", addr, entry, addrWidth);
15551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
1556d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addrDiff = addr - prevAddr;
1557d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        assert(addrDiff > 0);
15581035127f783b84befca34f1afe2a5bff64546902Andy McFadden        if (addrDiff < 8) {
1559d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            /* small difference, encode in 3 bits */
15601035127f783b84befca34f1afe2a5bff64546902Andy McFadden            key = addrDiff -1;          /* set 00000AAA */
1561d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            if (debug)
15624308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block                ALOGI(" : small %d, key=0x%02x", addrDiff, key);
1563d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        } else {
1564d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            /* large difference, output escape code */
15651d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            key = 0x07;                 /* escape code for AAA */
1566d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            if (debug)
15674308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block                ALOGI(" : large %d, key=0x%02x", addrDiff, key);
1568d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1569d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
15701d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        int numBitsChanged, firstBitChanged, lebSize;
15711d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
15721d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        lebSize = computeBitDiff(prevBits, mapData, regWidth,
15731d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            &firstBitChanged, &numBitsChanged, NULL);
15741d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
15751d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (debug) {
15764308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            ALOGI(" : diff fbc=%d nbc=%d ls=%d (rw=%d)",
15771d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                firstBitChanged, numBitsChanged, lebSize, regWidth);
15781d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
15791d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
15801d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (numBitsChanged == 0) {
15811d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* set B to 1 and CCCC to zero to indicate no bits were changed */
15821d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            key |= 0x08;
15834308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            if (debug) ALOGI(" : no bits changed");
15841d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        } else if (numBitsChanged == 1 && firstBitChanged < 16) {
15851d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* set B to 0 and CCCC to the index of the changed bit */
15861d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            key |= firstBitChanged << 4;
15874308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            if (debug) ALOGI(" : 1 low bit changed");
15881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        } else if (numBitsChanged < 15 && lebSize < regWidth) {
15891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* set B to 1 and CCCC to the number of bits */
15901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            key |= 0x08 | (numBitsChanged << 4);
15914308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            if (debug) ALOGI(" : some bits changed");
15921d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        } else {
15931d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* set B to 1 and CCCC to 0x0f so we store the entire vector */
15941d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            key |= 0x08 | 0xf0;
15954308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block            if (debug) ALOGI(" : encode original");
15961d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
1597d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1598d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        /*
1599d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden         * Encode output.  Start with the key, follow with the address
16001d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden         * diff (if it didn't fit in 3 bits), then the changed bit info.
1601d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden         */
1602d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        *tmpPtr++ = key;
16031035127f783b84befca34f1afe2a5bff64546902Andy McFadden        if ((key & 0x07) == 0x07)
1604d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            tmpPtr = writeUnsignedLeb128(tmpPtr, addrDiff);
1605d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
16061d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if ((key & 0x08) != 0) {
16071d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            int bitCount = key >> 4;
16081d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (bitCount == 0) {
16091d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* nothing changed, no additional output required */
16101d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            } else if (bitCount == 15) {
16111d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* full vector is most compact representation */
16121d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                memcpy(tmpPtr, mapData, regWidth);
16131d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                tmpPtr += regWidth;
16141d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            } else {
16151d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* write bit indices in LEB128 format */
16161d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                (void) computeBitDiff(prevBits, mapData, regWidth,
16171d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    NULL, NULL, tmpPtr);
16181d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                tmpPtr += lebSize;
16191d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            }
16201d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        } else {
16211d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* single-bit changed, value encoded in key byte */
16221d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
1623d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1624d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        prevBits = mapData;
1625d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        prevAddr = addr;
1626d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        mapData += regWidth;
1627d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1628d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        /*
1629d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden         * See if we've run past the original size.
1630d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden         */
16311813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        if (tmpPtr - tmpBuf.get() >= origSize) {
16321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (debug) {
1633062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block                ALOGD("Compressed size >= original (%d vs %d): %s.%s",
16341813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro                    tmpPtr - tmpBuf.get(), origSize,
16351d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    meth->clazz->descriptor, meth->name);
16361d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            }
16371813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro            return NULL;
1638d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1639d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1640d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1641d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1642d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Create a RegisterMap with the contents.
16431d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     *
16441d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * TODO: consider using a threshold other than merely ">=".  We would
16451d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * get poorer compression but potentially use less native heap space.
1646d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1647d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    static const int kHeaderSize = offsetof(RegisterMap, data);
16481813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    int newDataSize = tmpPtr - tmpBuf.get();
1649d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int newMapSize;
1650d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1651d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    newMapSize = kHeaderSize + unsignedLeb128Size(newDataSize) + newDataSize;
1652d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (newMapSize >= origSize) {
16531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (debug) {
1654062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block            ALOGD("Final comp size >= original (%d vs %d): %s.%s",
16551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                newMapSize, origSize, meth->clazz->descriptor, meth->name);
16561d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
16571813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        return NULL;
1658d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1659d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1660d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    pNewMap = (RegisterMap*) malloc(newMapSize);
1661d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (pNewMap == NULL)
16621813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        return NULL;
1663d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetFormat(pNewMap, kRegMapFormatDifferential);
1664d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetOnHeap(pNewMap, true);
1665d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetRegWidth(pNewMap, regWidth);
1666d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetNumEntries(pNewMap, numEntries);
1667d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1668d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    tmpPtr = pNewMap->data;
1669d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    tmpPtr = writeUnsignedLeb128(tmpPtr, newDataSize);
16701813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    memcpy(tmpPtr, tmpBuf.get(), newDataSize);
1671d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
16721d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (REGISTER_MAP_VERBOSE) {
1673062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("Compression successful (%d -> %d) from aw=%d rw=%d ne=%d",
16741d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap),
16751d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            addrWidth, regWidth, numEntries);
16761d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
1677d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1678d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    return pNewMap;
1679d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden}
1680d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1681d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden/*
16821d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Toggle the value of the "idx"th bit in "ptr".
16831d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden */
16841d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFaddenstatic inline void toggleBit(u1* ptr, int idx)
16851d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden{
16861d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    ptr[idx >> 3] ^= 1 << (idx & 0x07);
16871d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden}
16881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
16891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/*
1690d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Expand a compressed map to an uncompressed form.
1691d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
1692d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Returns a newly-allocated RegisterMap on success, or NULL on failure.
16931d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
16941d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * TODO: consider using the linear allocator or a custom allocator with
16951d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * LRU replacement for these instead of the native heap.
1696d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden */
1697d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic RegisterMap* uncompressMapDifferential(const RegisterMap* pMap)
1698d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden{
1699d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    static const int kHeaderSize = offsetof(RegisterMap, data);
1700d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1 format = dvmRegisterMapGetFormat(pMap);
1701d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    RegisterMapFormat newFormat;
1702d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int regWidth, numEntries, newAddrWidth, newMapSize;
1703d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1704d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (format != kRegMapFormatDifferential) {
1705c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("Not differential (%d)", format);
17061813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        return NULL;
1707d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1708d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1709d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    regWidth = dvmRegisterMapGetRegWidth(pMap);
1710d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    numEntries = dvmRegisterMapGetNumEntries(pMap);
1711d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1712d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /* get the data size; we can check this at the end */
1713d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* srcPtr = pMap->data;
1714d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int expectedSrcLen = readUnsignedLeb128(&srcPtr);
1715d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* srcStart = srcPtr;
1716d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1717d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /* get the initial address and the 16-bit address flag */
1718d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int addr = *srcPtr & 0x7f;
1719d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if ((*srcPtr & 0x80) == 0) {
1720d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newFormat = kRegMapFormatCompact8;
1721d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newAddrWidth = 1;
1722d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    } else {
1723d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newFormat = kRegMapFormatCompact16;
1724d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newAddrWidth = 2;
1725d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1726d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    srcPtr++;
1727d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1728d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /* now we know enough to allocate the new map */
17291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (REGISTER_MAP_VERBOSE) {
17304308417beec548c2b2c06ecec4f7f4a965b09fb2Steve Block        ALOGI("Expanding to map aw=%d rw=%d ne=%d",
17311d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            newAddrWidth, regWidth, numEntries);
17321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
1733d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    newMapSize = kHeaderSize + (newAddrWidth + regWidth) * numEntries;
17341813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro    RegisterMap* pNewMap = (RegisterMap*) malloc(newMapSize);
17351813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro
1736d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (pNewMap == NULL)
17371813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro      return NULL;
1738d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1739d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetFormat(pNewMap, newFormat);
1740d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetOnHeap(pNewMap, true);
1741d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetRegWidth(pNewMap, regWidth);
1742d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetNumEntries(pNewMap, numEntries);
1743d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1744d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1745d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Write the start address and initial bits to the new map.
1746d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1747d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1* dstPtr = pNewMap->data;
1748d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1749d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    *dstPtr++ = addr & 0xff;
1750d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (newAddrWidth > 1)
1751d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        *dstPtr++ = (u1) (addr >> 8);
1752d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1753d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    memcpy(dstPtr, srcPtr, regWidth);
1754d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1755d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int prevAddr = addr;
1756d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* prevBits = dstPtr;    /* point at uncompressed data */
1757d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1758d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dstPtr += regWidth;
1759d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    srcPtr += regWidth;
1760d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1761d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1762d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Walk through, uncompressing one line at a time.
1763d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1764d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int entry;
1765d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    for (entry = 1; entry < numEntries; entry++) {
1766d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        int addrDiff;
1767d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        u1 key;
1768d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1769d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        key = *srcPtr++;
1770d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1771d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        /* get the address */
1772d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        if ((key & 0x07) == 7) {
1773d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            /* address diff follows in ULEB128 */
1774d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            addrDiff = readUnsignedLeb128(&srcPtr);
1775d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        } else {
17761035127f783b84befca34f1afe2a5bff64546902Andy McFadden            addrDiff = (key & 0x07) +1;
1777d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1778d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1779d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addr = prevAddr + addrDiff;
1780d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        *dstPtr++ = addr & 0xff;
1781d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        if (newAddrWidth > 1)
1782d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            *dstPtr++ = (u1) (addr >> 8);
1783d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1784d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        /* unpack the bits */
1785d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        if ((key & 0x08) != 0) {
17861d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            int bitCount = (key >> 4);
17871d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (bitCount == 0) {
17881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* no bits changed, just copy previous */
17891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                memcpy(dstPtr, prevBits, regWidth);
17901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            } else if (bitCount == 15) {
1791d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                /* full copy of bit vector is present; ignore prevBits */
1792d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                memcpy(dstPtr, srcPtr, regWidth);
1793d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                srcPtr += regWidth;
1794d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            } else {
17951d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* copy previous bits and modify listed indices */
17961d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                memcpy(dstPtr, prevBits, regWidth);
17971d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                while (bitCount--) {
17981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    int bitIndex = readUnsignedLeb128(&srcPtr);
17991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    toggleBit(dstPtr, bitIndex);
18001d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                }
1801d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            }
1802d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        } else {
18031d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* copy previous bits and modify the specified one */
18041d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            memcpy(dstPtr, prevBits, regWidth);
18051d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
18061d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* one bit, from 0-15 inclusive, was changed */
18071d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            toggleBit(dstPtr, key >> 4);
1808d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1809d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1810d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        prevAddr = addr;
1811d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        prevBits = dstPtr;
1812d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        dstPtr += regWidth;
1813d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1814d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1815d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (dstPtr - (u1*) pNewMap != newMapSize) {
1816c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("ERROR: output %d bytes, expected %d",
1817d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            dstPtr - (u1*) pNewMap, newMapSize);
18181813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        free(pNewMap);
18191813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        return NULL;
1820d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1821d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1822d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (srcPtr - srcStart != expectedSrcLen) {
1823c1a4ab9c313d8a3d12007f2dbef7b5a6fa4ac2efSteve Block        ALOGE("ERROR: consumed %d bytes, expected %d",
1824d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            srcPtr - srcStart, expectedSrcLen);
18251813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        free(pNewMap);
18261813ab265f691e93401c7307c0b34247842ab35eCarl Shapiro        return NULL;
1827d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1828d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
18291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (REGISTER_MAP_VERBOSE) {
1830062bf509a77fce9dfcb7e7b2e401cf2a124d83d5Steve Block        ALOGD("Expansion successful (%d -> %d)",
18311d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap));
18321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
1833d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1834d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    return pNewMap;
1835d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden}
1836