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