RegisterMap.cpp revision 980ffb0243a1840ad0a93cfa06dfc02ca6f2d01c
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"
24f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "analysis/CodeVerify.h"
25f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "analysis/RegisterMap.h"
26f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "libdex/DexCatch.h"
27f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include "libdex/InstrUtils.h"
28d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden#include "libdex/Leb128.h"
29f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
30f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#include <stddef.h>
31f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/* double-check the compression */
33a66a01ad2a9e5c6aefc93d12a5c18d6bba570a3eAndy McFadden#define REGISTER_MAP_VERIFY     false
341d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
351d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/* verbose logging */
361d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden#define REGISTER_MAP_VERBOSE    false
371d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
38f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
39f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// fwd
40f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void outputTypeVector(const RegType* regs, int insnRegCount, u1* data);
41f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool verifyMap(VerifierData* vdata, const RegisterMap* pMap);
42d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2);
43d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
4499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic void computeMapStats(RegisterMap* pMap, const Method* method);
451d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFaddenstatic RegisterMap* compressMapDifferential(const RegisterMap* pMap,\
46d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const Method* meth);
47d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic RegisterMap* uncompressMapDifferential(const RegisterMap* pMap);
4899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
4999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
5099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project//#define REGISTER_MAP_STATS
5199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
5299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Generate some statistics on the register maps we create and use.
5499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
5599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#define kMaxGcPointGap      50
5699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#define kUpdatePosnMinRegs  24
5799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#define kNumUpdatePosns     8
5899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#define kMaxDiffBits        20
5999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projecttypedef struct MapStats {
6099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
6199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Buckets measuring the distance between GC points.  This tells us how
6299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * many bits we need to encode the advancing program counter.  We ignore
6399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * some of the "long tail" entries.
6499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
6599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int gcPointGap[kMaxGcPointGap];
6699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
6799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
6899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Number of gaps.  Equal to (number of gcPoints - number of methods),
6999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * since the computation isn't including the initial gap.
7099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
7199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int gcGapCount;
7299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
7399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
7499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Number of gaps.
7599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
7699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int totalGcPointCount;
7799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
7899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
7999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * For larger methods (>= 24 registers), measure in which octant register
8099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * updates occur.  This should help us understand whether register
8199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * changes tend to cluster in the low regs even for large methods.
8299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
8399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int updatePosn[kNumUpdatePosns];
8499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
8599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
8699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * For all methods, count up the number of changes to registers < 16
8799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * and >= 16.
8899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
8999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int updateLT16;
9099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int updateGE16;
9199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
9299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
9399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Histogram of the number of bits that differ between adjacent entries.
9499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
9599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int numDiffBits[kMaxDiffBits];
961d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
971d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    /*
991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * Track the number of expanded maps, and the heap space required to
1001d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * hold them.
1011d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     */
1021d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int numExpandedMaps;
1031d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int totalExpandedMapSize;
10499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project} MapStats;
10599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
10699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
10799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
10899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Prepare some things.
10999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
11099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectbool dvmRegisterMapStartup(void)
11199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
11299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
11399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    MapStats* pStats = calloc(1, sizeof(MapStats));
11499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    gDvm.registerMapStats = pStats;
11599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
11699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return true;
11799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
11899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
11999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
12099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Clean up.
12199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
12299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectvoid dvmRegisterMapShutdown(void)
12399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
12499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
12599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    free(gDvm.registerMapStats);
12699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
12799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
12899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
12999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
13099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Write stats to log file.
13199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
13299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectvoid dvmRegisterMapDumpStats(void)
13399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
13499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
13599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    MapStats* pStats = (MapStats*) gDvm.registerMapStats;
13699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int i, end;
13799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
13899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (end = kMaxGcPointGap-1; end >= 0; end--) {
13999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (pStats->gcPointGap[end] != 0)
14099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            break;
14199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
14299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
14399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    LOGI("Register Map gcPointGap stats (diff count=%d, total=%d):\n",
14499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pStats->gcGapCount, pStats->totalGcPointCount);
14599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(pStats->gcPointGap[0] == 0);
14699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 1; i <= end; i++) {
14799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGI(" %2d %d\n", i, pStats->gcPointGap[i]);
14899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
14999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
15099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
15199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (end = kMaxDiffBits-1; end >= 0; end--) {
15299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (pStats->numDiffBits[end] != 0)
15399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            break;
15499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
15599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
15699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    LOGI("Register Map bit difference stats:\n");
15799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 0; i <= end; i++) {
15899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGI(" %2d %d\n", i, pStats->numDiffBits[i]);
15999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
16099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
16199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
16299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    LOGI("Register Map update position stats (lt16=%d ge16=%d):\n",
16399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pStats->updateLT16, pStats->updateGE16);
16499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 0; i < kNumUpdatePosns; i++) {
16599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGI(" %2d %d\n", i, pStats->updatePosn[i]);
16699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
16799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
16899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
16999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
17099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
17199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
17299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
17399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *      Map generation
17499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
17599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Generate the register map for a method that has just been verified
179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * (i.e. we're doing this as part of verification).
180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * For type-precise determination we have all the data we need, so we
182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * just need to encode it in some clever fashion.
183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectRegisterMap* dvmGenerateRegisterMapV(VerifierData* vdata)
187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
188d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    static const int kHeaderSize = offsetof(RegisterMap, data);
189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    RegisterMap* pMap = NULL;
190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    RegisterMap* pResult = NULL;
191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    RegisterMapFormat format;
192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u1 regWidth;
193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u1* mapData;
194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int i, bytesForAddr, gcPointCount;
195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int bufSize;
196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
19799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (vdata->method->registersSize >= 2048) {
19899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGE("ERROR: register map can't handle %d registers\n",
19999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            vdata->method->registersSize);
20099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        goto bail;
20199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    regWidth = (vdata->method->registersSize + 7) / 8;
20399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
204d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
205d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Decide if we need 8 or 16 bits to hold the address.  Strictly speaking
206d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * we only need 16 bits if we actually encode an address >= 256 -- if
207d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * the method has a section at the end without GC points (e.g. array
208d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * data) we don't need to count it.  The situation is unusual, and
209d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * detecting it requires scanning the entire method, so we don't bother.
210d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (vdata->insnsSize < 256) {
21299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        format = kRegMapFormatCompact8;
213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bytesForAddr = 1;
214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
21599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        format = kRegMapFormatCompact16;
216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bytesForAddr = 2;
217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Count up the number of GC point instructions.
221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * NOTE: this does not automatically include the first instruction,
223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * since we don't count method entry as a GC point.
224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    gcPointCount = 0;
226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (i = 0; i < vdata->insnsSize; i++) {
227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmInsnIsGcPoint(vdata->insnFlags, i))
228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gcPointCount++;
229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcPointCount >= 65536) {
231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* we could handle this, but in practice we don't get near this */
232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGE("ERROR: register map can't handle %d gc points in one method\n",
233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gcPointCount);
234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Allocate a buffer to hold the map data.
239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
240d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    bufSize = kHeaderSize + gcPointCount * (bytesForAddr + regWidth);
241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
24299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    LOGV("+++ grm: %s.%s (adr=%d gpc=%d rwd=%d bsz=%d)\n",
243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        vdata->method->clazz->descriptor, vdata->method->name,
244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bytesForAddr, gcPointCount, regWidth, bufSize);
245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap = (RegisterMap*) malloc(bufSize);
247d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetFormat(pMap, format);
248d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetOnHeap(pMap, true);
249d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetRegWidth(pMap, regWidth);
25099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    dvmRegisterMapSetNumEntries(pMap, gcPointCount);
251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Populate it.
254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    mapData = pMap->data;
256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (i = 0; i < vdata->insnsSize; i++) {
257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmInsnIsGcPoint(vdata->insnFlags, i)) {
258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            assert(vdata->addrRegs[i] != NULL);
25999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (format == kRegMapFormatCompact8) {
260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *mapData++ = i;
26199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else /*kRegMapFormatCompact16*/ {
262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *mapData++ = i & 0xff;
263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                *mapData++ = i >> 8;
264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            outputTypeVector(vdata->addrRegs[i], vdata->insnRegCount, mapData);
266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            mapData += regWidth;
267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
27099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    LOGV("mapData=%p pMap=%p bufSize=%d\n", mapData, pMap, bufSize);
271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(mapData - (const u1*) pMap == bufSize);
272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
273a66a01ad2a9e5c6aefc93d12a5c18d6bba570a3eAndy McFadden    if (REGISTER_MAP_VERIFY && !verifyMap(vdata, pMap))
274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
27599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
27699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    computeMapStats(pMap, vdata->method);
27799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2791d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    /*
2801d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * Try to compress the map.
2811d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     */
2821d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    RegisterMap* pCompMap;
283d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
2841d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    pCompMap = compressMapDifferential(pMap, vdata->method);
2851d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (pCompMap != NULL) {
2861d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (REGISTER_MAP_VERIFY) {
2871d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /*
2881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             * Expand the compressed map we just created, and compare it
2891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             * to the original.  Abort the VM if it doesn't match up.
2901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             */
2911d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            RegisterMap* pUncompMap;
292d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            pUncompMap = uncompressMapDifferential(pCompMap);
293d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            if (pUncompMap == NULL) {
2941d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                LOGE("Map failed to uncompress - %s.%s\n",
2951d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    vdata->method->clazz->descriptor,
2961d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    vdata->method->name);
297d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                free(pCompMap);
2981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* bad - compression is broken or we're out of memory */
2991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                dvmAbort();
300d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            } else {
301d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                if (compareMaps(pMap, pUncompMap) != 0) {
3021d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    LOGE("Map comparison failed - %s.%s\n",
303d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                        vdata->method->clazz->descriptor,
304d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                        vdata->method->name);
3051d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    free(pCompMap);
3061d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    /* bad - compression is broken */
3071d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    dvmAbort();
308d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                }
309d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
3101d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* verify succeeded */
311d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                free(pUncompMap);
312d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            }
313d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
3141d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
3151d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (REGISTER_MAP_VERBOSE) {
3161d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            LOGD("Good compress on %s.%s\n",
3171d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                vdata->method->clazz->descriptor,
3181d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                vdata->method->name);
3191d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
3201d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        free(pMap);
3211d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        pMap = pCompMap;
3221d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    } else {
3231d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (REGISTER_MAP_VERBOSE) {
3241d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            LOGD("Unable to compress %s.%s (ent=%d rw=%d)\n",
3251d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                vdata->method->clazz->descriptor,
3261d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                vdata->method->name,
3271d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                dvmRegisterMapGetNumEntries(pMap),
3281d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                dvmRegisterMapGetRegWidth(pMap));
3291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
330d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
331d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pResult = pMap;
333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return pResult;
336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release the storage held by a RegisterMap.
340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmFreeRegisterMap(RegisterMap* pMap)
342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pMap == NULL)
344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
346d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    assert(dvmRegisterMapGetOnHeap(pMap));
347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    free(pMap);
348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Determine if the RegType value is a reference type.
352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Ordinarily we include kRegTypeZero in the "is it a reference"
354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * check.  There's no value in doing so here, because we know
355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the register can't hold anything but zero.
356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline bool isReferenceType(RegType type)
358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return (type > kRegTypeMAX || type == kRegTypeUninit);
360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Given a line of registers, output a bit vector that indicates whether
364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * or not the register holds a reference type (which could be null).
365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We use '1' to indicate it's a reference, '0' for anything else (numeric
367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * value, uninitialized data, merge conflict).  Register 0 will be found
368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * in the low bit of the first byte.
369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void outputTypeVector(const RegType* regs, int insnRegCount, u1* data)
371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    u1 val = 0;
373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int i;
374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (i = 0; i < insnRegCount; i++) {
376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        RegType type = *regs++;
377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        val >>= 1;
378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (isReferenceType(type))
379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            val |= 0x80;        /* set hi bit */
380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((i & 0x07) == 7)
382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *data++ = val;
383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((i & 0x07) != 0) {
385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* flush bits from last byte */
386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        val >>= 8 - (i & 0x07);
387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *data++ = val;
388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
3921d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Print the map as a series of binary strings.
3931d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
3941d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Pass in method->registersSize if known, or -1 if not.
3951d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden */
3961d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFaddenstatic void dumpRegisterMap(const RegisterMap* pMap, int registersSize)
3971d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden{
3981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const u1* rawMap = pMap->data;
3991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const RegisterMapFormat format = dvmRegisterMapGetFormat(pMap);
4001d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const int numEntries = dvmRegisterMapGetNumEntries(pMap);
4011d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const int regWidth = dvmRegisterMapGetRegWidth(pMap);
4021d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int addrWidth;
4031d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4041d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    switch (format) {
4051d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    case kRegMapFormatCompact8:
4061d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        addrWidth = 1;
4071d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        break;
4081d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    case kRegMapFormatCompact16:
4091d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        addrWidth = 2;
4101d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        break;
4111d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    default:
4121d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        /* can't happen */
4131d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        LOGE("Can only dump Compact8 / Compact16 maps (not %d)\n", format);
4141d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        return;
4151d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
4161d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4171d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (registersSize < 0)
4181d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        registersSize = 8 * regWidth;
4191d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    assert(registersSize <= regWidth * 8);
4201d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4211d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int ent;
4221d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    for (ent = 0; ent < numEntries; ent++) {
4231d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        int i, addr;
4241d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4251d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        addr = *rawMap++;
4261d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (addrWidth > 1)
4271d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            addr |= (*rawMap++) << 8;
4281d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        const u1* dataStart = rawMap;
4301d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        u1 val = 0;
4311d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        /* create binary string */
4331d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        char outBuf[registersSize +1];
4341d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        for (i = 0; i < registersSize; i++) {
4351d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            val >>= 1;
4361d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if ((i & 0x07) == 0)
4371d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                val = *rawMap++;
4381d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4391d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            outBuf[i] = '0' + (val & 0x01);
4401d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
4411d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        outBuf[i] = '\0';
4421d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4431d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        /* back up and create hex dump */
4441d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        char hexBuf[regWidth * 3 +1];
4451d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        char* cp = hexBuf;
4461d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        rawMap = dataStart;
4471d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        for (i = 0; i < regWidth; i++) {
4481d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            sprintf(cp, " %02x", *rawMap++);
4491d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            cp += 3;
4501d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
4511d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        hexBuf[i * 3] = '\0';
4521d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        LOGD("  %04x %s %s\n", addr, outBuf, hexBuf);
4541d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
4551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden}
4561d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
4571d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/*
458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Double-check the map.
459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We run through all of the data in the map, and compare it to the original.
46199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Only works on uncompressed data.
462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool verifyMap(VerifierData* vdata, const RegisterMap* pMap)
464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
46599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const u1* rawMap = pMap->data;
4661d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const RegisterMapFormat format = dvmRegisterMapGetFormat(pMap);
4671d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    const int numEntries = dvmRegisterMapGetNumEntries(pMap);
468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int ent;
46999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    bool dumpMap = false;
47099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
47199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (false) {
47299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const char* cd = "Landroid/net/http/Request;";
47399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const char* mn = "readResponse";
47499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const char* sg = "(Landroid/net/http/AndroidHttpClientConnection;)V";
47599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (strcmp(vdata->method->clazz->descriptor, cd) == 0 &&
47699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            strcmp(vdata->method->name, mn) == 0)
47799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        {
47899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            char* desc;
47999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            desc = dexProtoCopyMethodDescriptor(&vdata->method->prototype);
48099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            LOGI("Map for %s.%s %s\n", vdata->method->clazz->descriptor,
48199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                vdata->method->name, desc);
48299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            free(desc);
48399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
48499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            dumpMap = true;
48599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
48699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
48899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if ((vdata->method->registersSize + 7) / 8 != pMap->regWidth) {
48999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGE("GLITCH: registersSize=%d, regWidth=%d\n",
49099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            vdata->method->registersSize, pMap->regWidth);
49199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return false;
49299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
49399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
49499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (ent = 0; ent < numEntries; ent++) {
495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int addr;
496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
49799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        switch (format) {
49899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        case kRegMapFormatCompact8:
49999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr = *rawMap++;
500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
50199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        case kRegMapFormatCompact16:
50299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr = *rawMap++;
50399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr |= (*rawMap++) << 8;
504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        default:
506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* shouldn't happen */
50799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            LOGE("GLITCH: bad format (%d)", format);
508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmAbort();
509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
51199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const u1* dataStart = rawMap;
512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const RegType* regs = vdata->addrRegs[addr];
513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (regs == NULL) {
514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGE("GLITCH: addr %d has no data\n", addr);
515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
51899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        u1 val = 0;
519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int i;
520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (i = 0; i < vdata->method->registersSize; i++) {
522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bool bitIsRef, regIsRef;
523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            val >>= 1;
525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if ((i & 0x07) == 0) {
526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* load next byte of data */
52799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                val = *rawMap++;
528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            bitIsRef = val & 0x01;
531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            RegType type = regs[i];
533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            regIsRef = isReferenceType(type);
534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (bitIsRef != regIsRef) {
536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                LOGE("GLITCH: addr %d reg %d: bit=%d reg=%d(%d)\n",
537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    addr, i, bitIsRef, regIsRef, type);
538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return false;
539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
54299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /* rawMap now points to the address field of the next entry */
54399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
54499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
5451d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (dumpMap)
5461d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        dumpRegisterMap(pMap, vdata->method->registersSize);
5471d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
54899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return true;
54999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
55099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
55199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
55299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
55399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
55499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *      DEX generation & parsing
55599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
55699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
55799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
55899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
55999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Advance "ptr" to ensure 32-bit alignment.
56099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
56199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic inline u1* align32(u1* ptr)
56299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
56399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return (u1*) (((int) ptr + 3) & ~0x03);
56499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
56599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
56699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
56799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Compute the size, in bytes, of a register map.
56899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
56999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic size_t computeRegisterMapSize(const RegisterMap* pMap)
57099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
57199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    static const int kHeaderSize = offsetof(RegisterMap, data);
572d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1 format = dvmRegisterMapGetFormat(pMap);
57399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
57499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
57599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(pMap != NULL);
57699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
57799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    switch (format) {
57899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatNone:
57999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return 1;
58099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatCompact8:
58199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return kHeaderSize + (1 + pMap->regWidth) * numEntries;
58299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatCompact16:
58399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return kHeaderSize + (2 + pMap->regWidth) * numEntries;
584d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatDifferential:
585d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        {
586d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            /* kHeaderSize + decoded ULEB128 length */
587d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            const u1* ptr = pMap->data;
588d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            int len = readUnsignedLeb128(&ptr);
589d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            return len + (ptr - (u1*) pMap);
590d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
59199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    default:
59299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGE("Bad register map format %d\n", format);
59399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
59499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return 0;
59599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
59699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
59799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
59899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
59999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Output the map for a single method, if it has one.
60099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
60199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Abstract and native methods have no map.  All others are expected to
60299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * have one, since we know the class verified successfully.
60399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
60499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * This strips the "allocated on heap" flag from the format byte, so that
60599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * direct-mapped maps are correctly identified as such.
60699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
60799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic bool writeMapForMethod(const Method* meth, u1** pPtr)
60899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
60999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (meth->registerMap == NULL) {
61099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (!dvmIsAbstractMethod(meth) && !dvmIsNativeMethod(meth)) {
61199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            LOGW("Warning: no map available for %s.%s\n",
61299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                meth->clazz->descriptor, meth->name);
61399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            /* weird, but keep going */
61499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
61599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        *(*pPtr)++ = kRegMapFormatNone;
61699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return true;
61799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
61899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
61999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /* serialize map into the buffer */
62099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    size_t mapSize = computeRegisterMapSize(meth->registerMap);
62199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    memcpy(*pPtr, meth->registerMap, mapSize);
62299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
62399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /* strip the "on heap" flag out of the format byte, which is always first */
62499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(**pPtr == meth->registerMap->format);
62599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    **pPtr &= ~(kRegMapFormatOnHeap);
62699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
62799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    *pPtr += mapSize;
62899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
62999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return true;
63099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
63199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
63299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
63399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Write maps for all methods in the specified class to the buffer, which
63499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * can hold at most "length" bytes.  "*pPtr" will be advanced past the end
63599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * of the data we write.
63699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
63799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic bool writeMapsAllMethods(DvmDex* pDvmDex, const ClassObject* clazz,
63899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u1** pPtr, size_t length)
63999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
64099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    RegisterMapMethodPool* pMethodPool;
64199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u1* ptr = *pPtr;
64299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int i, methodCount;
64399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
64499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /* artificial limit */
64599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (clazz->virtualMethodCount + clazz->directMethodCount >= 65536) {
64699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGE("Too many methods in %s\n", clazz->descriptor);
64799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return false;
64899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
64999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
65099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pMethodPool = (RegisterMapMethodPool*) ptr;
65199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    ptr += offsetof(RegisterMapMethodPool, methodData);
65299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    methodCount = 0;
65399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
65499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
65599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Run through all methods, direct then virtual.  The class loader will
65699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * traverse them in the same order.  (We could split them into two
65799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * distinct pieces, but there doesn't appear to be any value in doing
65899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * so other than that it makes class loading slightly less fragile.)
65999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *
66099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * The class loader won't know about miranda methods at the point
66199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * where it parses this, so we omit those.
66299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *
66399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * TODO: consider omitting all native/abstract definitions.  Should be
66499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * safe, though we lose the ability to sanity-check against the
66599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * method counts in the DEX file.
66699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
66799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 0; i < clazz->directMethodCount; i++) {
66899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const Method* meth = &clazz->directMethods[i];
66999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (dvmIsMirandaMethod(meth))
67099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            continue;
67199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (!writeMapForMethod(&clazz->directMethods[i], &ptr)) {
67299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            return false;
67399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
67499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        methodCount++;
67599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        //ptr = align32(ptr);
67699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
67799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
67899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (i = 0; i < clazz->virtualMethodCount; i++) {
67999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const Method* meth = &clazz->virtualMethods[i];
68099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (dvmIsMirandaMethod(meth))
68199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            continue;
68299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (!writeMapForMethod(&clazz->virtualMethods[i], &ptr)) {
68399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            return false;
684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
68599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        methodCount++;
68699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        //ptr = align32(ptr);
687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
68999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pMethodPool->methodCount = methodCount;
69099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
69199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    *pPtr = ptr;
692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
69599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
69699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Write maps for all classes to the specified buffer, which can hold at
69799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * most "length" bytes.
69899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
69999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Returns the actual length used, or 0 on failure.
70099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
70199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic size_t writeMapsAllClasses(DvmDex* pDvmDex, u1* basePtr, size_t length)
70299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
70399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    DexFile* pDexFile = pDvmDex->pDexFile;
70499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4 count = pDexFile->pHeader->classDefsSize;
70599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    RegisterMapClassPool* pClassPool;
70699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4* offsetTable;
70799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u1* ptr = basePtr;
70899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4 idx;
70999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
71099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(gDvm.optimizing);
71199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
71299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pClassPool = (RegisterMapClassPool*) ptr;
71399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    ptr += offsetof(RegisterMapClassPool, classDataOffset);
71499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    offsetTable = (u4*) ptr;
71599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    ptr += count * sizeof(u4);
71699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
71799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pClassPool->numClasses = count;
71899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
71999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
72099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * We want an entry for every class, loaded or not.
72199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
72299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (idx = 0; idx < count; idx++) {
72399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const DexClassDef* pClassDef;
72499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const char* classDescriptor;
72599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        ClassObject* clazz;
72699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
72799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pClassDef = dexGetClassDef(pDexFile, idx);
72899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
72999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
73099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /*
73199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * All classes have been loaded into the bootstrap class loader.
73299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * If we can find it, and it was successfully pre-verified, we
73399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * run through its methods and add the register maps.
73499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         *
73599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * If it wasn't pre-verified then we know it can't have any
73699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * register maps.  Classes that can't be loaded or failed
73799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * verification get an empty slot in the index.
73899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         */
73999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        clazz = NULL;
74099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if ((pClassDef->accessFlags & CLASS_ISPREVERIFIED) != 0)
74199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            clazz = dvmLookupClass(classDescriptor, NULL, false);
74299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
74399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (clazz != NULL) {
74499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            offsetTable[idx] = ptr - basePtr;
74599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            LOGVV("%d -> offset %d (%p-%p)\n",
74699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                idx, offsetTable[idx], ptr, basePtr);
74799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
74899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (!writeMapsAllMethods(pDvmDex, clazz, &ptr,
74999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                    length - (ptr - basePtr)))
75099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            {
75199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                return 0;
75299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
75399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
75499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            ptr = align32(ptr);
75599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            LOGVV("Size %s (%d+%d methods): %d\n", clazz->descriptor,
75699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                clazz->directMethodCount, clazz->virtualMethodCount,
75799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                (ptr - basePtr) - offsetTable[idx]);
75899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        } else {
75999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            LOGV("%4d NOT mapadding '%s'\n", idx, classDescriptor);
76099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            assert(offsetTable[idx] == 0);
76199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
76299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
76399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
76499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (ptr - basePtr >= (int)length) {
76599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /* a bit late */
76699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGE("Buffer overrun\n");
76799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
76899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
76999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
77099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return ptr - basePtr;
77199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
77299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
77399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
77499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Generate a register map set for all verified classes in "pDvmDex".
77599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
77699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectRegisterMapBuilder* dvmGenerateRegisterMaps(DvmDex* pDvmDex)
77799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
77899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    RegisterMapBuilder* pBuilder;
77999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
78099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pBuilder = (RegisterMapBuilder*) calloc(1, sizeof(RegisterMapBuilder));
78199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (pBuilder == NULL)
78299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
78399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
78499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
78599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * We have a couple of options here:
78699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *  (1) Compute the size of the output, and malloc a buffer.
78799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *  (2) Create a "large-enough" anonymous mmap region.
78899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *
78999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * The nice thing about option #2 is that we don't have to traverse
79099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * all of the classes and methods twice.  The risk is that we might
79199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * not make the region large enough.  Since the pages aren't mapped
79299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * until used we can allocate a semi-absurd amount of memory without
79399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * worrying about the effect on the rest of the system.
79499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     *
79599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * The basic encoding on the largest jar file requires about 1MB of
79699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * storage.  We map out 4MB here.  (TODO: guarantee that the last
79799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * page of the mapping is marked invalid, so we reliably fail if
79899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * we overrun.)
79999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
80099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (sysCreatePrivateMap(4 * 1024 * 1024, &pBuilder->memMap) != 0) {
80199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        free(pBuilder);
80299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
80399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
80499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
80599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
80699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Create the maps.
80799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
80899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    size_t actual = writeMapsAllClasses(pDvmDex, (u1*)pBuilder->memMap.addr,
80999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                                        pBuilder->memMap.length);
81099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (actual == 0) {
81199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmFreeRegisterMapBuilder(pBuilder);
81299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
81399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
81499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
815f5f370ef5005db7f9af092d6d813c408090c15b4Andy McFadden    LOGV("TOTAL size of register maps: %d\n", actual);
81699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
81799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pBuilder->data = pBuilder->memMap.addr;
81899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pBuilder->size = actual;
81999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return pBuilder;
82099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
82199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
82299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
82399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Free the builder.
82499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
82599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectvoid dvmFreeRegisterMapBuilder(RegisterMapBuilder* pBuilder)
82699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
82799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (pBuilder == NULL)
82899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return;
82999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
83099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    sysReleaseShmem(&pBuilder->memMap);
83199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    free(pBuilder);
83299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
83399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
83499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
83599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
83699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Find the data for the specified class.
83799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
83899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * If there's no register map data, or none for this class, we return NULL.
83999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
840d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenconst void* dvmRegisterMapGetClassData(const DexFile* pDexFile, u4 classIdx,
84199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4* pNumMaps)
84299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
84399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const RegisterMapClassPool* pClassPool;
84499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const RegisterMapMethodPool* pMethodPool;
84599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
84699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pClassPool = (const RegisterMapClassPool*) pDexFile->pRegisterMapPool;
84799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (pClassPool == NULL)
84899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
84999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
85099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (classIdx >= pClassPool->numClasses) {
85199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGE("bad class index (%d vs %d)\n", classIdx, pClassPool->numClasses);
85299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
85399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
85499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
85599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u4 classOffset = pClassPool->classDataOffset[classIdx];
85699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (classOffset == 0) {
85799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGV("+++ no map for classIdx=%d\n", classIdx);
85899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
85999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
86099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
86199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    pMethodPool =
86299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        (const RegisterMapMethodPool*) (((u1*) pClassPool) + classOffset);
86399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (pNumMaps != NULL)
86499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        *pNumMaps = pMethodPool->methodCount;
86599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return pMethodPool->methodData;
86699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
86799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
86899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
86999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * This advances "*pPtr" and returns its original value.
87099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
871d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenconst RegisterMap* dvmRegisterMapGetNext(const void** pPtr)
87299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
87399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const RegisterMap* pMap = *pPtr;
87499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
87599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    *pPtr = /*align32*/(((u1*) pMap) + computeRegisterMapSize(pMap));
87699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    LOGVV("getNext: %p -> %p (f=0x%x w=%d e=%d)\n",
87799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pMap, *pPtr, pMap->format, pMap->regWidth,
87899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmRegisterMapGetNumEntries(pMap));
87999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return pMap;
88099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
88199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
88299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
88399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
88499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
88599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *      Utility functions
88699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
88799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
88899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
88999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
89099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * Return the data for the specified address, or NULL if not found.
89199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *
89299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * The result must be released with dvmReleaseRegisterMapLine().
89399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
894d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenconst u1* dvmRegisterMapGetLine(const RegisterMap* pMap, int addr)
89599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
89699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int addrWidth, lineWidth;
897d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1 format = dvmRegisterMapGetFormat(pMap);
89899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
89999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
90099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    assert(numEntries > 0);
90199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
90299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    switch (format) {
90399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatNone:
90499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
90599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatCompact8:
90699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        addrWidth = 1;
90799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        break;
90899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    case kRegMapFormatCompact16:
90999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        addrWidth = 2;
91099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        break;
91199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    default:
91299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        LOGE("Unknown format %d\n", format);
91399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        dvmAbort();
91499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        return NULL;
91599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
91699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
91799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    lineWidth = addrWidth + pMap->regWidth;
91899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
91999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    /*
92099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * Find the appropriate entry.  Many maps are very small, some are very
92199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     * large.
92299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project     */
92399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    static const int kSearchThreshold = 8;
924734155efc18543eab20b763f9a315ab1a44240acAndy McFadden    const u1* data = NULL;
92599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int lineAddr;
92699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
92799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    if (numEntries < kSearchThreshold) {
92899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        int i;
92999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        data = pMap->data;
93099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        for (i = numEntries; i > 0; i--) {
93199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            lineAddr = data[0];
93299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (addrWidth > 1)
93399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                lineAddr |= data[1] << 8;
93499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (lineAddr == addr)
93599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                return data + addrWidth;
93699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
93799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            data += lineWidth;
93899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
939869898f16f414a63187cd736e375fe32aae41f0fAndy McFadden        assert(data == pMap->data + lineWidth * numEntries);
94099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    } else {
94199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        int hi, lo, mid;
94299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
94399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        lo = 0;
94499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        hi = numEntries -1;
94599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
94699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        while (hi >= lo) {
94799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            mid = (hi + lo) / 2;
94899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            data = pMap->data + lineWidth * mid;
94999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
95099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            lineAddr = data[0];
95199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (addrWidth > 1)
95299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                lineAddr |= data[1] << 8;
95399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
95499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (addr > lineAddr) {
95599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                lo = mid + 1;
95699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else if (addr < lineAddr) {
95799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                hi = mid - 1;
95899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else {
95999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                return data + addrWidth;
96099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
96199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
96299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
96399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
96499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    return NULL;
96599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
96699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
967d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden/*
968d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Compare two register maps.
969d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
970d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Returns 0 if they're equal, nonzero if not.
971d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden */
972d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2)
973d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden{
974d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    size_t size1, size2;
975d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
976d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    size1 = computeRegisterMapSize(pMap1);
977d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    size2 = computeRegisterMapSize(pMap2);
978d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (size1 != size2) {
979d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGI("compareMaps: size mismatch (%zd vs %zd)\n", size1, size2);
980d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return -1;
981d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
982d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
983d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (memcmp(pMap1, pMap2, size1) != 0) {
984d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGI("compareMaps: content mismatch\n");
985d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return -1;
986d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
987d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
988d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    return 0;
989d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden}
990d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
991d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
992d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden/*
993d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Get the expanded form of the register map associated with the method.
994d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
995d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * If the map is already in one of the uncompressed formats, we return
996d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * immediately.  Otherwise, we expand the map and replace method's register
997d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * map pointer, freeing it if it was allocated on the heap.
998d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
9999faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden * NOTE: this function is not synchronized; external locking is mandatory
10009faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden * (unless we're in the zygote, where single-threaded access is guaranteed).
1001d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden */
1002d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenconst RegisterMap* dvmGetExpandedRegisterMap0(Method* method)
1003d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden{
1004d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const RegisterMap* curMap = method->registerMap;
1005d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    RegisterMap* newMap;
1006d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1007d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (curMap == NULL)
1008d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return NULL;
1009d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1010d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /* sanity check to ensure this isn't called w/o external locking */
10119faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden    /* (if we use this at a time other than during GC, fix/remove this test) */
1012d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (true) {
1013980ffb0243a1840ad0a93cfa06dfc02ca6f2d01cCarl Shapiro        if (!gDvm.zygote && dvmTryLockMutex(&gDvm.gcHeapLock) == 0) {
1014d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            LOGE("GLITCH: dvmGetExpandedRegisterMap not called at GC time\n");
1015d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            dvmAbort();
1016d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1017d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1018d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1019d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    RegisterMapFormat format = dvmRegisterMapGetFormat(curMap);
1020d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    switch (format) {
1021d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatCompact8:
1022d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatCompact16:
10231d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (REGISTER_MAP_VERBOSE) {
10241d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (dvmRegisterMapGetOnHeap(curMap)) {
10251d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                LOGD("RegMap: already expanded: %s.%s\n",
10261d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    method->clazz->descriptor, method->name);
10271d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            } else {
10281d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                LOGD("RegMap: stored w/o compression: %s.%s\n",
10291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    method->clazz->descriptor, method->name);
10301d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            }
1031d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1032d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return curMap;
1033d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatDifferential:
1034d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newMap = uncompressMapDifferential(curMap);
1035d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        break;
1036d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    default:
1037d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGE("Unknown format %d in dvmGetExpandedRegisterMap\n", format);
1038d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        dvmAbort();
1039a915b67335c1ffd78927eecd7023fc3d08e3e93fAndy McFadden        newMap = NULL;      // make gcc happy
1040d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1041d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1042d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (newMap == NULL) {
1043d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGE("Map failed to uncompress (fmt=%d) %s.%s\n",
1044d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            format, method->clazz->descriptor, method->name);
1045d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        return NULL;
1046d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1047d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
10481d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden#ifdef REGISTER_MAP_STATS
10491d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    /*
10501d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * Gather and display some stats.
10511d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     */
10521d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    {
10531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        MapStats* pStats = (MapStats*) gDvm.registerMapStats;
10541d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        pStats->numExpandedMaps++;
10551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        pStats->totalExpandedMapSize += computeRegisterMapSize(newMap);
10561d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        LOGD("RMAP: count=%d size=%d\n",
10571d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            pStats->numExpandedMaps, pStats->totalExpandedMapSize);
10581d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
10591d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden#endif
10601d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
10619faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden    IF_LOGV() {
10629faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden        char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
10639faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden        LOGV("Expanding map -> %s.%s:%s\n",
10649faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden            method->clazz->descriptor, method->name, desc);
10659faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden        free(desc);
10669faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden    }
10679faa9e6a7df9a5b9ef7c8e9d5c07d2a050c319d3Andy McFadden
1068d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1069d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Update method, and free compressed map if it was sitting on the heap.
1070d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1071d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmSetRegisterMap(method, newMap);
1072d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1073d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (dvmRegisterMapGetOnHeap(curMap))
1074d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        dvmFreeRegisterMap((RegisterMap*) curMap);
1075d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1076d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    return newMap;
1077d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden}
1078d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
107999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
108099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
108199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
108299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project *      Map compression
108399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project * ===========================================================================
108499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
108599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
108699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
108799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectNotes on map compression
108899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
108999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectThe idea is to create a compressed form that will be uncompressed before
109099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectuse, with the output possibly saved in a cache.  This means we can use an
109199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectapproach that is unsuited for random access if we choose.
109299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
109399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectIn the event that a map simply does not work with our compression scheme,
109499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectit's reasonable to store the map without compression.  In the future we
109599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectmay want to have more than one compression scheme, and try each in turn,
109699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectretaining the best.  (We certainly want to keep the uncompressed form if it
109799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectturns out to be smaller or even slightly larger than the compressed form.)
109899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
109999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectEach entry consists of an address and a bit vector.  Adjacent entries are
110099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstrongly correlated, suggesting differential encoding.
110199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
110299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
110399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectIdeally we would avoid outputting adjacent entries with identical
110499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectbit vectors.  However, the register values at a given address do not
110599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectimply anything about the set of valid registers at subsequent addresses.
110699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectWe therefore cannot omit an entry.
110799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
110899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  If the thread stack has a PC at an address without a corresponding
110999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  entry in the register map, we must conservatively scan the registers in
111099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  that thread.  This can happen when single-stepping in the debugger,
111199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  because the debugger is allowed to invoke arbitrary methods when
111299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  a thread is stopped at a breakpoint.  If we can guarantee that a GC
111399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  thread scan will never happen while the debugger has that thread stopped,
111499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  then we can lift this restriction and simply omit entries that don't
111599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  change the bit vector from its previous state.
111699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
111799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectEach entry advances the address value by at least 1 (measured in 16-bit
111899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project"code units").  Looking at the bootclasspath entries, advancing by 2 units
111999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectis most common.  Advances by 1 unit are far less common than advances by
112099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project2 units, but more common than 5, and things fall off rapidly.  Gaps of
112199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectup to 220 code units appear in some computationally intensive bits of code,
112299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectbut are exceedingly rare.
112399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
112499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectIf we sum up the number of transitions in a couple of ranges in framework.jar:
112599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  [1,4]: 188998 of 218922 gaps (86.3%)
112699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  [1,7]: 211647 of 218922 gaps (96.7%)
112799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectUsing a 3-bit delta, with one value reserved as an escape code, should
112899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectyield good results for the address.
112999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
113099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectThese results would change dramatically if we reduced the set of GC
113199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectpoints by e.g. removing instructions like integer divide that are only
113299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectpresent because they can throw and cause an allocation.
113399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
113499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectWe also need to include an "initial gap", because the first few instructions
113599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectin a method may not be GC points.
113699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
113799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
113899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectBy observation, many entries simply repeat the previous bit vector, or
113999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectchange only one or two bits.  (This is with type-precise information;
114099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectthe rate of change of bits will be different if live-precise information
114199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectis factored in).
114299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
114399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectLooking again at adjacent entries in framework.jar:
114499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  0 bits changed: 63.0%
114599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  1 bit changed: 32.2%
114699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectAfter that it falls off rapidly, e.g. the number of entries with 2 bits
114799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectchanged is usually less than 1/10th of the number of entries with 1 bit
114899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectchanged.  A solution that allows us to encode 0- or 1- bit changes
114999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectefficiently will do well.
115099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
115199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectWe still need to handle cases where a large number of bits change.  We
115299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectprobably want a way to drop in a full copy of the bit vector when it's
115399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectsmaller than the representation of multiple bit changes.
115499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
115599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
115699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectThe bit-change information can be encoded as an index that tells the
115799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectdecoder to toggle the state.  We want to encode the index in as few bits
115899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectas possible, but we need to allow for fairly wide vectors (e.g. we have a
115999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectmethod with 175 registers).  We can deal with this in a couple of ways:
116099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project(1) use an encoding that assumes few registers and has an escape code
116199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectfor larger numbers of registers; or (2) use different encodings based
116299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projecton how many total registers the method has.  The choice depends to some
116399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectextent on whether methods with large numbers of registers tend to modify
116499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectthe first 16 regs more often than the others.
116599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
116699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectThe last N registers hold method arguments.  If the bytecode is expected
116799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectto be examined in a debugger, "dx" ensures that the contents of these
116899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectregisters won't change.  Depending upon the encoding format, we may be
116999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectable to take advantage of this.  We still have to encode the initial
117099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstate, but we know we'll never have to output a bit change for the last
117199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectN registers.
117299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
117399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectConsidering only methods with 16 or more registers, the "target octant"
117499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectfor register changes looks like this:
117599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project  [ 43.1%, 16.4%, 6.5%, 6.2%, 7.4%, 8.8%, 9.7%, 1.8% ]
117699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectAs expected, there are fewer changes at the end of the list where the
117799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectarguments are kept, and more changes at the start of the list because
117899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectregister values smaller than 16 can be used in compact Dalvik instructions
117999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectand hence are favored for frequently-used values.  In general, the first
118099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectoctant is considerably more active than later entries, the last octant
118199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectis much less active, and the rest are all about the same.
118299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
118399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectLooking at all bit changes in all methods, 94% are to registers 0-15.  The
118499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectencoding will benefit greatly by favoring the low-numbered registers.
118599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
118699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
118799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectSome of the smaller methods have identical maps, and space could be
118899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectsaved by simply including a pointer to an earlier definition.  This would
118999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectbe best accomplished by specifying a "pointer" format value, followed by
119099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projecta 3-byte (or ULEB128) offset.  Implementing this would probably involve
119199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectgenerating a hash value for each register map and maintaining a hash table.
119299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
119399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source ProjectIn some cases there are repeating patterns in the bit vector that aren't
119499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectadjacent.  These could benefit from a dictionary encoding.  This doesn't
119599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectreally become useful until the methods reach a certain size though,
119699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectand managing the dictionary may incur more overhead than we want.
1197d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1198d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenLarge maps can be compressed significantly.  The trouble is that, when
1199d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenwe need to use them, we have to uncompress them onto the heap.  We may
1200d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenget a better trade-off between storage size and heap usage by refusing to
1201d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddencompress large maps, so that they can be memory mapped and used directly.
1202d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden(OTOH, only about 2% of the maps will ever actually be used.)
1203d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1204d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1205d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden----- differential format -----
1206d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1207d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden// common header
1208d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+00 1B format
1209d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+01 1B regWidth
1210d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+02 2B numEntries (little-endian)
1211d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+04 nB length in bytes of the data that follows, in ULEB128 format
1212d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden       (not strictly necessary; allows determination of size w/o full parse)
1213d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+05+ 1B initial address (0-127), high bit set if max addr >= 256
1214d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+06+ nB initial value for bit vector
1215d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1216d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden// for each entry
1217d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+00: CCCCBAAA
1218d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1219d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  AAA: address difference.  Values from 0 to 6 indicate an increment of 1
1220d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  to 7.  A value of 7 indicates that the address difference is large,
1221d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  and the next byte is a ULEB128-encoded difference value.
1222d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1223d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  B: determines the meaning of CCCC.
1224d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
12251d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden  CCCC: if B is 0, this is the number of the bit to toggle (0-15).
12261d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden  If B is 1, this is a count of the number of changed bits (1-14).  A value
12271d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden  of 0 means that no bits were changed, and a value of 15 indicates
1228d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  that enough bits were changed that it required less space to output
1229d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  the entire bit vector.
1230d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1231d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+01: (optional) ULEB128-encoded address difference
1232d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1233d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden+01+: (optional) one or more ULEB128-encoded bit numbers, OR the entire
1234d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden  bit vector.
1235d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1236d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenThe most common situation is an entry whose address has changed by 2-4
1237d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddencode units, has no changes or just a single bit change, and the changed
1238d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenregister is less than 16.  We should therefore be able to encode a large
1239d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddennumber of entries with a single byte, which is half the size of the
1240d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenCompact8 encoding method.
124199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project*/
124299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
124399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project/*
1244d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Compute some stats on an uncompressed register map.
124599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project */
124699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Projectstatic void computeMapStats(RegisterMap* pMap, const Method* method)
124799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project{
124899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#ifdef REGISTER_MAP_STATS
124999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    MapStats* pStats = (MapStats*) gDvm.registerMapStats;
1250d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1 format = dvmRegisterMapGetFormat(pMap);
125199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
125299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const u1* rawMap = pMap->data;
125399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    const u1* prevData = NULL;
125499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    int ent, addr, prevAddr = -1;
125599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
125699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    for (ent = 0; ent < numEntries; ent++) {
125799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        switch (format) {
125899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        case kRegMapFormatCompact8:
125999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr = *rawMap++;
126099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            break;
126199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        case kRegMapFormatCompact16:
126299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr = *rawMap++;
126399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            addr |= (*rawMap++) << 8;
126499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            break;
126599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        default:
126699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            /* shouldn't happen */
126799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            LOGE("GLITCH: bad format (%d)", format);
126899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            dvmAbort();
126999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
127099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
127199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        const u1* dataStart = rawMap;
127299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
127399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        pStats->totalGcPointCount++;
127499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
127599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /*
127699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * Gather "gap size" stats, i.e. the difference in addresses between
127799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         * successive GC points.
127899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project         */
127999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        if (prevData != NULL) {
128099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            assert(prevAddr >= 0);
128199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            int addrDiff = addr - prevAddr;
128299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
128399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (addrDiff < 0) {
128499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                LOGE("GLITCH: address went backward (0x%04x->0x%04x, %s.%s)\n",
128599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                    prevAddr, addr, method->clazz->descriptor, method->name);
128699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else if (addrDiff > kMaxGcPointGap) {
12871d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                if (REGISTER_MAP_VERBOSE) {
12881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    LOGI("HEY: addrDiff is %d, max %d (0x%04x->0x%04x %s.%s)\n",
12891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        addrDiff, kMaxGcPointGap, prevAddr, addr,
12901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        method->clazz->descriptor, method->name);
12911d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                }
129299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                /* skip this one */
129399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else {
129499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                pStats->gcPointGap[addrDiff]++;
129599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
129699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            pStats->gcGapCount++;
129799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
129899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
129999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            /*
130099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * Compare bit vectors in adjacent entries.  We want to count
130199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * up the number of bits that differ (to see if we frequently
130299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * change 0 or 1 bits) and get a sense for which part of the
130399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * vector changes the most often (near the start, middle, end).
130499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             *
130599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * We only do the vector position quantization if we have at
130699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             * least 16 registers in the method.
130799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project             */
130899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            int numDiff = 0;
130999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            float div = (float) kNumUpdatePosns / method->registersSize;
131099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            int regByte;
131199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            for (regByte = 0; regByte < pMap->regWidth; regByte++) {
131299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                int prev, cur, bit;
131399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
131499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                prev = prevData[regByte];
131599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                cur = dataStart[regByte];
131699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
131799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                for (bit = 0; bit < 8; bit++) {
131899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                    if (((prev >> bit) & 1) != ((cur >> bit) & 1)) {
131999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        numDiff++;
132099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
132199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        int bitNum = regByte * 8 + bit;
132299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
132399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        if (bitNum < 16)
132499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            pStats->updateLT16++;
132599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        else
132699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            pStats->updateGE16++;
132799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
132899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        if (method->registersSize < 16)
132999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            continue;
133099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
133199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        if (bitNum >= method->registersSize) {
133299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            /* stuff off the end should be zero in both */
133399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            LOGE("WEIRD: bit=%d (%d/%d), prev=%02x cur=%02x\n",
133499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                                bit, regByte, method->registersSize,
133599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                                prev, cur);
133699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            assert(false);
133799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        }
133899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        int idx = (int) (bitNum * div);
133999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        if (!(idx >= 0 && idx < kNumUpdatePosns)) {
134099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            LOGE("FAIL: bitNum=%d (of %d) div=%.3f idx=%d\n",
134199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                                bitNum, method->registersSize, div, idx);
134299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                            assert(false);
134399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        }
134499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                        pStats->updatePosn[idx]++;
134599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                    }
134699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                }
134799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
134899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
134999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            if (numDiff > kMaxDiffBits) {
13501d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                if (REGISTER_MAP_VERBOSE) {
13511d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    LOGI("WOW: numDiff is %d, max %d\n", numDiff, kMaxDiffBits);
13521d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                }
135399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            } else {
135499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project                pStats->numDiffBits[numDiff]++;
135599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project            }
135699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        }
135799409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
135899409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        /* advance to start of next line */
135999409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        rawMap += pMap->regWidth;
136099409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
136199409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        prevAddr = addr;
136299409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project        prevData = dataStart;
136399409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project    }
136499409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project#endif
136599409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project}
136699409883d9c4c0ffb49b070ce307bb33a9dfe9f1The Android Open Source Project
1367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
13691d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Compute the difference between two bit vectors.
13701d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
13711d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * If "lebOutBuf" is non-NULL, we output the bit indices in ULEB128 format
13721d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * as we go.  Otherwise, we just generate the various counts.
13731d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
13741d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * The bit vectors are compared byte-by-byte, so any unused bits at the
13751d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * end must be zero.
13761d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
13771d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Returns the number of bytes required to hold the ULEB128 output.
13781d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
13791d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * If "pFirstBitChanged" or "pNumBitsChanged" are non-NULL, they will
13801d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * receive the index of the first changed bit and the number of changed
13811d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * bits, respectively.
13821d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden */
13831d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFaddenstatic int computeBitDiff(const u1* bits1, const u1* bits2, int byteWidth,
13841d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int* pFirstBitChanged, int* pNumBitsChanged, u1* lebOutBuf)
13851d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden{
13861d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int numBitsChanged = 0;
13871d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int firstBitChanged = -1;
13881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int lebSize = 0;
13891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    int byteNum;
13901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
13911d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    /*
13921d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * Run through the vectors, first comparing them at the byte level.  This
13931d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     * will yield a fairly quick result if nothing has changed between them.
13941d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden     */
13951d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    for (byteNum = 0; byteNum < byteWidth; byteNum++) {
13961d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        u1 byte1 = *bits1++;
13971d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        u1 byte2 = *bits2++;
13981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (byte1 != byte2) {
13991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /*
14001d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             * Walk through the byte, identifying the changed bits.
14011d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden             */
14021d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            int bitNum;
14031d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            for (bitNum = 0; bitNum < 8; bitNum++) {
14041d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                if (((byte1 >> bitNum) & 0x01) != ((byte2 >> bitNum) & 0x01)) {
14051d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    int bitOffset = (byteNum << 3) + bitNum;
14061d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14071d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    if (firstBitChanged < 0)
14081d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        firstBitChanged = bitOffset;
14091d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    numBitsChanged++;
14101d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14111d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    if (lebOutBuf == NULL) {
14121d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        lebSize += unsignedLeb128Size(bitOffset);
14131d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    } else {
14141d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        u1* curBuf = lebOutBuf;
14151d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        lebOutBuf = writeUnsignedLeb128(lebOutBuf, bitOffset);
14161d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                        lebSize += lebOutBuf - curBuf;
14171d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    }
14181d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                }
14191d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            }
14201d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
14211d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
14221d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14231d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (numBitsChanged > 0)
14241d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        assert(firstBitChanged >= 0);
14251d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14261d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (pFirstBitChanged != NULL)
14271d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        *pFirstBitChanged = firstBitChanged;
14281d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (pNumBitsChanged != NULL)
14291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        *pNumBitsChanged = numBitsChanged;
14301d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14311d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    return lebSize;
14321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden}
14331d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
14341d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/*
1435d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Compress the register map with differential encoding.
1436d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
1437d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * "meth" is only needed for debug output.
1438d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
1439d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * On success, returns a newly-allocated RegisterMap.  If the map is not
1440d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * compatible for some reason, or fails to get smaller, this will return NULL.
1441d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden */
1442d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic RegisterMap* compressMapDifferential(const RegisterMap* pMap,
1443d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const Method* meth)
1444d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden{
1445d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    RegisterMap* pNewMap = NULL;
1446d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int origSize = computeRegisterMapSize(pMap);
1447d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1* tmpBuf = NULL;
1448d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1* tmpPtr;
1449d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int addrWidth, regWidth, numEntries;
1450d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    bool debug = false;
1451d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1452d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (false &&
14531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        strcmp(meth->clazz->descriptor, "Landroid/text/StaticLayout;") == 0 &&
14541d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        strcmp(meth->name, "generate") == 0)
1455d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    {
1456d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        debug = true;
1457d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1458d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1459d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1 format = dvmRegisterMapGetFormat(pMap);
1460d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    switch (format) {
1461d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatCompact8:
1462d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addrWidth = 1;
1463d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        break;
1464d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    case kRegMapFormatCompact16:
1465d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addrWidth = 2;
1466d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        break;
1467d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    default:
1468d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGE("ERROR: can't compress map with format=%d\n", format);
1469d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
1470d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1471d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1472d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    regWidth = dvmRegisterMapGetRegWidth(pMap);
1473d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    numEntries = dvmRegisterMapGetNumEntries(pMap);
1474d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1475d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (debug) {
1476d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGI("COMPRESS: %s.%s aw=%d rw=%d ne=%d\n",
1477d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            meth->clazz->descriptor, meth->name,
1478d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            addrWidth, regWidth, numEntries);
14791d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        dumpRegisterMap(pMap, -1);
1480d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1481d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1482d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (numEntries <= 1) {
1483d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGV("Can't compress map with 0 or 1 entries\n");
1484d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
1485d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1486d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1487d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1488d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * We don't know how large the compressed data will be.  It's possible
1489d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * for it to expand and become larger than the original.  The header
1490d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * itself is variable-sized, so we generate everything into a temporary
1491d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * buffer and then copy it to form-fitting storage once we know how big
1492d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * it will be (and that it's smaller than the original).
1493d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     *
1494d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * If we use a size that is equal to the size of the input map plus
1495d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * a value longer than a single entry can possibly expand to, we need
1496d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * only check for overflow at the end of each entry.  The worst case
1497d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * for a single line is (1 + <ULEB8 address> + <full copy of vector>).
1498d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Addresses are 16 bits, so that's (1 + 3 + regWidth).
1499d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     *
1500d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * The initial address offset and bit vector will take up less than
1501d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * or equal to the amount of space required when uncompressed -- large
1502d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * initial offsets are rejected.
1503d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1504d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    tmpBuf = (u1*) malloc(origSize + (1 + 3 + regWidth));
1505d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (tmpBuf == NULL)
1506d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
1507d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1508d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    tmpPtr = tmpBuf;
1509d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1510d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* mapData = pMap->data;
1511d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* prevBits;
1512d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u2 addr, prevAddr;
1513d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1514d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    addr = *mapData++;
1515d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (addrWidth > 1)
1516d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addr |= (*mapData++) << 8;
1517d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1518d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (addr >= 128) {
15191d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        LOGV("Can't compress map with starting address >= 128\n");
1520d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
1521d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1522d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1523d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1524d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Start by writing the initial address and bit vector data.  The high
1525d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * bit of the initial address is used to indicate the required address
1526d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * width (which the decoder can't otherwise determine without parsing
1527d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * the compressed data).
1528d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1529d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    *tmpPtr++ = addr | (addrWidth > 1 ? 0x80 : 0x00);
1530d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    memcpy(tmpPtr, mapData, regWidth);
1531d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1532d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    prevBits = mapData;
1533d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    prevAddr = addr;
1534d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1535d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    tmpPtr += regWidth;
1536d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    mapData += regWidth;
1537d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1538d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1539d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Loop over all following entries.
1540d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1541d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int entry;
1542d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    for (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)
15541d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            LOGI(" addr=0x%04x ent=%d (aw=%d)\n", 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)
1562d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                LOGI(" : small %d, key=0x%02x\n", addrDiff, key);
1563d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        } else {
1564d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            /* large difference, output escape code */
15651d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            key = 0x07;                 /* escape code for AAA */
1566d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            if (debug)
1567d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                LOGI(" : large %d, key=0x%02x\n", 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) {
15761d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            LOGI(" : diff fbc=%d nbc=%d ls=%d (rw=%d)\n",
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;
15831d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (debug) LOGI(" : no bits changed\n");
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;
15871d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (debug) LOGI(" : 1 low bit changed\n");
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);
15911d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (debug) LOGI(" : some bits changed\n");
15921d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        } else {
15931d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* set B to 1 and CCCC to 0x0f so we store the entire vector */
15941d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            key |= 0x08 | 0xf0;
15951d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (debug) LOGI(" : encode original\n");
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         */
16311d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (tmpPtr - tmpBuf >= origSize) {
16321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (debug) {
16331d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                LOGD("Compressed size >= original (%d vs %d): %s.%s\n",
16341d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    tmpPtr - tmpBuf, origSize,
16351d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    meth->clazz->descriptor, meth->name);
16361d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            }
1637d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            goto bail;
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);
1648d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int newDataSize = tmpPtr - tmpBuf;
1649d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int newMapSize;
1650d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1651d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    newMapSize = kHeaderSize + unsignedLeb128Size(newDataSize) + newDataSize;
1652d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (newMapSize >= origSize) {
16531d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        if (debug) {
16541d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            LOGD("Final comp size >= original (%d vs %d): %s.%s\n",
16551d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                newMapSize, origSize, meth->clazz->descriptor, meth->name);
16561d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        }
1657d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
1658d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1659d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1660d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    pNewMap = (RegisterMap*) malloc(newMapSize);
1661d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (pNewMap == NULL)
1662d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
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);
1670d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    memcpy(tmpPtr, tmpBuf, newDataSize);
1671d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
16721d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (REGISTER_MAP_VERBOSE) {
16731d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        LOGD("Compression successful (%d -> %d) from aw=%d rw=%d ne=%d\n",
16741d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap),
16751d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            addrWidth, regWidth, numEntries);
16761d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
1677d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1678d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenbail:
1679d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    free(tmpBuf);
1680d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    return pNewMap;
1681d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden}
1682d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1683d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden/*
16841d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * Toggle the value of the "idx"th bit in "ptr".
16851d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden */
16861d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFaddenstatic inline void toggleBit(u1* ptr, int idx)
16871d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden{
16881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    ptr[idx >> 3] ^= 1 << (idx & 0x07);
16891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden}
16901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
16911d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden/*
1692d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Expand a compressed map to an uncompressed form.
1693d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden *
1694d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden * Returns a newly-allocated RegisterMap on success, or NULL on failure.
16951d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden *
16961d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * TODO: consider using the linear allocator or a custom allocator with
16971d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden * LRU replacement for these instead of the native heap.
1698d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden */
1699d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenstatic RegisterMap* uncompressMapDifferential(const RegisterMap* pMap)
1700d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden{
1701d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    RegisterMap* pNewMap = NULL;
1702d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    static const int kHeaderSize = offsetof(RegisterMap, data);
1703d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1 format = dvmRegisterMapGetFormat(pMap);
1704d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    RegisterMapFormat newFormat;
1705d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int regWidth, numEntries, newAddrWidth, newMapSize;
1706d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1707d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (format != kRegMapFormatDifferential) {
1708d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGE("Not differential (%d)\n", format);
1709d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
1710d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1711d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1712d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    regWidth = dvmRegisterMapGetRegWidth(pMap);
1713d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    numEntries = dvmRegisterMapGetNumEntries(pMap);
1714d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1715d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /* get the data size; we can check this at the end */
1716d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* srcPtr = pMap->data;
1717d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int expectedSrcLen = readUnsignedLeb128(&srcPtr);
1718d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* srcStart = srcPtr;
1719d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1720d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /* get the initial address and the 16-bit address flag */
1721d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int addr = *srcPtr & 0x7f;
1722d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if ((*srcPtr & 0x80) == 0) {
1723d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newFormat = kRegMapFormatCompact8;
1724d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newAddrWidth = 1;
1725d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    } else {
1726d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newFormat = kRegMapFormatCompact16;
1727d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        newAddrWidth = 2;
1728d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1729d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    srcPtr++;
1730d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1731d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /* now we know enough to allocate the new map */
17321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (REGISTER_MAP_VERBOSE) {
17331d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        LOGI("Expanding to map aw=%d rw=%d ne=%d\n",
17341d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            newAddrWidth, regWidth, numEntries);
17351d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
1736d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    newMapSize = kHeaderSize + (newAddrWidth + regWidth) * numEntries;
1737d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    pNewMap = (RegisterMap*) malloc(newMapSize);
1738d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (pNewMap == NULL)
1739d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
1740d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1741d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetFormat(pNewMap, newFormat);
1742d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetOnHeap(pNewMap, true);
1743d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetRegWidth(pNewMap, regWidth);
1744d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dvmRegisterMapSetNumEntries(pNewMap, numEntries);
1745d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1746d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1747d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Write the start address and initial bits to the new map.
1748d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1749d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    u1* dstPtr = pNewMap->data;
1750d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1751d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    *dstPtr++ = addr & 0xff;
1752d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (newAddrWidth > 1)
1753d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        *dstPtr++ = (u1) (addr >> 8);
1754d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1755d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    memcpy(dstPtr, srcPtr, regWidth);
1756d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1757d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int prevAddr = addr;
1758d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    const u1* prevBits = dstPtr;    /* point at uncompressed data */
1759d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1760d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    dstPtr += regWidth;
1761d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    srcPtr += regWidth;
1762d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1763d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    /*
1764d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     * Walk through, uncompressing one line at a time.
1765d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden     */
1766d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    int entry;
1767d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    for (entry = 1; entry < numEntries; entry++) {
1768d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        int addrDiff;
1769d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        u1 key;
1770d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1771d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        key = *srcPtr++;
1772d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1773d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        /* get the address */
1774d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        if ((key & 0x07) == 7) {
1775d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            /* address diff follows in ULEB128 */
1776d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            addrDiff = readUnsignedLeb128(&srcPtr);
1777d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        } else {
17781035127f783b84befca34f1afe2a5bff64546902Andy McFadden            addrDiff = (key & 0x07) +1;
1779d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1780d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1781d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        addr = prevAddr + addrDiff;
1782d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        *dstPtr++ = addr & 0xff;
1783d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        if (newAddrWidth > 1)
1784d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            *dstPtr++ = (u1) (addr >> 8);
1785d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1786d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        /* unpack the bits */
1787d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        if ((key & 0x08) != 0) {
17881d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            int bitCount = (key >> 4);
17891d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            if (bitCount == 0) {
17901d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* no bits changed, just copy previous */
17911d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                memcpy(dstPtr, prevBits, regWidth);
17921d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            } else if (bitCount == 15) {
1793d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                /* full copy of bit vector is present; ignore prevBits */
1794d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                memcpy(dstPtr, srcPtr, regWidth);
1795d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden                srcPtr += regWidth;
1796d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            } else {
17971d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                /* copy previous bits and modify listed indices */
17981d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                memcpy(dstPtr, prevBits, regWidth);
17991d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                while (bitCount--) {
18001d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    int bitIndex = readUnsignedLeb128(&srcPtr);
18011d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                    toggleBit(dstPtr, bitIndex);
18021d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden                }
1803d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            }
1804d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        } else {
18051d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* copy previous bits and modify the specified one */
18061d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            memcpy(dstPtr, prevBits, regWidth);
18071d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden
18081d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            /* one bit, from 0-15 inclusive, was changed */
18091d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            toggleBit(dstPtr, key >> 4);
1810d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        }
1811d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1812d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        prevAddr = addr;
1813d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        prevBits = dstPtr;
1814d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        dstPtr += regWidth;
1815d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1816d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1817d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (dstPtr - (u1*) pNewMap != newMapSize) {
1818d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGE("ERROR: output %d bytes, expected %d\n",
1819d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            dstPtr - (u1*) pNewMap, newMapSize);
1820d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
1821d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1822d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1823d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    if (srcPtr - srcStart != expectedSrcLen) {
1824d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        LOGE("ERROR: consumed %d bytes, expected %d\n",
1825d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden            srcPtr - srcStart, expectedSrcLen);
1826d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden        goto bail;
1827d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    }
1828d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
18291d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    if (REGISTER_MAP_VERBOSE) {
18301d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden        LOGD("Expansion successful (%d -> %d)\n",
18311d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden            computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap));
18321d47a87b38e41f9957849ba685af1f41e53f8a05Andy McFadden    }
1833d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1834d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    return pNewMap;
1835d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1836d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenbail:
1837d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    free(pNewMap);
1838d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden    return NULL;
1839d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden}
1840d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1841d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1842d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden/*
1843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * ===========================================================================
1844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *      Just-in-time generation
1845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * ===========================================================================
1846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#if 0   /* incomplete implementation; may be removed entirely in the future */
1849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
1851d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenNotes on just-in-time RegisterMap generation
1852d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1853d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenGenerating RegisterMap tables as part of verification is convenient because
1854d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenwe generate most of what we need to know as part of doing the verify.
1855d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenThe negative aspect of doing it this way is that we must store the
1856d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenresult in the DEX file (if we're verifying ahead of time) or in memory
1857d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden(if verifying during class load) for every concrete non-native method,
1858d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddeneven if we never actually need the map during a GC.
1859d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1860d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenA simple but compact encoding of register map data increases the size of
1861d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenoptimized DEX files by about 25%, so size considerations are important.
1862d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1863d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenWe can instead generate the RegisterMap at the point where it is needed.
1864d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenIn a typical application we only need to convert about 2% of the loaded
1865d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenmethods, and we can generate type-precise roots reasonably quickly because
1866d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden(a) we know the method has already been verified and hence can make a
1867d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenlot of assumptions, and (b) we don't care what type of object a register
1868d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenholds, just whether or not it holds a reference, and hence can skip a
1869d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenlot of class resolution gymnastics.
1870d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1871d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenThere are a couple of problems with this approach however.  First, to
1872d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenget good performance we really want an implementation that is largely
1873d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenindependent from the verifier, which means some duplication of effort.
1874d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenSecond, we're dealing with post-dexopt code, which contains "quickened"
1875d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddeninstructions.  We can't process those without either tracking type
1876d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddeninformation (which slows us down) or storing additional data in the DEX
1877d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenfile that allows us to reconstruct the original instructions (adds ~5%
1878d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddento the size of the ODEX).
1879d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1880d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1881d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenImplementation notes...
1882d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1883d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenBoth type-precise and live-precise information can be generated knowing
1884d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenonly whether or not a register holds a reference.  We don't need to
1885d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenknow what kind of reference or whether the object has been initialized.
1886d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenNot only can we skip many of the fancy steps in the verifier, we can
1887d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddeninitialize from simpler sources, e.g. the initial registers and return
1888d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddentype are set from the "shorty" signature rather than the full signature.
1889d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1890d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenThe short-term storage needs for just-in-time register map generation can
1891d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenbe much lower because we can use a 1-byte SRegType instead of a 4-byte
1892d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenRegType.  On the other hand, if we're not doing type-precise analysis
1893d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenin the verifier we only need to store register contents at every branch
1894d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddentarget, rather than every GC point (which are much more frequent).
1895d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1896d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenWhether it happens in the verifier or independently, because this is done
1897d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenwith native heap allocations that may be difficult to return to the system,
1898d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFaddenan effort should be made to minimize memory use.
1899d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden*/
1900d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden
1901d45a88794c6470d96e2139cbe803002d9d5d3a6cAndy McFadden/*
1902f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * This is like RegType in the verifier, but simplified.  It holds a value
1903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * from the reg type enum, or kRegTypeReference.
1904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecttypedef u1 SRegType;
1906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kRegTypeReference kRegTypeMAX
1907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
1909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * We need an extra "pseudo register" to hold the return type briefly.  It
1910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * can be category 1 or 2, so we need two slots.
1911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define kExtraRegs  2
1913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#define RESULT_REGISTER(_insnRegCountPlus)  (_insnRegCountPlus - kExtraRegs)
1914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
1916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Working state.
1917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projecttypedef struct WorkState {
1919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
1920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * The method we're working on.
1921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const Method* method;
1923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
1925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Number of instructions in the method.
1926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int         insnsSize;
1928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
1930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Number of registers we track for each instruction.  This is equal
1931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to the method's declared "registersSize" plus kExtraRegs.
1932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int         insnRegCountPlus;
1934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
1936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Instruction widths and flags, one entry per code unit.
1937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    InsnFlags*  insnFlags;
1939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
1941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Array of SRegType arrays, one entry per code unit.  We only need
1942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to create an entry when an instruction starts at this address.
1943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * We can further reduce this to instructions that are GC points.
1944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
1945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * We could just go ahead and allocate one per code unit, but for
1946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * larger methods that can represent a significant bit of short-term
1947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * storage.
1948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType**  addrRegs;
1950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
1952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * A single large alloc, with all of the storage needed for addrRegs.
1953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType*   regAlloc;
1955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project} WorkState;
1956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project// fwd
1958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool generateMap(WorkState* pState, RegisterMap* pMap);
1959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool analyzeMethod(WorkState* pState);
1960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool handleInstruction(WorkState* pState, SRegType* workRegs,\
1961f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int insnIdx, int* pStartGuess);
1962f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void updateRegisters(WorkState* pState, int nextInsn,\
1963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const SRegType* workRegs);
1964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1965f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
1967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Set instruction flags.
1968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
1969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool setInsnFlags(WorkState* pState, int* pGcPointCount)
1970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
1971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const Method* meth = pState->method;
1972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    InsnFlags* insnFlags = pState->insnFlags;
1973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int insnsSize = pState->insnsSize;
1974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const u2* insns = meth->insns;
1975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int gcPointCount = 0;
1976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int offset;
1977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* set the widths */
1979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!dvmComputeCodeWidths(meth, pState->insnFlags, NULL))
1980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
1981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* mark "try" regions and exception handler branch targets */
1983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!dvmSetTryFlags(meth, pState->insnFlags))
1984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return false;
1985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* the start of the method is a "branch target" */
1987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmInsnSetBranchTarget(insnFlags, 0, true);
1988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
1989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
1990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Run through the instructions, looking for switches and branches.
1991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Mark their targets.
1992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
1993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * We don't really need to "check" these instructions -- the verifier
1994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * already did that -- but the additional overhead isn't significant
1995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * enough to warrant making a second copy of the "Check" function.
1996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
1997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Mark and count GC points while we're at it.
1998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
1999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (offset = 0; offset < insnsSize; offset++) {
2000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        static int gcMask = kInstrCanBranch | kInstrCanSwitch |
2001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            kInstrCanThrow | kInstrCanReturn;
2002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        u1 opcode = insns[offset] & 0xff;
2003f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        InstructionFlags opFlags = dexGetInstrFlags(gDvm.instrFlags, opcode);
2004f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (opFlags & kInstrCanBranch) {
2006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!dvmCheckBranchTarget(meth, insnFlags, offset, true))
2007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return false;
2008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (opFlags & kInstrCanSwitch) {
2010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!dvmCheckSwitchTargets(meth, insnFlags, offset))
2011f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                return false;
2012f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2013f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2014f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((opFlags & gcMask) != 0) {
2015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmInsnSetGcPoint(pState->insnFlags, offset, true);
2016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            gcPointCount++;
2017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    *pGcPointCount = gcPointCount;
2021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
2022f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2024f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2025f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Generate the register map for a method.
2026f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
2027f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns a pointer to newly-allocated storage.
2028f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2029f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source ProjectRegisterMap* dvmGenerateRegisterMap(const Method* meth)
2030f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2031f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    WorkState* pState = NULL;
2032f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    RegisterMap* pMap = NULL;
2033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    RegisterMap* result = NULL;
2034f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType* regPtr;
2035f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2036f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pState = (WorkState*) calloc(1, sizeof(WorkState));
2037f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pState == NULL)
2038f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
2039f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2040f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap = (RegisterMap*) calloc(1, sizeof(RegisterMap));
2041f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pMap == NULL)
2042f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
2043f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2044f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pState->method = meth;
2045f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pState->insnsSize = dvmGetMethodInsnsSize(meth);
2046f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pState->insnRegCountPlus = meth->registersSize + kExtraRegs;
2047f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2048f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pState->insnFlags = calloc(sizeof(InsnFlags), pState->insnsSize);
2049f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pState->addrRegs = calloc(sizeof(SRegType*), pState->insnsSize);
2050f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2051f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2052f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Set flags on instructions, and calculate the number of code units
2053f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * that happen to be GC points.
2054f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2055f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int gcPointCount;
2056f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!setInsnFlags(pState, &gcPointCount))
2057f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
2058f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2059f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (gcPointCount == 0) {
2060f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* the method doesn't allocate or call, and never returns? unlikely */
2061f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOG_VFY_METH(meth, "Found do-nothing method\n");
2062f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
2063f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2064f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pState->regAlloc = (SRegType*)
2066f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        calloc(sizeof(SRegType), pState->insnsSize * gcPointCount);
2067f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    regPtr = pState->regAlloc;
2068f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * For each instruction that is a GC point, set a pointer into the
2071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * regAlloc buffer.
2072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2073f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int offset;
2074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    for (offset = 0; offset < pState->insnsSize; offset++) {
2075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmInsnIsGcPoint(pState->insnFlags, offset)) {
2076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            pState->addrRegs[offset] = regPtr;
2077f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            regPtr += pState->insnRegCountPlus;
2078f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(regPtr - pState->regAlloc == pState->insnsSize * gcPointCount);
2081f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(pState->addrRegs[0] != NULL);
2082f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2083f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2084f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Compute the register map.
2085f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2086f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!generateMap(pState, pMap))
2087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
2088f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* success */
2090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = pMap;
2091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    pMap = NULL;
2092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
2094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pState != NULL) {
2095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        free(pState->insnFlags);
2096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        free(pState->addrRegs);
2097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        free(pState->regAlloc);
2098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        free(pState);
2099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pMap != NULL)
2101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmFreeRegisterMap(pMap);
2102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
2103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Release the storage associated with a RegisterMap.
2107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectvoid dvmFreeRegisterMap(RegisterMap* pMap)
2109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (pMap == NULL)
2111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return;
2112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Create the RegisterMap using the provided state.
2117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool generateMap(WorkState* pState, RegisterMap* pMap)
2119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    bool result = false;
2121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Analyze the method and store the results in WorkState.
2124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!analyzeMethod(pState))
2126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
2127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Convert the analyzed data into a RegisterMap.
2130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // TODO
2132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = true;
2134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
2136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
2137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Set the register types for the method arguments.  We can pull the values
2141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * out of the "shorty" signature.
2142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool setTypesFromSignature(WorkState* pState)
2144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const Method* meth = pState->method;
2146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int argReg = meth->registersSize - meth->insSize;   /* first arg */
2147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType* pRegs = pState->addrRegs[0];
2148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType* pCurReg = &pRegs[argReg];
2149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const char* ccp;
2150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Include "this" pointer, if appropriate.
2153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!dvmIsStaticMethod(meth)) {
2155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *pCurReg++ = kRegTypeReference;
2156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    ccp = meth->shorty +1;      /* skip first byte, which holds return type */
2159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (*ccp != 0) {
2160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        switch (*ccp) {
2161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        case 'L':
2162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        //case '[':
2163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeReference;
2164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
2165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        case 'Z':
2166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeBoolean;
2167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
2168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        case 'C':
2169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeChar;
2170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
2171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        case 'B':
2172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeByte;
2173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
2174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        case 'I':
2175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeInteger;
2176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
2177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        case 'S':
2178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeShort;
2179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
2180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        case 'F':
2181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeFloat;
2182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
2183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        case 'D':
2184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeDoubleLo;
2185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeDoubleHi;
2186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
2187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        case 'J':
2188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeLongLo;
2189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            *pCurReg++ = kRegTypeLongHi;
2190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            break;
2191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        default:
2192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            assert(false);
2193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            return false;
2194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(pCurReg - pRegs == meth->insSize);
2198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return true;
2199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Find the start of the register set for the specified instruction in
2203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the current method.
2204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline SRegType* getRegisterLine(const WorkState* pState, int insnIdx)
2206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return pState->addrRegs[insnIdx];
2208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copy a set of registers.
2212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline void copyRegisters(SRegType* dst, const SRegType* src,
2214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int numRegs)
2215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    memcpy(dst, src, numRegs * sizeof(SRegType));
2217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Compare a set of registers.  Returns 0 if they match.
2221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline int compareRegisters(const SRegType* src1, const SRegType* src2,
2223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int numRegs)
2224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return memcmp(src1, src2, numRegs * sizeof(SRegType));
2226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Run through the instructions repeatedly until we have exercised all
2230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * possible paths.
2231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool analyzeMethod(WorkState* pState)
2233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const Method* meth = pState->method;
2235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType workRegs[pState->insnRegCountPlus];
2236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    InsnFlags* insnFlags = pState->insnFlags;
2237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int insnsSize = pState->insnsSize;
2238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int insnIdx, startGuess;
2239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    bool result = false;
2240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Initialize the types of the registers that correspond to method
2243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * arguments.
2244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!setTypesFromSignature(pState))
2246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto bail;
2247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Mark the first instruction as "changed".
2250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dvmInsnSetChanged(insnFlags, 0, true);
2252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    startGuess = 0;
2253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (true) {
2255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        IF_LOGI() {
2256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
2257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGI("Now mapping: %s.%s %s (ins=%d regs=%d)\n",
2258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                meth->clazz->descriptor, meth->name, desc,
2259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                meth->insSize, meth->registersSize);
2260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            LOGI(" ------ [0    4    8    12   16   20   24   28   32   36\n");
2261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            free(desc);
2262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Continue until no instructions are marked "changed".
2267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    while (true) {
2269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
2270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Find the first marked one.  Use "startGuess" as a way to find
2271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * one quickly.
2272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
2273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (insnIdx = startGuess; insnIdx < insnsSize; insnIdx++) {
2274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (dvmInsnIsChanged(insnFlags, insnIdx))
2275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
2276f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2277f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2278f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (insnIdx == insnsSize) {
2279f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (startGuess != 0) {
2280f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* try again, starting from the top */
2281f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                startGuess = 0;
2282f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                continue;
2283f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            } else {
2284f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* all flags are clear */
2285f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                break;
2286f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
2287f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2288f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2289f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
2290f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We carry the working set of registers from instruction to
2291f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * instruction.  If this address can be the target of a branch
2292f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * (or throw) instruction, or if we're skipping around chasing
2293f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * "changed" flags, we need to load the set of registers from
2294f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the table.
2295f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         *
2296f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Because we always prefer to continue on to the next instruction,
2297f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * we should never have a situation where we have a stray
2298f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * "changed" flag set on an instruction that isn't a branch target.
2299f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
2300f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dvmInsnIsBranchTarget(insnFlags, insnIdx)) {
2301f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            SRegType* insnRegs = getRegisterLine(pState, insnIdx);
2302f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            assert(insnRegs != NULL);
2303f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            copyRegisters(workRegs, insnRegs, pState->insnRegCountPlus);
2304f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2305f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
2306f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#ifndef NDEBUG
2307f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /*
2308f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * Sanity check: retrieve the stored register line (assuming
2309f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             * a full table) and make sure it actually matches.
2310f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project             */
2311f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            SRegType* insnRegs = getRegisterLine(pState, insnIdx);
2312f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (insnRegs != NULL &&
2313f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                compareRegisters(workRegs, insnRegs,
2314f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                                 pState->insnRegCountPlus) != 0)
2315f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
2316f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                char* desc = dexProtoCopyMethodDescriptor(&meth->prototype);
2317f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                LOG_VFY("HUH? workRegs diverged in %s.%s %s\n",
2318f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                        meth->clazz->descriptor, meth->name, desc);
2319f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                free(desc);
2320f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
2321f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif
2322f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2323f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2324f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
2325f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * Update the register sets altered by this instruction.
2326f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
2327f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (!handleInstruction(pState, workRegs, insnIdx, &startGuess)) {
2328f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            goto bail;
2329f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2330f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2331f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmInsnSetVisited(insnFlags, insnIdx, true);
2332f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmInsnSetChanged(insnFlags, insnIdx, false);
2333f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2334f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2335f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    // TODO - add dead code scan to help validate this code?
2336f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2337f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = true;
2338f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2339f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
2340f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
2341f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2342f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2343f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2344f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Get a pointer to the method being invoked.
2345f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
2346f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns NULL on failure.
2347f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2348f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic Method* getInvokedMethod(const Method* meth,
2349f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const DecodedInstruction* pDecInsn, MethodType methodType)
2350f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2351f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    Method* resMethod;
2352f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    char* sigOriginal = NULL;
2353f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2354f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2355f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Resolve the method.  This could be an abstract or concrete method
2356f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * depending on what sort of call we're making.
2357f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2358f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (methodType == METHOD_INTERFACE) {
2359f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resMethod = dvmOptResolveInterfaceMethod(meth->clazz, pDecInsn->vB);
2360f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
2361f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        resMethod = dvmOptResolveMethod(meth->clazz, pDecInsn->vB, methodType);
2362f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2363f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (resMethod == NULL) {
2364f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* failed; print a meaningful failure message */
2365f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
2366f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const DexMethodId* pMethodId;
2367f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const char* methodName;
2368f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        char* methodDesc;
2369f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const char* classDescriptor;
2370f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2371f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        pMethodId = dexGetMethodId(pDexFile, pDecInsn->vB);
2372f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        methodName = dexStringById(pDexFile, pMethodId->nameIdx);
2373f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        methodDesc = dexCopyDescriptorFromMethodId(pDexFile, pMethodId);
2374f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        classDescriptor = dexStringByTypeIdx(pDexFile, pMethodId->classIdx);
2375f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2376f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOG_VFY("VFY: unable to resolve %s method %u: %s.%s %s\n",
2377f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmMethodTypeStr(methodType), pDecInsn->vB,
2378f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            classDescriptor, methodName, methodDesc);
2379f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        free(methodDesc);
2380f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return NULL;
2381f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2382f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2383f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return resMethod;
2384f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2385f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2386f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2387f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Return the register type for the method.  Since we don't care about
2388f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * the actual type, we can just look at the "shorty" signature.
2389f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
2390f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Returns kRegTypeUnknown for "void".
2391f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2392f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic SRegType getMethodReturnType(const Method* meth)
2393f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2394f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType type;
2395f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2396f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    switch (meth->shorty[0]) {
2397f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'I':
2398f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeInteger;
2399f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2400f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'C':
2401f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeChar;
2402f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2403f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'S':
2404f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeShort;
2405f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2406f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'B':
2407f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeByte;
2408f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2409f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'Z':
2410f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeBoolean;
2411f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2412f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'V':
2413f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeUnknown;
2414f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2415f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'F':
2416f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeFloat;
2417f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2418f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'D':
2419f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeDoubleLo;
2420f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2421f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'J':
2422f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeLongLo;
2423f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2424f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case 'L':
2425f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //case '[':
2426f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeReference;
2427f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2428f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    default:
2429f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* we verified signature return type earlier, so this is impossible */
2430f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(false);
2431f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        type = kRegTypeConflict;
2432f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2433f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2434f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2435f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return type;
2436f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2437f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2438f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2439f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copy a category 1 register.
2440f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2441f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline void copyRegister1(SRegType* insnRegs, u4 vdst, u4 vsrc)
2442f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2443f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    insnRegs[vdst] = insnRegs[vsrc];
2444f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2445f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2446f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2447f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Copy a category 2 register.  Note the source and destination may overlap.
2448f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2449f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline void copyRegister2(SRegType* insnRegs, u4 vdst, u4 vsrc)
2450f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2451f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    //memmove(&insnRegs[vdst], &insnRegs[vsrc], sizeof(SRegType) * 2);
2452f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType r1 = insnRegs[vsrc];
2453f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType r2 = insnRegs[vsrc+1];
2454f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    insnRegs[vdst] = r1;
2455f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    insnRegs[vdst+1] = r2;
2456f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2457f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2458f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2459f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Set the type of a category 1 register.
2460f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2461f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic inline void setRegisterType(SRegType* insnRegs, u4 vdst, SRegType type)
2462f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2463f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    insnRegs[vdst] = type;
2464f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
2465f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2466f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
2467f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Decode the specified instruction and update the register info.
2468f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
2469f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic bool handleInstruction(WorkState* pState, SRegType* workRegs,
2470f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int insnIdx, int* pStartGuess)
2471f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
2472f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const Method* meth = pState->method;
2473f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const u2* insns = meth->insns + insnIdx;
2474f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    InsnFlags* insnFlags = pState->insnFlags;
2475f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    bool result = false;
2476f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2477f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2478f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Once we finish decoding the instruction, we need to figure out where
2479f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * we can go from here.  There are three possible ways to transfer
2480f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * control to another statement:
2481f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
2482f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * (1) Continue to the next instruction.  Applies to all but
2483f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *     unconditional branches, method returns, and exception throws.
2484f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * (2) Branch to one or more possible locations.  Applies to branches
2485f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *     and switch statements.
2486f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * (3) Exception handlers.  Applies to any instruction that can
2487f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *     throw an exception that is handled by an encompassing "try"
2488f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *     block.  (We simplify this to be any instruction that can
2489f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *     throw any exception.)
2490f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
2491f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * We can also return, in which case there is no successor instruction
2492f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * from this point.
2493f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
2494f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * The behavior can be determined from the InstrFlags.
2495f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2496f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    DecodedInstruction decInsn;
2497f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType entryRegs[pState->insnRegCountPlus];
2498f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const int insnRegCountPlus = pState->insnRegCountPlus;
2499f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    bool justSetResult = false;
2500f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    int branchTarget = 0;
2501f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType tmpType;
2502f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2503f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    dexDecodeInstruction(gDvm.instrFormat, insns, &decInsn);
2504f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const int nextFlags = dexGetInstrFlags(gDvm.instrFlags, decInsn.opCode);
2505f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2506f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2507f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Make a copy of the previous register state.  If the instruction
2508f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * throws an exception, we merge *this* into the destination rather
2509f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * than workRegs, because we don't want the result from the "successful"
2510f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * code path (e.g. a check-cast that "improves" a type) to be visible
2511f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * to the exception handler.
2512f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2513f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
2514f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
2515f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        copyRegisters(entryRegs, workRegs, insnRegCountPlus);
2516f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
2517f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2518f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    switch (decInsn.opCode) {
2519f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_NOP:
2520f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2521f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2522f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE:
2523f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_FROM16:
2524f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_16:
2525f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_OBJECT:
2526f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_OBJECT_FROM16:
2527f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_OBJECT_16:
2528f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        copyRegister1(workRegs, decInsn.vA, decInsn.vB);
2529f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2530f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_WIDE:
2531f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_WIDE_FROM16:
2532f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_WIDE_16:
2533f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        copyRegister2(workRegs, decInsn.vA, decInsn.vB);
2534f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2535f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2536f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2537f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * The move-result instructions copy data out of a "pseudo-register"
2538f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * with the results from the last method invocation.  In practice we
2539f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * might want to hold the result in an actual CPU register, so the
2540f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Dalvik spec requires that these only appear immediately after an
2541f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * invoke or filled-new-array.
2542f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
2543f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * These calls invalidate the "result" register.  (This is now
2544f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * redundant with the reset done below, but it can make the debug info
2545f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * easier to read in some cases.)
2546f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
2547f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_RESULT:
2548f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_RESULT_OBJECT:
2549f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        copyRegister1(workRegs, decInsn.vA, RESULT_REGISTER(insnRegCountPlus));
2550f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2551f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_RESULT_WIDE:
2552f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        copyRegister2(workRegs, decInsn.vA, RESULT_REGISTER(insnRegCountPlus));
2553f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2554f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2555f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MOVE_EXCEPTION:
2556f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
2557f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * This statement can only appear as the first instruction in an
2558f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * exception handler (though not all exception handlers need to
2559f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * have one of these).  We verify that as part of extracting the
2560f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * exception type from the catch block list.
2561f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
2562f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
2563f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2564f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2565f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_RETURN_VOID:
2566f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_RETURN:
2567f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_RETURN_WIDE:
2568f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_RETURN_OBJECT:
2569f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2570f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2571f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_4:
2572f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_16:
2573f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST:
2574f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* could be boolean, int, float, or a null reference */
2575f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA,
2576f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmDetermineCat1Const((s4)decInsn.vB));
2577f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2578f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_HIGH16:
2579f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* could be boolean, int, float, or a null reference */
2580f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA,
2581f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmDetermineCat1Const((s4) decInsn.vB << 16));
2582f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2583f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_WIDE_16:
2584f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_WIDE_32:
2585f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_WIDE:
2586f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_WIDE_HIGH16:
2587f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* could be long or double; default to long and allow conversion */
2588f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2589f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2590f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_STRING:
2591f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_STRING_JUMBO:
2592f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CONST_CLASS:
2593f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
2594f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2595f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2596f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MONITOR_ENTER:
2597f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MONITOR_EXIT:
2598f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2599f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2600f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CHECK_CAST:
2601f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
2602f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2603f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INSTANCE_OF:
2604f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* result is boolean */
2605f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
2606f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2607f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2608f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ARRAY_LENGTH:
2609f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
2610f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2611f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2612f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_NEW_INSTANCE:
2613f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_NEW_ARRAY:
2614f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* add the new uninitialized reference to the register ste */
2615f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
2616f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2617f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_FILLED_NEW_ARRAY:
2618f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_FILLED_NEW_ARRAY_RANGE:
2619f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
2620f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            kRegTypeReference);
2621f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        justSetResult = true;
2622f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2623f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2624f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CMPL_FLOAT:
2625f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CMPG_FLOAT:
2626f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
2627f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2628f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CMPL_DOUBLE:
2629f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CMPG_DOUBLE:
2630f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
2631f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2632f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_CMP_LONG:
2633f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeBoolean);
2634f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2635f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2636f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_THROW:
2637f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_GOTO:
2638f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_GOTO_16:
2639f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_GOTO_32:
2640f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_PACKED_SWITCH:
2641f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SPARSE_SWITCH:
2642f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2643f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2644f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_FILL_ARRAY_DATA:
2645f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2646f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2647f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_EQ:
2648f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_NE:
2649f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_LT:
2650f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_GE:
2651f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_GT:
2652f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_LE:
2653f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_EQZ:
2654f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_NEZ:
2655f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_LTZ:
2656f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_GEZ:
2657f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_GTZ:
2658f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IF_LEZ:
2659f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2660f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2661f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AGET:
2662f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeInteger;
2663f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto aget_1nr_common;
2664f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AGET_BOOLEAN:
2665f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeBoolean;
2666f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto aget_1nr_common;
2667f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AGET_BYTE:
2668f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeByte;
2669f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto aget_1nr_common;
2670f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AGET_CHAR:
2671f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeChar;
2672f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto aget_1nr_common;
2673f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AGET_SHORT:
2674f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeShort;
2675f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto aget_1nr_common;
2676f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectaget_1nr_common:
2677f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, tmpType);
2678f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2679f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2680f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AGET_WIDE:
2681f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
2682f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We know this is either long or double, and we don't really
2683f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * discriminate between those during verification, so we
2684f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * call it a long.
2685f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
2686f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2687f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2688f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2689f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AGET_OBJECT:
2690f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
2691f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2692f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2693f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_APUT:
2694f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_APUT_BOOLEAN:
2695f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_APUT_BYTE:
2696f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_APUT_CHAR:
2697f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_APUT_SHORT:
2698f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_APUT_WIDE:
2699f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_APUT_OBJECT:
2700f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2701f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2702f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET:
2703f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeInteger;
2704f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto iget_1nr_common;
2705f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET_BOOLEAN:
2706f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeBoolean;
2707f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto iget_1nr_common;
2708f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET_BYTE:
2709f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeByte;
2710f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto iget_1nr_common;
2711f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET_CHAR:
2712f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeChar;
2713f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto iget_1nr_common;
2714f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET_SHORT:
2715f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeShort;
2716f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto iget_1nr_common;
2717f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectiget_1nr_common:
2718f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, tmpType);
2719f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2720f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2721f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET_WIDE:
2722f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2723f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2724f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2725f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET_OBJECT:
2726f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
2727f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2728f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2729f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT:
2730f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT_BOOLEAN:
2731f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT_BYTE:
2732f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT_CHAR:
2733f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT_SHORT:
2734f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT_WIDE:
2735f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT_OBJECT:
2736f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2737f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2738f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SGET:
2739f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeInteger;
2740f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto sget_1nr_common;
2741f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SGET_BOOLEAN:
2742f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeBoolean;
2743f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto sget_1nr_common;
2744f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SGET_BYTE:
2745f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeByte;
2746f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto sget_1nr_common;
2747f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SGET_CHAR:
2748f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeChar;
2749f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto sget_1nr_common;
2750f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SGET_SHORT:
2751f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        tmpType = kRegTypeShort;
2752f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        goto sget_1nr_common;
2753f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectsget_1nr_common:
2754f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, tmpType);
2755f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2756f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2757f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SGET_WIDE:
2758f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2759f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2760f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2761f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SGET_OBJECT:
2762f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeReference);
2763f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2764f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2765f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SPUT:
2766f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SPUT_BOOLEAN:
2767f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SPUT_BYTE:
2768f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SPUT_CHAR:
2769f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SPUT_SHORT:
2770f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SPUT_WIDE:
2771f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SPUT_OBJECT:
2772f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2773f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2774f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_VIRTUAL:
2775f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_VIRTUAL_RANGE:
2776f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_SUPER:
2777f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_SUPER_RANGE:
2778f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
2779f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Method* calledMethod;
2780f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2781f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            calledMethod = getInvokedMethod(meth, &decInsn, METHOD_VIRTUAL);
2782f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (calledMethod == NULL)
2783f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                goto bail;
2784f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
2785f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                getMethodReturnType(calledMethod));
2786f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            justSetResult = true;
2787f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2788f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2789f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_DIRECT:
2790f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_DIRECT_RANGE:
2791f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
2792f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Method* calledMethod;
2793f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2794f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            calledMethod = getInvokedMethod(meth, &decInsn, METHOD_DIRECT);
2795f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (calledMethod == NULL)
2796f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                goto bail;
2797f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
2798f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                getMethodReturnType(calledMethod));
2799f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            justSetResult = true;
2800f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2801f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2802f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_STATIC:
2803f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_STATIC_RANGE:
2804f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
2805f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Method* calledMethod;
2806f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2807f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            calledMethod = getInvokedMethod(meth, &decInsn, METHOD_STATIC);
2808f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (calledMethod == NULL)
2809f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                goto bail;
2810f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
2811f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                getMethodReturnType(calledMethod));
2812f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            justSetResult = true;
2813f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2814f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2815f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_INTERFACE:
2816f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_INTERFACE_RANGE:
2817f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        {
2818f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            Method* absMethod;
2819f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2820f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            absMethod = getInvokedMethod(meth, &decInsn, METHOD_INTERFACE);
2821f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (absMethod == NULL)
2822f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                goto bail;
2823f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            setRegisterType(workRegs, RESULT_REGISTER(insnRegCountPlus),
2824f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                getMethodReturnType(absMethod));
2825f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            justSetResult = true;
2826f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
2827f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2828f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2829f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_NEG_INT:
2830f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_NOT_INT:
2831f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
2832f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2833f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_NEG_LONG:
2834f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_NOT_LONG:
2835f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2836f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2837f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_NEG_FLOAT:
2838f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
2839f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2840f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_NEG_DOUBLE:
2841f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
2842f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2843f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INT_TO_LONG:
2844f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2845f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2846f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INT_TO_FLOAT:
2847f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
2848f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2849f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INT_TO_DOUBLE:
2850f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
2851f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2852f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_LONG_TO_INT:
2853f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
2854f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2855f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_LONG_TO_FLOAT:
2856f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
2857f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2858f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_LONG_TO_DOUBLE:
2859f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
2860f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2861f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_FLOAT_TO_INT:
2862f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
2863f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2864f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_FLOAT_TO_LONG:
2865f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2866f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2867f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_FLOAT_TO_DOUBLE:
2868f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
2869f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2870f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DOUBLE_TO_INT:
2871f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
2872f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2873f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DOUBLE_TO_LONG:
2874f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2875f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2876f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DOUBLE_TO_FLOAT:
2877f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
2878f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2879f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INT_TO_BYTE:
2880f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeByte);
2881f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2882f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INT_TO_CHAR:
2883f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeChar);
2884f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2885f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INT_TO_SHORT:
2886f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeShort);
2887f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2888f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2889f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_INT:
2890f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SUB_INT:
2891f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_INT:
2892f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_INT:
2893f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_INT:
2894f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHL_INT:
2895f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHR_INT:
2896f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_USHR_INT:
2897f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AND_INT:
2898f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_OR_INT:
2899f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_XOR_INT:
2900f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
2901f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2902f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_LONG:
2903f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SUB_LONG:
2904f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_LONG:
2905f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_LONG:
2906f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_LONG:
2907f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AND_LONG:
2908f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_OR_LONG:
2909f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_XOR_LONG:
2910f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHL_LONG:
2911f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHR_LONG:
2912f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_USHR_LONG:
2913f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2914f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2915f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_FLOAT:
2916f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SUB_FLOAT:
2917f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_FLOAT:
2918f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_FLOAT:
2919f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_FLOAT:
2920f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
2921f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2922f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_DOUBLE:
2923f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SUB_DOUBLE:
2924f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_DOUBLE:
2925f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_DOUBLE:
2926f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_DOUBLE:
2927f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
2928f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2929f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_INT_2ADDR:
2930f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SUB_INT_2ADDR:
2931f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_INT_2ADDR:
2932f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_INT_2ADDR:
2933f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHL_INT_2ADDR:
2934f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHR_INT_2ADDR:
2935f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_USHR_INT_2ADDR:
2936f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AND_INT_2ADDR:
2937f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_OR_INT_2ADDR:
2938f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_XOR_INT_2ADDR:
2939f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_INT_2ADDR:
2940f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
2941f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2942f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_LONG_2ADDR:
2943f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SUB_LONG_2ADDR:
2944f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_LONG_2ADDR:
2945f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_LONG_2ADDR:
2946f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_LONG_2ADDR:
2947f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AND_LONG_2ADDR:
2948f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_OR_LONG_2ADDR:
2949f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_XOR_LONG_2ADDR:
2950f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHL_LONG_2ADDR:
2951f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHR_LONG_2ADDR:
2952f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_USHR_LONG_2ADDR:
2953f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeLongLo);
2954f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2955f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_FLOAT_2ADDR:
2956f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SUB_FLOAT_2ADDR:
2957f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_FLOAT_2ADDR:
2958f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_FLOAT_2ADDR:
2959f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_FLOAT_2ADDR:
2960f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeFloat);
2961f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2962f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_DOUBLE_2ADDR:
2963f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SUB_DOUBLE_2ADDR:
2964f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_DOUBLE_2ADDR:
2965f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_DOUBLE_2ADDR:
2966f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_DOUBLE_2ADDR:
2967f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeDoubleLo);
2968f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2969f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_INT_LIT16:
2970f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_RSUB_INT:
2971f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_INT_LIT16:
2972f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_INT_LIT16:
2973f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_INT_LIT16:
2974f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AND_INT_LIT16:
2975f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_OR_INT_LIT16:
2976f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_XOR_INT_LIT16:
2977f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_ADD_INT_LIT8:
2978f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_RSUB_INT_LIT8:
2979f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_MUL_INT_LIT8:
2980f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_DIV_INT_LIT8:
2981f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_REM_INT_LIT8:
2982f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHL_INT_LIT8:
2983f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_SHR_INT_LIT8:
2984f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_USHR_INT_LIT8:
2985f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_AND_INT_LIT8:
2986f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_OR_INT_LIT8:
2987f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_XOR_INT_LIT8:
2988f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        setRegisterType(workRegs, decInsn.vA, kRegTypeInteger);
2989f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
2990f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2991f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
2992f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
2993f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * See comments in analysis/CodeVerify.c re: why some of these are
2994f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * annoying to deal with.  It's worse in this implementation, because
2995f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * we're not keeping any information about the classes held in each
2996f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * reference register.
2997f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
2998f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Handling most of these would require retaining the field/method
2999f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * reference info that we discarded when the instructions were
3000f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * quickened.  This is feasible but not currently supported.
3001f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3002f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_EXECUTE_INLINE:
3003b0a0541b59d1126ff77c88de742b4a74579fe296Andy McFadden    case OP_EXECUTE_INLINE_RANGE:
3004f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_DIRECT_EMPTY:
3005f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET_QUICK:
3006f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET_WIDE_QUICK:
3007f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IGET_OBJECT_QUICK:
3008f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT_QUICK:
3009f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT_WIDE_QUICK:
3010f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_IPUT_OBJECT_QUICK:
30115387824f19033ed51a945fbc8c2b574998404b3dAndy McFadden    case OP_IGET_WIDE_VOLATILE:
30125387824f19033ed51a945fbc8c2b574998404b3dAndy McFadden    case OP_IPUT_WIDE_VOLATILE:
30135387824f19033ed51a945fbc8c2b574998404b3dAndy McFadden    case OP_SGET_WIDE_VOLATILE:
30145387824f19033ed51a945fbc8c2b574998404b3dAndy McFadden    case OP_SPUT_WIDE_VOLATILE:
3015f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_VIRTUAL_QUICK:
3016f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_VIRTUAL_QUICK_RANGE:
3017f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_SUPER_QUICK:
3018f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_INVOKE_SUPER_QUICK_RANGE:
3019f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmAbort();     // not implemented, shouldn't be here
3020f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
3021f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3022f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3023f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /* these should never appear */
3024f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_3E:
3025f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_3F:
3026f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_40:
3027f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_41:
3028f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_42:
3029f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_43:
3030f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_73:
3031f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_79:
3032f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_7A:
3033f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_E3:
3034f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_E4:
3035f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_E5:
3036f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_E6:
3037f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_E7:
303896516932f1557d8f48a8b2dbbb885af01a11ef6eAndy McFadden    case OP_BREAKPOINT:
3039f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_ED:
3040f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_F1:
3041f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_FC:
3042f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_FD:
3043f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_FE:
3044f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    case OP_UNUSED_FF:
3045f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmAbort();
3046f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        break;
3047f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3048f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
3049f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * DO NOT add a "default" clause here.  Without it the compiler will
3050f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * complain if an instruction is missing (which is desirable).
3051f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3052f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
3053f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3054f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3055f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
3056f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * If we didn't just set the result register, clear it out.  This
3057f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * isn't so important here, but does help ensure that our output matches
3058f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * the verifier.
3059f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3060f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!justSetResult) {
3061f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int reg = RESULT_REGISTER(pState->insnRegCountPlus);
3062f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        workRegs[reg] = workRegs[reg+1] = kRegTypeUnknown;
3063f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
3064f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3065f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
3066f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Handle "continue".  Tag the next consecutive instruction.
3067f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3068f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((nextFlags & kInstrCanContinue) != 0) {
3069f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int insnWidth = dvmInsnGetWidth(insnFlags, insnIdx);
3070f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3071f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
3072f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We want to update the registers and set the "changed" flag on the
3073f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * next instruction (if necessary).  We aren't storing register
3074f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * changes for all addresses, so for non-GC-point targets we just
3075f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * compare "entry" vs. "work" to see if we've changed anything.
3076f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
3077f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (getRegisterLine(pState, insnIdx+insnWidth) != NULL) {
3078f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            updateRegisters(pState, insnIdx+insnWidth, workRegs);
3079f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
3080f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* if not yet visited, or regs were updated, set "changed" */
3081f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (!dvmInsnIsVisited(insnFlags, insnIdx+insnWidth) ||
3082f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                compareRegisters(workRegs, entryRegs,
3083f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    pState->insnRegCountPlus) != 0)
3084f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            {
3085f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                dvmInsnSetChanged(insnFlags, insnIdx+insnWidth, true);
3086f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
3087f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
3088f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
3089f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3090f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
3091f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Handle "branch".  Tag the branch target.
3092f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3093f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((nextFlags & kInstrCanBranch) != 0) {
3094f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bool isConditional;
3095f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3096f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmGetBranchTarget(meth, insnFlags, insnIdx, &branchTarget,
3097f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                &isConditional);
3098f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(isConditional || (nextFlags & kInstrCanContinue) == 0);
3099f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        assert(!isConditional || (nextFlags & kInstrCanContinue) != 0);
3100f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3101f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        updateRegisters(pState, insnIdx+branchTarget, workRegs);
3102f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
3103f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3104f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
3105f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Handle "switch".  Tag all possible branch targets.
3106f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3107f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((nextFlags & kInstrCanSwitch) != 0) {
3108f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int offsetToSwitch = insns[1] | (((s4)insns[2]) << 16);
3109f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const u2* switchInsns = insns + offsetToSwitch;
3110f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int switchCount = switchInsns[1];
3111f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int offsetToTargets, targ;
3112f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3113f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if ((*insns & 0xff) == OP_PACKED_SWITCH) {
3114f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* 0=sig, 1=count, 2/3=firstKey */
3115f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            offsetToTargets = 4;
3116f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
3117f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* 0=sig, 1=count, 2..count*2 = keys */
3118f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            assert((*insns & 0xff) == OP_SPARSE_SWITCH);
3119f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            offsetToTargets = 2 + 2*switchCount;
3120f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
3121f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3122f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* verify each switch target */
3123f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (targ = 0; targ < switchCount; targ++) {
3124f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            int offset, absOffset;
3125f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3126f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* offsets are 32-bit, and only partly endian-swapped */
3127f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            offset = switchInsns[offsetToTargets + targ*2] |
3128f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                     (((s4) switchInsns[offsetToTargets + targ*2 +1]) << 16);
3129f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            absOffset = insnIdx + offset;
3130f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            assert(absOffset >= 0 && absOffset < pState->insnsSize);
3131f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3132f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            updateRegisters(pState, absOffset, workRegs);
3133f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
3134f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
3135f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3136f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
3137f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Handle instructions that can throw and that are sitting in a
3138f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * "try" block.  (If they're not in a "try" block when they throw,
3139f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * control transfers out of the method.)
3140f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3141f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((nextFlags & kInstrCanThrow) != 0 && dvmInsnIsInTry(insnFlags, insnIdx))
3142f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    {
3143f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
3144f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        const DexCode* pCode = dvmGetMethodCode(meth);
3145f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        DexCatchIterator iterator;
3146f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3147f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (dexFindCatchHandler(&iterator, pCode, insnIdx)) {
3148f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            while (true) {
3149f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
3150f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                if (handler == NULL)
3151f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                    break;
3152f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3153f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                /* note we use entryRegs, not workRegs */
3154f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                updateRegisters(pState, handler->address, entryRegs);
3155f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            }
3156f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
3157f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
3158f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3159f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
3160f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Update startGuess.  Advance to the next instruction of that's
3161f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * possible, otherwise use the branch target if one was found.  If
3162f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * neither of those exists we're in a return or throw; leave startGuess
3163f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * alone and let the caller sort it out.
3164f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3165f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if ((nextFlags & kInstrCanContinue) != 0) {
3166f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *pStartGuess = insnIdx + dvmInsnGetWidth(insnFlags, insnIdx);
3167f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else if ((nextFlags & kInstrCanBranch) != 0) {
3168f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* we're still okay if branchTarget is zero */
3169f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *pStartGuess = insnIdx + branchTarget;
3170f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
3171f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3172f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    assert(*pStartGuess >= 0 && *pStartGuess < pState->insnsSize &&
3173f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmInsnGetWidth(insnFlags, *pStartGuess) != 0);
3174f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3175f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    result = true;
3176f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3177f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectbail:
3178f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
3179f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
3180f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3181f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3182f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
3183f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Merge two SRegType values.
3184f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
3185f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Sets "*pChanged" to "true" if the result doesn't match "type1".
3186f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
3187f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic SRegType mergeTypes(SRegType type1, SRegType type2, bool* pChanged)
3188f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
3189f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType result;
3190f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3191f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
3192f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Check for trivial case so we don't have to hit memory.
3193f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3194f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (type1 == type2)
3195f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        return type1;
3196f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3197f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    /*
3198f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * Use the table if we can, and reject any attempts to merge something
3199f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * from the table with a reference type.
3200f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     *
3201f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * The uninitialized table entry at index zero *will* show up as a
3202f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * simple kRegTypeUninit value.  Since this cannot be merged with
3203f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     * anything but itself, the rules do the right thing.
3204f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project     */
3205f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (type1 < kRegTypeMAX) {
3206f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (type2 < kRegTypeMAX) {
3207f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            result = gDvmMergeTab[type1][type2];
3208f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
3209f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* simple + reference == conflict, usually */
3210f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (type1 == kRegTypeZero)
3211f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                result = type2;
3212f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            else
3213f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                result = kRegTypeConflict;
3214f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
3215f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
3216f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (type2 < kRegTypeMAX) {
3217f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* reference + simple == conflict, usually */
3218f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            if (type2 == kRegTypeZero)
3219f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                result = type1;
3220f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            else
3221f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project                result = kRegTypeConflict;
3222f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        } else {
3223f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            /* merging two references */
3224f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            assert(type1 == type2);
3225f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            result = type1;
3226f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
3227f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
3228f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3229f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (result != type1)
3230f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        *pChanged = true;
3231f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    return result;
3232f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
3233f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3234f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project/*
3235f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Control can transfer to "nextInsn".
3236f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project *
3237f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * Merge the registers from "workRegs" into "addrRegs" at "nextInsn", and
3238f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project * set the "changed" flag on the target address if the registers have changed.
3239f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project */
3240f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Projectstatic void updateRegisters(WorkState* pState, int nextInsn,
3241f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const SRegType* workRegs)
3242f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project{
3243f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const Method* meth = pState->method;
3244f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    InsnFlags* insnFlags = pState->insnFlags;
3245f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    const int insnRegCountPlus = pState->insnRegCountPlus;
3246f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    SRegType* targetRegs = getRegisterLine(pState, nextInsn);
3247f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3248f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    if (!dvmInsnIsVisitedOrChanged(insnFlags, nextInsn)) {
3249f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /*
3250f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * We haven't processed this instruction before, and we haven't
3251f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * touched the registers here, so there's nothing to "merge".  Copy
3252f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * the registers over and mark it as changed.  (This is the only
3253f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * way a register can transition out of "unknown", so this is not
3254f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         * just an optimization.)
3255f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project         */
3256f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGVV("COPY into 0x%04x\n", nextInsn);
3257f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        copyRegisters(targetRegs, workRegs, insnRegCountPlus);
3258f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        dvmInsnSetChanged(insnFlags, nextInsn, true);
3259f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    } else {
3260f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        /* merge registers, set Changed only if different */
3261f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        LOGVV("MERGE into 0x%04x\n", nextInsn);
3262f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        bool changed = false;
3263f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        int i;
3264f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3265f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        for (i = 0; i < insnRegCountPlus; i++) {
3266f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            targetRegs[i] = mergeTypes(targetRegs[i], workRegs[i], &changed);
3267f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        }
3268f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3269f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project        if (changed)
3270f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project            dvmInsnSetChanged(insnFlags, nextInsn, true);
3271f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project    }
3272f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project}
3273f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3274f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project#endif /*#if 0*/
3275f6c387128427e121477c1b32ad35cdcaa5101ba3The Android Open Source Project
3276