1 /*
2 * Copyright (C) 2009 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * This code generate "register maps" for Dalvik bytecode. In a stack-based
19 * VM we might call these "stack maps". They are used to increase the
20 * precision in the garbage collector when scanning references in the
21 * interpreter thread stacks.
22 */
23 #include "Dalvik.h"
24 #include "UniquePtr.h"
25 #include "analysis/CodeVerify.h"
26 #include "analysis/RegisterMap.h"
27 #include "libdex/DexCatch.h"
28 #include "libdex/InstrUtils.h"
29 #include "libdex/Leb128.h"
30
31 #include <stddef.h>
32
33 /* double-check the compression */
34 #define REGISTER_MAP_VERIFY false
35
36 /* verbose logging */
37 #define REGISTER_MAP_VERBOSE false
38
39 //#define REGISTER_MAP_STATS
40
41 // fwd
42 static void outputTypeVector(const RegType* regs, int insnRegCount, u1* data);
43 static bool verifyMap(VerifierData* vdata, const RegisterMap* pMap);
44 static int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2);
45
46 #ifdef REGISTER_MAP_STATS
47 static void computeMapStats(RegisterMap* pMap, const Method* method);
48 #endif
49 static RegisterMap* compressMapDifferential(const RegisterMap* pMap,\
50 const Method* meth);
51 static RegisterMap* uncompressMapDifferential(const RegisterMap* pMap);
52
53 #ifdef REGISTER_MAP_STATS
54 /*
55 * Generate some statistics on the register maps we create and use.
56 */
57 #define kMaxGcPointGap 50
58 #define kUpdatePosnMinRegs 24
59 #define kNumUpdatePosns 8
60 #define kMaxDiffBits 20
61 struct MapStats {
62 /*
63 * Buckets measuring the distance between GC points. This tells us how
64 * many bits we need to encode the advancing program counter. We ignore
65 * some of the "long tail" entries.
66 */
67 int gcPointGap[kMaxGcPointGap];
68
69 /*
70 * Number of gaps. Equal to (number of gcPoints - number of methods),
71 * since the computation isn't including the initial gap.
72 */
73 int gcGapCount;
74
75 /*
76 * Number of gaps.
77 */
78 int totalGcPointCount;
79
80 /*
81 * For larger methods (>= 24 registers), measure in which octant register
82 * updates occur. This should help us understand whether register
83 * changes tend to cluster in the low regs even for large methods.
84 */
85 int updatePosn[kNumUpdatePosns];
86
87 /*
88 * For all methods, count up the number of changes to registers < 16
89 * and >= 16.
90 */
91 int updateLT16;
92 int updateGE16;
93
94 /*
95 * Histogram of the number of bits that differ between adjacent entries.
96 */
97 int numDiffBits[kMaxDiffBits];
98
99
100 /*
101 * Track the number of expanded maps, and the heap space required to
102 * hold them.
103 */
104 int numExpandedMaps;
105 int totalExpandedMapSize;
106 };
107 #endif
108
109 /*
110 * Prepare some things.
111 */
dvmRegisterMapStartup()112 bool dvmRegisterMapStartup()
113 {
114 #ifdef REGISTER_MAP_STATS
115 MapStats* pStats = calloc(1, sizeof(MapStats));
116 gDvm.registerMapStats = pStats;
117 #endif
118 return true;
119 }
120
121 /*
122 * Clean up.
123 */
dvmRegisterMapShutdown()124 void dvmRegisterMapShutdown()
125 {
126 #ifdef REGISTER_MAP_STATS
127 free(gDvm.registerMapStats);
128 #endif
129 }
130
131 /*
132 * Write stats to log file.
133 */
dvmRegisterMapDumpStats()134 void dvmRegisterMapDumpStats()
135 {
136 #ifdef REGISTER_MAP_STATS
137 MapStats* pStats = (MapStats*) gDvm.registerMapStats;
138 int i, end;
139
140 for (end = kMaxGcPointGap-1; end >= 0; end--) {
141 if (pStats->gcPointGap[end] != 0)
142 break;
143 }
144
145 ALOGI("Register Map gcPointGap stats (diff count=%d, total=%d):",
146 pStats->gcGapCount, pStats->totalGcPointCount);
147 assert(pStats->gcPointGap[0] == 0);
148 for (i = 1; i <= end; i++) {
149 ALOGI(" %2d %d", i, pStats->gcPointGap[i]);
150 }
151
152
153 for (end = kMaxDiffBits-1; end >= 0; end--) {
154 if (pStats->numDiffBits[end] != 0)
155 break;
156 }
157
158 ALOGI("Register Map bit difference stats:");
159 for (i = 0; i <= end; i++) {
160 ALOGI(" %2d %d", i, pStats->numDiffBits[i]);
161 }
162
163
164 ALOGI("Register Map update position stats (lt16=%d ge16=%d):",
165 pStats->updateLT16, pStats->updateGE16);
166 for (i = 0; i < kNumUpdatePosns; i++) {
167 ALOGI(" %2d %d", i, pStats->updatePosn[i]);
168 }
169 #endif
170 }
171
172
173 /*
174 * ===========================================================================
175 * Map generation
176 * ===========================================================================
177 */
178
179 /*
180 * Generate the register map for a method that has just been verified
181 * (i.e. we're doing this as part of verification).
182 *
183 * For type-precise determination we have all the data we need, so we
184 * just need to encode it in some clever fashion.
185 *
186 * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
187 */
dvmGenerateRegisterMapV(VerifierData * vdata)188 RegisterMap* dvmGenerateRegisterMapV(VerifierData* vdata)
189 {
190 static const int kHeaderSize = offsetof(RegisterMap, data);
191 RegisterMap* pMap = NULL;
192 RegisterMap* pResult = NULL;
193 RegisterMapFormat format;
194 u1 regWidth;
195 u1* mapData;
196 int i, bytesForAddr, gcPointCount;
197 int bufSize;
198
199 if (vdata->method->registersSize >= 2048) {
200 ALOGE("ERROR: register map can't handle %d registers",
201 vdata->method->registersSize);
202 goto bail;
203 }
204 regWidth = (vdata->method->registersSize + 7) / 8;
205
206 /*
207 * Decide if we need 8 or 16 bits to hold the address. Strictly speaking
208 * we only need 16 bits if we actually encode an address >= 256 -- if
209 * the method has a section at the end without GC points (e.g. array
210 * data) we don't need to count it. The situation is unusual, and
211 * detecting it requires scanning the entire method, so we don't bother.
212 */
213 if (vdata->insnsSize < 256) {
214 format = kRegMapFormatCompact8;
215 bytesForAddr = 1;
216 } else {
217 format = kRegMapFormatCompact16;
218 bytesForAddr = 2;
219 }
220
221 /*
222 * Count up the number of GC point instructions.
223 *
224 * NOTE: this does not automatically include the first instruction,
225 * since we don't count method entry as a GC point.
226 */
227 gcPointCount = 0;
228 for (i = 0; i < (int) vdata->insnsSize; i++) {
229 if (dvmInsnIsGcPoint(vdata->insnFlags, i))
230 gcPointCount++;
231 }
232 if (gcPointCount >= 65536) {
233 /* we could handle this, but in practice we don't get near this */
234 ALOGE("ERROR: register map can't handle %d gc points in one method",
235 gcPointCount);
236 goto bail;
237 }
238
239 /*
240 * Allocate a buffer to hold the map data.
241 */
242 bufSize = kHeaderSize + gcPointCount * (bytesForAddr + regWidth);
243
244 ALOGV("+++ grm: %s.%s (adr=%d gpc=%d rwd=%d bsz=%d)",
245 vdata->method->clazz->descriptor, vdata->method->name,
246 bytesForAddr, gcPointCount, regWidth, bufSize);
247
248 pMap = (RegisterMap*) malloc(bufSize);
249 dvmRegisterMapSetFormat(pMap, format);
250 dvmRegisterMapSetOnHeap(pMap, true);
251 dvmRegisterMapSetRegWidth(pMap, regWidth);
252 dvmRegisterMapSetNumEntries(pMap, gcPointCount);
253
254 /*
255 * Populate it.
256 */
257 mapData = pMap->data;
258 for (i = 0; i < (int) vdata->insnsSize; i++) {
259 if (dvmInsnIsGcPoint(vdata->insnFlags, i)) {
260 assert(vdata->registerLines[i].regTypes != NULL);
261 if (format == kRegMapFormatCompact8) {
262 *mapData++ = i;
263 } else /*kRegMapFormatCompact16*/ {
264 *mapData++ = i & 0xff;
265 *mapData++ = i >> 8;
266 }
267 outputTypeVector(vdata->registerLines[i].regTypes,
268 vdata->insnRegCount, mapData);
269 mapData += regWidth;
270 }
271 }
272
273 ALOGV("mapData=%p pMap=%p bufSize=%d", mapData, pMap, bufSize);
274 assert(mapData - (const u1*) pMap == bufSize);
275
276 if (REGISTER_MAP_VERIFY && !verifyMap(vdata, pMap))
277 goto bail;
278 #ifdef REGISTER_MAP_STATS
279 computeMapStats(pMap, vdata->method);
280 #endif
281
282 /*
283 * Try to compress the map.
284 */
285 RegisterMap* pCompMap;
286
287 pCompMap = compressMapDifferential(pMap, vdata->method);
288 if (pCompMap != NULL) {
289 if (REGISTER_MAP_VERIFY) {
290 /*
291 * Expand the compressed map we just created, and compare it
292 * to the original. Abort the VM if it doesn't match up.
293 */
294 RegisterMap* pUncompMap;
295 pUncompMap = uncompressMapDifferential(pCompMap);
296 if (pUncompMap == NULL) {
297 ALOGE("Map failed to uncompress - %s.%s",
298 vdata->method->clazz->descriptor,
299 vdata->method->name);
300 free(pCompMap);
301 /* bad - compression is broken or we're out of memory */
302 dvmAbort();
303 } else {
304 if (compareMaps(pMap, pUncompMap) != 0) {
305 ALOGE("Map comparison failed - %s.%s",
306 vdata->method->clazz->descriptor,
307 vdata->method->name);
308 free(pCompMap);
309 /* bad - compression is broken */
310 dvmAbort();
311 }
312
313 /* verify succeeded */
314 delete pUncompMap;
315 }
316 }
317
318 if (REGISTER_MAP_VERBOSE) {
319 ALOGD("Good compress on %s.%s",
320 vdata->method->clazz->descriptor,
321 vdata->method->name);
322 }
323 free(pMap);
324 pMap = pCompMap;
325 } else {
326 if (REGISTER_MAP_VERBOSE) {
327 ALOGD("Unable to compress %s.%s (ent=%d rw=%d)",
328 vdata->method->clazz->descriptor,
329 vdata->method->name,
330 dvmRegisterMapGetNumEntries(pMap),
331 dvmRegisterMapGetRegWidth(pMap));
332 }
333 }
334
335 pResult = pMap;
336
337 bail:
338 return pResult;
339 }
340
341 /*
342 * Release the storage held by a RegisterMap.
343 */
dvmFreeRegisterMap(RegisterMap * pMap)344 void dvmFreeRegisterMap(RegisterMap* pMap)
345 {
346 if (pMap == NULL)
347 return;
348
349 assert(dvmRegisterMapGetOnHeap(pMap));
350 free(pMap);
351 }
352
353 /*
354 * Determine if the RegType value is a reference type.
355 *
356 * Ordinarily we include kRegTypeZero in the "is it a reference"
357 * check. There's no value in doing so here, because we know
358 * the register can't hold anything but zero.
359 */
isReferenceType(RegType type)360 static inline bool isReferenceType(RegType type)
361 {
362 return (type > kRegTypeMAX || type == kRegTypeUninit);
363 }
364
365 /*
366 * Given a line of registers, output a bit vector that indicates whether
367 * or not the register holds a reference type (which could be null).
368 *
369 * We use '1' to indicate it's a reference, '0' for anything else (numeric
370 * value, uninitialized data, merge conflict). Register 0 will be found
371 * in the low bit of the first byte.
372 */
outputTypeVector(const RegType * regs,int insnRegCount,u1 * data)373 static void outputTypeVector(const RegType* regs, int insnRegCount, u1* data)
374 {
375 u1 val = 0;
376 int i;
377
378 for (i = 0; i < insnRegCount; i++) {
379 RegType type = *regs++;
380 val >>= 1;
381 if (isReferenceType(type))
382 val |= 0x80; /* set hi bit */
383
384 if ((i & 0x07) == 7)
385 *data++ = val;
386 }
387 if ((i & 0x07) != 0) {
388 /* flush bits from last byte */
389 val >>= 8 - (i & 0x07);
390 *data++ = val;
391 }
392 }
393
394 /*
395 * Print the map as a series of binary strings.
396 *
397 * Pass in method->registersSize if known, or -1 if not.
398 */
dumpRegisterMap(const RegisterMap * pMap,int registersSize)399 static void dumpRegisterMap(const RegisterMap* pMap, int registersSize)
400 {
401 const u1* rawMap = pMap->data;
402 const RegisterMapFormat format = dvmRegisterMapGetFormat(pMap);
403 const int numEntries = dvmRegisterMapGetNumEntries(pMap);
404 const int regWidth = dvmRegisterMapGetRegWidth(pMap);
405 int addrWidth;
406
407 switch (format) {
408 case kRegMapFormatCompact8:
409 addrWidth = 1;
410 break;
411 case kRegMapFormatCompact16:
412 addrWidth = 2;
413 break;
414 default:
415 /* can't happen */
416 ALOGE("Can only dump Compact8 / Compact16 maps (not %d)", format);
417 return;
418 }
419
420 if (registersSize < 0)
421 registersSize = 8 * regWidth;
422 assert(registersSize <= regWidth * 8);
423
424 int ent;
425 for (ent = 0; ent < numEntries; ent++) {
426 int i, addr;
427
428 addr = *rawMap++;
429 if (addrWidth > 1)
430 addr |= (*rawMap++) << 8;
431
432 const u1* dataStart = rawMap;
433 u1 val = 0;
434
435 /* create binary string */
436 char outBuf[registersSize +1];
437 for (i = 0; i < registersSize; i++) {
438 val >>= 1;
439 if ((i & 0x07) == 0)
440 val = *rawMap++;
441
442 outBuf[i] = '0' + (val & 0x01);
443 }
444 outBuf[i] = '\0';
445
446 /* back up and create hex dump */
447 char hexBuf[regWidth * 3 +1];
448 char* cp = hexBuf;
449 rawMap = dataStart;
450 for (i = 0; i < regWidth; i++) {
451 sprintf(cp, " %02x", *rawMap++);
452 cp += 3;
453 }
454 hexBuf[i * 3] = '\0';
455
456 ALOGD(" %04x %s %s", addr, outBuf, hexBuf);
457 }
458 }
459
460 /*
461 * Double-check the map.
462 *
463 * We run through all of the data in the map, and compare it to the original.
464 * Only works on uncompressed data.
465 */
verifyMap(VerifierData * vdata,const RegisterMap * pMap)466 static bool verifyMap(VerifierData* vdata, const RegisterMap* pMap)
467 {
468 const u1* rawMap = pMap->data;
469 const RegisterMapFormat format = dvmRegisterMapGetFormat(pMap);
470 const int numEntries = dvmRegisterMapGetNumEntries(pMap);
471 int ent;
472 bool dumpMap = false;
473
474 if (false) {
475 const char* cd = "Landroid/net/http/Request;";
476 const char* mn = "readResponse";
477 if (strcmp(vdata->method->clazz->descriptor, cd) == 0 &&
478 strcmp(vdata->method->name, mn) == 0)
479 {
480 char* desc;
481 desc = dexProtoCopyMethodDescriptor(&vdata->method->prototype);
482 ALOGI("Map for %s.%s %s", vdata->method->clazz->descriptor,
483 vdata->method->name, desc);
484 free(desc);
485
486 dumpMap = true;
487 }
488 }
489
490 if ((vdata->method->registersSize + 7) / 8 != pMap->regWidth) {
491 ALOGE("GLITCH: registersSize=%d, regWidth=%d",
492 vdata->method->registersSize, pMap->regWidth);
493 return false;
494 }
495
496 for (ent = 0; ent < numEntries; ent++) {
497 int addr;
498
499 switch (format) {
500 case kRegMapFormatCompact8:
501 addr = *rawMap++;
502 break;
503 case kRegMapFormatCompact16:
504 addr = *rawMap++;
505 addr |= (*rawMap++) << 8;
506 break;
507 default:
508 /* shouldn't happen */
509 ALOGE("GLITCH: bad format (%d)", format);
510 dvmAbort();
511 }
512
513 const RegType* regs = vdata->registerLines[addr].regTypes;
514 if (regs == NULL) {
515 ALOGE("GLITCH: addr %d has no data", addr);
516 return false;
517 }
518
519 u1 val = 0;
520 int i;
521
522 for (i = 0; i < vdata->method->registersSize; i++) {
523 bool bitIsRef, regIsRef;
524
525 val >>= 1;
526 if ((i & 0x07) == 0) {
527 /* load next byte of data */
528 val = *rawMap++;
529 }
530
531 bitIsRef = val & 0x01;
532
533 RegType type = regs[i];
534 regIsRef = isReferenceType(type);
535
536 if (bitIsRef != regIsRef) {
537 ALOGE("GLITCH: addr %d reg %d: bit=%d reg=%d(%d)",
538 addr, i, bitIsRef, regIsRef, type);
539 return false;
540 }
541 }
542
543 /* rawMap now points to the address field of the next entry */
544 }
545
546 if (dumpMap)
547 dumpRegisterMap(pMap, vdata->method->registersSize);
548
549 return true;
550 }
551
552
553 /*
554 * ===========================================================================
555 * DEX generation & parsing
556 * ===========================================================================
557 */
558
559 /*
560 * Advance "ptr" to ensure 32-bit alignment.
561 */
align32(u1 * ptr)562 static inline u1* align32(u1* ptr)
563 {
564 return (u1*) (((int) ptr + 3) & ~0x03);
565 }
566
567 /*
568 * Compute the size, in bytes, of a register map.
569 */
computeRegisterMapSize(const RegisterMap * pMap)570 static size_t computeRegisterMapSize(const RegisterMap* pMap)
571 {
572 static const int kHeaderSize = offsetof(RegisterMap, data);
573 u1 format = dvmRegisterMapGetFormat(pMap);
574 u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
575
576 assert(pMap != NULL);
577
578 switch (format) {
579 case kRegMapFormatNone:
580 return 1;
581 case kRegMapFormatCompact8:
582 return kHeaderSize + (1 + pMap->regWidth) * numEntries;
583 case kRegMapFormatCompact16:
584 return kHeaderSize + (2 + pMap->regWidth) * numEntries;
585 case kRegMapFormatDifferential:
586 {
587 /* kHeaderSize + decoded ULEB128 length */
588 const u1* ptr = pMap->data;
589 int len = readUnsignedLeb128(&ptr);
590 return len + (ptr - (u1*) pMap);
591 }
592 default:
593 ALOGE("Bad register map format %d", format);
594 dvmAbort();
595 return 0;
596 }
597 }
598
599 /*
600 * Output the map for a single method, if it has one.
601 *
602 * Abstract and native methods have no map. All others are expected to
603 * have one, since we know the class verified successfully.
604 *
605 * This strips the "allocated on heap" flag from the format byte, so that
606 * direct-mapped maps are correctly identified as such.
607 */
writeMapForMethod(const Method * meth,u1 ** pPtr)608 static bool writeMapForMethod(const Method* meth, u1** pPtr)
609 {
610 if (meth->registerMap == NULL) {
611 if (!dvmIsAbstractMethod(meth) && !dvmIsNativeMethod(meth)) {
612 ALOGW("Warning: no map available for %s.%s",
613 meth->clazz->descriptor, meth->name);
614 /* weird, but keep going */
615 }
616 *(*pPtr)++ = kRegMapFormatNone;
617 return true;
618 }
619
620 /* serialize map into the buffer */
621 size_t mapSize = computeRegisterMapSize(meth->registerMap);
622 memcpy(*pPtr, meth->registerMap, mapSize);
623
624 /* strip the "on heap" flag out of the format byte, which is always first */
625 assert(**pPtr == meth->registerMap->format);
626 **pPtr &= ~(kRegMapFormatOnHeap);
627
628 *pPtr += mapSize;
629
630 return true;
631 }
632
633 /*
634 * Write maps for all methods in the specified class to the buffer, which
635 * can hold at most "length" bytes. "*pPtr" will be advanced past the end
636 * of the data we write.
637 */
writeMapsAllMethods(DvmDex * pDvmDex,const ClassObject * clazz,u1 ** pPtr,size_t length)638 static bool writeMapsAllMethods(DvmDex* pDvmDex, const ClassObject* clazz,
639 u1** pPtr, size_t length)
640 {
641 RegisterMapMethodPool* pMethodPool;
642 u1* ptr = *pPtr;
643 int i, methodCount;
644
645 /* artificial limit */
646 if (clazz->virtualMethodCount + clazz->directMethodCount >= 65536) {
647 ALOGE("Too many methods in %s", clazz->descriptor);
648 return false;
649 }
650
651 pMethodPool = (RegisterMapMethodPool*) ptr;
652 ptr += offsetof(RegisterMapMethodPool, methodData);
653 methodCount = 0;
654
655 /*
656 * Run through all methods, direct then virtual. The class loader will
657 * traverse them in the same order. (We could split them into two
658 * distinct pieces, but there doesn't appear to be any value in doing
659 * so other than that it makes class loading slightly less fragile.)
660 *
661 * The class loader won't know about miranda methods at the point
662 * where it parses this, so we omit those.
663 *
664 * TODO: consider omitting all native/abstract definitions. Should be
665 * safe, though we lose the ability to sanity-check against the
666 * method counts in the DEX file.
667 */
668 for (i = 0; i < clazz->directMethodCount; i++) {
669 const Method* meth = &clazz->directMethods[i];
670 if (dvmIsMirandaMethod(meth))
671 continue;
672 if (!writeMapForMethod(&clazz->directMethods[i], &ptr)) {
673 return false;
674 }
675 methodCount++;
676 //ptr = align32(ptr);
677 }
678
679 for (i = 0; i < clazz->virtualMethodCount; i++) {
680 const Method* meth = &clazz->virtualMethods[i];
681 if (dvmIsMirandaMethod(meth))
682 continue;
683 if (!writeMapForMethod(&clazz->virtualMethods[i], &ptr)) {
684 return false;
685 }
686 methodCount++;
687 //ptr = align32(ptr);
688 }
689
690 pMethodPool->methodCount = methodCount;
691
692 *pPtr = ptr;
693 return true;
694 }
695
696 /*
697 * Write maps for all classes to the specified buffer, which can hold at
698 * most "length" bytes.
699 *
700 * Returns the actual length used, or 0 on failure.
701 */
writeMapsAllClasses(DvmDex * pDvmDex,u1 * basePtr,size_t length)702 static size_t writeMapsAllClasses(DvmDex* pDvmDex, u1* basePtr, size_t length)
703 {
704 DexFile* pDexFile = pDvmDex->pDexFile;
705 u4 count = pDexFile->pHeader->classDefsSize;
706 RegisterMapClassPool* pClassPool;
707 u4* offsetTable;
708 u1* ptr = basePtr;
709 u4 idx;
710
711 assert(gDvm.optimizing);
712
713 pClassPool = (RegisterMapClassPool*) ptr;
714 ptr += offsetof(RegisterMapClassPool, classDataOffset);
715 offsetTable = (u4*) ptr;
716 ptr += count * sizeof(u4);
717
718 pClassPool->numClasses = count;
719
720 /*
721 * We want an entry for every class, loaded or not.
722 */
723 for (idx = 0; idx < count; idx++) {
724 const DexClassDef* pClassDef;
725 const char* classDescriptor;
726 ClassObject* clazz;
727
728 pClassDef = dexGetClassDef(pDexFile, idx);
729 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
730
731 /*
732 * All classes have been loaded into the bootstrap class loader.
733 * If we can find it, and it was successfully pre-verified, we
734 * run through its methods and add the register maps.
735 *
736 * If it wasn't pre-verified then we know it can't have any
737 * register maps. Classes that can't be loaded or failed
738 * verification get an empty slot in the index.
739 */
740 clazz = NULL;
741 if ((pClassDef->accessFlags & CLASS_ISPREVERIFIED) != 0)
742 clazz = dvmLookupClass(classDescriptor, NULL, false);
743
744 if (clazz != NULL) {
745 offsetTable[idx] = ptr - basePtr;
746 LOGVV("%d -> offset %d (%p-%p)",
747 idx, offsetTable[idx], ptr, basePtr);
748
749 if (!writeMapsAllMethods(pDvmDex, clazz, &ptr,
750 length - (ptr - basePtr)))
751 {
752 return 0;
753 }
754
755 ptr = align32(ptr);
756 LOGVV("Size %s (%d+%d methods): %d", clazz->descriptor,
757 clazz->directMethodCount, clazz->virtualMethodCount,
758 (ptr - basePtr) - offsetTable[idx]);
759 } else {
760 ALOGV("%4d NOT mapadding '%s'", idx, classDescriptor);
761 assert(offsetTable[idx] == 0);
762 }
763 }
764
765 if (ptr - basePtr >= (int)length) {
766 /* a bit late */
767 ALOGE("Buffer overrun");
768 dvmAbort();
769 }
770
771 return ptr - basePtr;
772 }
773
774 /*
775 * Generate a register map set for all verified classes in "pDvmDex".
776 */
dvmGenerateRegisterMaps(DvmDex * pDvmDex)777 RegisterMapBuilder* dvmGenerateRegisterMaps(DvmDex* pDvmDex)
778 {
779 RegisterMapBuilder* pBuilder;
780
781 pBuilder = (RegisterMapBuilder*) calloc(1, sizeof(RegisterMapBuilder));
782 if (pBuilder == NULL)
783 return NULL;
784
785 /*
786 * We have a couple of options here:
787 * (1) Compute the size of the output, and malloc a buffer.
788 * (2) Create a "large-enough" anonymous mmap region.
789 *
790 * The nice thing about option #2 is that we don't have to traverse
791 * all of the classes and methods twice. The risk is that we might
792 * not make the region large enough. Since the pages aren't mapped
793 * until used we can allocate a semi-absurd amount of memory without
794 * worrying about the effect on the rest of the system.
795 *
796 * The basic encoding on the largest jar file requires about 1MB of
797 * storage. We map out 4MB here. (TODO: guarantee that the last
798 * page of the mapping is marked invalid, so we reliably fail if
799 * we overrun.)
800 */
801 if (sysCreatePrivateMap(4 * 1024 * 1024, &pBuilder->memMap) != 0) {
802 free(pBuilder);
803 return NULL;
804 }
805
806 /*
807 * Create the maps.
808 */
809 size_t actual = writeMapsAllClasses(pDvmDex, (u1*)pBuilder->memMap.addr,
810 pBuilder->memMap.length);
811 if (actual == 0) {
812 dvmFreeRegisterMapBuilder(pBuilder);
813 return NULL;
814 }
815
816 ALOGV("TOTAL size of register maps: %d", actual);
817
818 pBuilder->data = pBuilder->memMap.addr;
819 pBuilder->size = actual;
820 return pBuilder;
821 }
822
823 /*
824 * Free the builder.
825 */
dvmFreeRegisterMapBuilder(RegisterMapBuilder * pBuilder)826 void dvmFreeRegisterMapBuilder(RegisterMapBuilder* pBuilder)
827 {
828 if (pBuilder == NULL)
829 return;
830
831 sysReleaseShmem(&pBuilder->memMap);
832 free(pBuilder);
833 }
834
835
836 /*
837 * Find the data for the specified class.
838 *
839 * If there's no register map data, or none for this class, we return NULL.
840 */
dvmRegisterMapGetClassData(const DexFile * pDexFile,u4 classIdx,u4 * pNumMaps)841 const void* dvmRegisterMapGetClassData(const DexFile* pDexFile, u4 classIdx,
842 u4* pNumMaps)
843 {
844 const RegisterMapClassPool* pClassPool;
845 const RegisterMapMethodPool* pMethodPool;
846
847 pClassPool = (const RegisterMapClassPool*) pDexFile->pRegisterMapPool;
848 if (pClassPool == NULL)
849 return NULL;
850
851 if (classIdx >= pClassPool->numClasses) {
852 ALOGE("bad class index (%d vs %d)", classIdx, pClassPool->numClasses);
853 dvmAbort();
854 }
855
856 u4 classOffset = pClassPool->classDataOffset[classIdx];
857 if (classOffset == 0) {
858 ALOGV("+++ no map for classIdx=%d", classIdx);
859 return NULL;
860 }
861
862 pMethodPool =
863 (const RegisterMapMethodPool*) (((u1*) pClassPool) + classOffset);
864 if (pNumMaps != NULL)
865 *pNumMaps = pMethodPool->methodCount;
866 return pMethodPool->methodData;
867 }
868
869 /*
870 * This advances "*pPtr" and returns its original value.
871 */
dvmRegisterMapGetNext(const void ** pPtr)872 const RegisterMap* dvmRegisterMapGetNext(const void** pPtr)
873 {
874 const RegisterMap* pMap = (const RegisterMap*) *pPtr;
875
876 *pPtr = /*align32*/(((u1*) pMap) + computeRegisterMapSize(pMap));
877 LOGVV("getNext: %p -> %p (f=%#x w=%d e=%d)",
878 pMap, *pPtr, pMap->format, pMap->regWidth,
879 dvmRegisterMapGetNumEntries(pMap));
880 return pMap;
881 }
882
883
884 /*
885 * ===========================================================================
886 * Utility functions
887 * ===========================================================================
888 */
889
890 /*
891 * Return the data for the specified address, or NULL if not found.
892 *
893 * The result must be released with dvmReleaseRegisterMapLine().
894 */
dvmRegisterMapGetLine(const RegisterMap * pMap,int addr)895 const u1* dvmRegisterMapGetLine(const RegisterMap* pMap, int addr)
896 {
897 int addrWidth, lineWidth;
898 u1 format = dvmRegisterMapGetFormat(pMap);
899 u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
900
901 assert(numEntries > 0);
902
903 switch (format) {
904 case kRegMapFormatNone:
905 return NULL;
906 case kRegMapFormatCompact8:
907 addrWidth = 1;
908 break;
909 case kRegMapFormatCompact16:
910 addrWidth = 2;
911 break;
912 default:
913 ALOGE("Unknown format %d", format);
914 dvmAbort();
915 return NULL;
916 }
917
918 lineWidth = addrWidth + pMap->regWidth;
919
920 /*
921 * Find the appropriate entry. Many maps are very small, some are very
922 * large.
923 */
924 static const int kSearchThreshold = 8;
925 const u1* data = NULL;
926 int lineAddr;
927
928 if (numEntries < kSearchThreshold) {
929 int i;
930 data = pMap->data;
931 for (i = numEntries; i > 0; i--) {
932 lineAddr = data[0];
933 if (addrWidth > 1)
934 lineAddr |= data[1] << 8;
935 if (lineAddr == addr)
936 return data + addrWidth;
937
938 data += lineWidth;
939 }
940 assert(data == pMap->data + lineWidth * numEntries);
941 } else {
942 int hi, lo, mid;
943
944 lo = 0;
945 hi = numEntries -1;
946
947 while (hi >= lo) {
948 mid = (hi + lo) / 2;
949 data = pMap->data + lineWidth * mid;
950
951 lineAddr = data[0];
952 if (addrWidth > 1)
953 lineAddr |= data[1] << 8;
954
955 if (addr > lineAddr) {
956 lo = mid + 1;
957 } else if (addr < lineAddr) {
958 hi = mid - 1;
959 } else {
960 return data + addrWidth;
961 }
962 }
963 }
964
965 return NULL;
966 }
967
968 /*
969 * Compare two register maps.
970 *
971 * Returns 0 if they're equal, nonzero if not.
972 */
compareMaps(const RegisterMap * pMap1,const RegisterMap * pMap2)973 static int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2)
974 {
975 size_t size1, size2;
976
977 size1 = computeRegisterMapSize(pMap1);
978 size2 = computeRegisterMapSize(pMap2);
979 if (size1 != size2) {
980 ALOGI("compareMaps: size mismatch (%zd vs %zd)", size1, size2);
981 return -1;
982 }
983
984 if (memcmp(pMap1, pMap2, size1) != 0) {
985 ALOGI("compareMaps: content mismatch");
986 return -1;
987 }
988
989 return 0;
990 }
991
992
993 /*
994 * Get the expanded form of the register map associated with the method.
995 *
996 * If the map is already in one of the uncompressed formats, we return
997 * immediately. Otherwise, we expand the map and replace method's register
998 * map pointer, freeing it if it was allocated on the heap.
999 *
1000 * NOTE: this function is not synchronized; external locking is mandatory
1001 * (unless we're in the zygote, where single-threaded access is guaranteed).
1002 */
dvmGetExpandedRegisterMap0(Method * method)1003 const RegisterMap* dvmGetExpandedRegisterMap0(Method* method)
1004 {
1005 const RegisterMap* curMap = method->registerMap;
1006 RegisterMap* newMap;
1007
1008 if (curMap == NULL)
1009 return NULL;
1010
1011 /* sanity check to ensure this isn't called w/o external locking */
1012 /* (if we use this at a time other than during GC, fix/remove this test) */
1013 if (true) {
1014 if (!gDvm.zygote && dvmTryLockMutex(&gDvm.gcHeapLock) == 0) {
1015 ALOGE("GLITCH: dvmGetExpandedRegisterMap not called at GC time");
1016 dvmAbort();
1017 }
1018 }
1019
1020 RegisterMapFormat format = dvmRegisterMapGetFormat(curMap);
1021 switch (format) {
1022 case kRegMapFormatCompact8:
1023 case kRegMapFormatCompact16:
1024 if (REGISTER_MAP_VERBOSE) {
1025 if (dvmRegisterMapGetOnHeap(curMap)) {
1026 ALOGD("RegMap: already expanded: %s.%s",
1027 method->clazz->descriptor, method->name);
1028 } else {
1029 ALOGD("RegMap: stored w/o compression: %s.%s",
1030 method->clazz->descriptor, method->name);
1031 }
1032 }
1033 return curMap;
1034 case kRegMapFormatDifferential:
1035 newMap = uncompressMapDifferential(curMap);
1036 break;
1037 default:
1038 ALOGE("Unknown format %d in dvmGetExpandedRegisterMap", format);
1039 dvmAbort();
1040 newMap = NULL; // make gcc happy
1041 }
1042
1043 if (newMap == NULL) {
1044 ALOGE("Map failed to uncompress (fmt=%d) %s.%s",
1045 format, method->clazz->descriptor, method->name);
1046 return NULL;
1047 }
1048
1049 #ifdef REGISTER_MAP_STATS
1050 /*
1051 * Gather and display some stats.
1052 */
1053 {
1054 MapStats* pStats = (MapStats*) gDvm.registerMapStats;
1055 pStats->numExpandedMaps++;
1056 pStats->totalExpandedMapSize += computeRegisterMapSize(newMap);
1057 ALOGD("RMAP: count=%d size=%d",
1058 pStats->numExpandedMaps, pStats->totalExpandedMapSize);
1059 }
1060 #endif
1061
1062 IF_ALOGV() {
1063 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
1064 ALOGV("Expanding map -> %s.%s:%s",
1065 method->clazz->descriptor, method->name, desc);
1066 free(desc);
1067 }
1068
1069 /*
1070 * Update method, and free compressed map if it was sitting on the heap.
1071 */
1072 dvmSetRegisterMap(method, newMap);
1073
1074 if (dvmRegisterMapGetOnHeap(curMap))
1075 dvmFreeRegisterMap((RegisterMap*) curMap);
1076
1077 return newMap;
1078 }
1079
1080
1081 /*
1082 * ===========================================================================
1083 * Map compression
1084 * ===========================================================================
1085 */
1086
1087 /*
1088 Notes on map compression
1089
1090 The idea is to create a compressed form that will be uncompressed before
1091 use, with the output possibly saved in a cache. This means we can use an
1092 approach that is unsuited for random access if we choose.
1093
1094 In the event that a map simply does not work with our compression scheme,
1095 it's reasonable to store the map without compression. In the future we
1096 may want to have more than one compression scheme, and try each in turn,
1097 retaining the best. (We certainly want to keep the uncompressed form if it
1098 turns out to be smaller or even slightly larger than the compressed form.)
1099
1100 Each entry consists of an address and a bit vector. Adjacent entries are
1101 strongly correlated, suggesting differential encoding.
1102
1103
1104 Ideally we would avoid outputting adjacent entries with identical
1105 bit vectors. However, the register values at a given address do not
1106 imply anything about the set of valid registers at subsequent addresses.
1107 We therefore cannot omit an entry.
1108
1109 If the thread stack has a PC at an address without a corresponding
1110 entry in the register map, we must conservatively scan the registers in
1111 that thread. This can happen when single-stepping in the debugger,
1112 because the debugger is allowed to invoke arbitrary methods when
1113 a thread is stopped at a breakpoint. If we can guarantee that a GC
1114 thread scan will never happen while the debugger has that thread stopped,
1115 then we can lift this restriction and simply omit entries that don't
1116 change the bit vector from its previous state.
1117
1118 Each entry advances the address value by at least 1 (measured in 16-bit
1119 "code units"). Looking at the bootclasspath entries, advancing by 2 units
1120 is most common. Advances by 1 unit are far less common than advances by
1121 2 units, but more common than 5, and things fall off rapidly. Gaps of
1122 up to 220 code units appear in some computationally intensive bits of code,
1123 but are exceedingly rare.
1124
1125 If we sum up the number of transitions in a couple of ranges in framework.jar:
1126 [1,4]: 188998 of 218922 gaps (86.3%)
1127 [1,7]: 211647 of 218922 gaps (96.7%)
1128 Using a 3-bit delta, with one value reserved as an escape code, should
1129 yield good results for the address.
1130
1131 These results would change dramatically if we reduced the set of GC
1132 points by e.g. removing instructions like integer divide that are only
1133 present because they can throw and cause an allocation.
1134
1135 We also need to include an "initial gap", because the first few instructions
1136 in a method may not be GC points.
1137
1138
1139 By observation, many entries simply repeat the previous bit vector, or
1140 change only one or two bits. (This is with type-precise information;
1141 the rate of change of bits will be different if live-precise information
1142 is factored in).
1143
1144 Looking again at adjacent entries in framework.jar:
1145 0 bits changed: 63.0%
1146 1 bit changed: 32.2%
1147 After that it falls off rapidly, e.g. the number of entries with 2 bits
1148 changed is usually less than 1/10th of the number of entries with 1 bit
1149 changed. A solution that allows us to encode 0- or 1- bit changes
1150 efficiently will do well.
1151
1152 We still need to handle cases where a large number of bits change. We
1153 probably want a way to drop in a full copy of the bit vector when it's
1154 smaller than the representation of multiple bit changes.
1155
1156
1157 The bit-change information can be encoded as an index that tells the
1158 decoder to toggle the state. We want to encode the index in as few bits
1159 as possible, but we need to allow for fairly wide vectors (e.g. we have a
1160 method with 175 registers). We can deal with this in a couple of ways:
1161 (1) use an encoding that assumes few registers and has an escape code
1162 for larger numbers of registers; or (2) use different encodings based
1163 on how many total registers the method has. The choice depends to some
1164 extent on whether methods with large numbers of registers tend to modify
1165 the first 16 regs more often than the others.
1166
1167 The last N registers hold method arguments. If the bytecode is expected
1168 to be examined in a debugger, "dx" ensures that the contents of these
1169 registers won't change. Depending upon the encoding format, we may be
1170 able to take advantage of this. We still have to encode the initial
1171 state, but we know we'll never have to output a bit change for the last
1172 N registers.
1173
1174 Considering only methods with 16 or more registers, the "target octant"
1175 for register changes looks like this:
1176 [ 43.1%, 16.4%, 6.5%, 6.2%, 7.4%, 8.8%, 9.7%, 1.8% ]
1177 As expected, there are fewer changes at the end of the list where the
1178 arguments are kept, and more changes at the start of the list because
1179 register values smaller than 16 can be used in compact Dalvik instructions
1180 and hence are favored for frequently-used values. In general, the first
1181 octant is considerably more active than later entries, the last octant
1182 is much less active, and the rest are all about the same.
1183
1184 Looking at all bit changes in all methods, 94% are to registers 0-15. The
1185 encoding will benefit greatly by favoring the low-numbered registers.
1186
1187
1188 Some of the smaller methods have identical maps, and space could be
1189 saved by simply including a pointer to an earlier definition. This would
1190 be best accomplished by specifying a "pointer" format value, followed by
1191 a 3-byte (or ULEB128) offset. Implementing this would probably involve
1192 generating a hash value for each register map and maintaining a hash table.
1193
1194 In some cases there are repeating patterns in the bit vector that aren't
1195 adjacent. These could benefit from a dictionary encoding. This doesn't
1196 really become useful until the methods reach a certain size though,
1197 and managing the dictionary may incur more overhead than we want.
1198
1199 Large maps can be compressed significantly. The trouble is that, when
1200 we need to use them, we have to uncompress them onto the heap. We may
1201 get a better trade-off between storage size and heap usage by refusing to
1202 compress large maps, so that they can be memory mapped and used directly.
1203 (OTOH, only about 2% of the maps will ever actually be used.)
1204
1205
1206 ----- differential format -----
1207
1208 // common header
1209 +00 1B format
1210 +01 1B regWidth
1211 +02 2B numEntries (little-endian)
1212 +04 nB length in bytes of the data that follows, in ULEB128 format
1213 (not strictly necessary; allows determination of size w/o full parse)
1214 +05+ 1B initial address (0-127), high bit set if max addr >= 256
1215 +06+ nB initial value for bit vector
1216
1217 // for each entry
1218 +00: CCCCBAAA
1219
1220 AAA: address difference. Values from 0 to 6 indicate an increment of 1
1221 to 7. A value of 7 indicates that the address difference is large,
1222 and the next byte is a ULEB128-encoded difference value.
1223
1224 B: determines the meaning of CCCC.
1225
1226 CCCC: if B is 0, this is the number of the bit to toggle (0-15).
1227 If B is 1, this is a count of the number of changed bits (1-14). A value
1228 of 0 means that no bits were changed, and a value of 15 indicates
1229 that enough bits were changed that it required less space to output
1230 the entire bit vector.
1231
1232 +01: (optional) ULEB128-encoded address difference
1233
1234 +01+: (optional) one or more ULEB128-encoded bit numbers, OR the entire
1235 bit vector.
1236
1237 The most common situation is an entry whose address has changed by 2-4
1238 code units, has no changes or just a single bit change, and the changed
1239 register is less than 16. We should therefore be able to encode a large
1240 number of entries with a single byte, which is half the size of the
1241 Compact8 encoding method.
1242 */
1243
1244 /*
1245 * Compute some stats on an uncompressed register map.
1246 */
1247 #ifdef REGISTER_MAP_STATS
computeMapStats(RegisterMap * pMap,const Method * method)1248 static void computeMapStats(RegisterMap* pMap, const Method* method)
1249 {
1250 MapStats* pStats = (MapStats*) gDvm.registerMapStats;
1251 const u1 format = dvmRegisterMapGetFormat(pMap);
1252 const u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
1253 const u1* rawMap = pMap->data;
1254 const u1* prevData = NULL;
1255 int ent, addr, prevAddr = -1;
1256
1257 for (ent = 0; ent < numEntries; ent++) {
1258 switch (format) {
1259 case kRegMapFormatCompact8:
1260 addr = *rawMap++;
1261 break;
1262 case kRegMapFormatCompact16:
1263 addr = *rawMap++;
1264 addr |= (*rawMap++) << 8;
1265 break;
1266 default:
1267 /* shouldn't happen */
1268 ALOGE("GLITCH: bad format (%d)", format);
1269 dvmAbort();
1270 }
1271
1272 const u1* dataStart = rawMap;
1273
1274 pStats->totalGcPointCount++;
1275
1276 /*
1277 * Gather "gap size" stats, i.e. the difference in addresses between
1278 * successive GC points.
1279 */
1280 if (prevData != NULL) {
1281 assert(prevAddr >= 0);
1282 int addrDiff = addr - prevAddr;
1283
1284 if (addrDiff < 0) {
1285 ALOGE("GLITCH: address went backward (0x%04x->0x%04x, %s.%s)",
1286 prevAddr, addr, method->clazz->descriptor, method->name);
1287 } else if (addrDiff > kMaxGcPointGap) {
1288 if (REGISTER_MAP_VERBOSE) {
1289 ALOGI("HEY: addrDiff is %d, max %d (0x%04x->0x%04x %s.%s)",
1290 addrDiff, kMaxGcPointGap, prevAddr, addr,
1291 method->clazz->descriptor, method->name);
1292 }
1293 /* skip this one */
1294 } else {
1295 pStats->gcPointGap[addrDiff]++;
1296 }
1297 pStats->gcGapCount++;
1298
1299
1300 /*
1301 * Compare bit vectors in adjacent entries. We want to count
1302 * up the number of bits that differ (to see if we frequently
1303 * change 0 or 1 bits) and get a sense for which part of the
1304 * vector changes the most often (near the start, middle, end).
1305 *
1306 * We only do the vector position quantization if we have at
1307 * least 16 registers in the method.
1308 */
1309 int numDiff = 0;
1310 float div = (float) kNumUpdatePosns / method->registersSize;
1311 int regByte;
1312 for (regByte = 0; regByte < pMap->regWidth; regByte++) {
1313 int prev, cur, bit;
1314
1315 prev = prevData[regByte];
1316 cur = dataStart[regByte];
1317
1318 for (bit = 0; bit < 8; bit++) {
1319 if (((prev >> bit) & 1) != ((cur >> bit) & 1)) {
1320 numDiff++;
1321
1322 int bitNum = regByte * 8 + bit;
1323
1324 if (bitNum < 16)
1325 pStats->updateLT16++;
1326 else
1327 pStats->updateGE16++;
1328
1329 if (method->registersSize < 16)
1330 continue;
1331
1332 if (bitNum >= method->registersSize) {
1333 /* stuff off the end should be zero in both */
1334 ALOGE("WEIRD: bit=%d (%d/%d), prev=%02x cur=%02x",
1335 bit, regByte, method->registersSize,
1336 prev, cur);
1337 assert(false);
1338 }
1339 int idx = (int) (bitNum * div);
1340 if (!(idx >= 0 && idx < kNumUpdatePosns)) {
1341 ALOGE("FAIL: bitNum=%d (of %d) div=%.3f idx=%d",
1342 bitNum, method->registersSize, div, idx);
1343 assert(false);
1344 }
1345 pStats->updatePosn[idx]++;
1346 }
1347 }
1348 }
1349
1350 if (numDiff > kMaxDiffBits) {
1351 if (REGISTER_MAP_VERBOSE) {
1352 ALOGI("WOW: numDiff is %d, max %d", numDiff, kMaxDiffBits);
1353 }
1354 } else {
1355 pStats->numDiffBits[numDiff]++;
1356 }
1357 }
1358
1359 /* advance to start of next line */
1360 rawMap += pMap->regWidth;
1361
1362 prevAddr = addr;
1363 prevData = dataStart;
1364 }
1365 }
1366 #endif
1367
1368 /*
1369 * Compute the difference between two bit vectors.
1370 *
1371 * If "lebOutBuf" is non-NULL, we output the bit indices in ULEB128 format
1372 * as we go. Otherwise, we just generate the various counts.
1373 *
1374 * The bit vectors are compared byte-by-byte, so any unused bits at the
1375 * end must be zero.
1376 *
1377 * Returns the number of bytes required to hold the ULEB128 output.
1378 *
1379 * If "pFirstBitChanged" or "pNumBitsChanged" are non-NULL, they will
1380 * receive the index of the first changed bit and the number of changed
1381 * bits, respectively.
1382 */
computeBitDiff(const u1 * bits1,const u1 * bits2,int byteWidth,int * pFirstBitChanged,int * pNumBitsChanged,u1 * lebOutBuf)1383 static int computeBitDiff(const u1* bits1, const u1* bits2, int byteWidth,
1384 int* pFirstBitChanged, int* pNumBitsChanged, u1* lebOutBuf)
1385 {
1386 int numBitsChanged = 0;
1387 int firstBitChanged = -1;
1388 int lebSize = 0;
1389 int byteNum;
1390
1391 /*
1392 * Run through the vectors, first comparing them at the byte level. This
1393 * will yield a fairly quick result if nothing has changed between them.
1394 */
1395 for (byteNum = 0; byteNum < byteWidth; byteNum++) {
1396 u1 byte1 = *bits1++;
1397 u1 byte2 = *bits2++;
1398 if (byte1 != byte2) {
1399 /*
1400 * Walk through the byte, identifying the changed bits.
1401 */
1402 int bitNum;
1403 for (bitNum = 0; bitNum < 8; bitNum++) {
1404 if (((byte1 >> bitNum) & 0x01) != ((byte2 >> bitNum) & 0x01)) {
1405 int bitOffset = (byteNum << 3) + bitNum;
1406
1407 if (firstBitChanged < 0)
1408 firstBitChanged = bitOffset;
1409 numBitsChanged++;
1410
1411 if (lebOutBuf == NULL) {
1412 lebSize += unsignedLeb128Size(bitOffset);
1413 } else {
1414 u1* curBuf = lebOutBuf;
1415 lebOutBuf = writeUnsignedLeb128(lebOutBuf, bitOffset);
1416 lebSize += lebOutBuf - curBuf;
1417 }
1418 }
1419 }
1420 }
1421 }
1422
1423 if (numBitsChanged > 0)
1424 assert(firstBitChanged >= 0);
1425
1426 if (pFirstBitChanged != NULL)
1427 *pFirstBitChanged = firstBitChanged;
1428 if (pNumBitsChanged != NULL)
1429 *pNumBitsChanged = numBitsChanged;
1430
1431 return lebSize;
1432 }
1433
1434 /*
1435 * Compress the register map with differential encoding.
1436 *
1437 * "meth" is only needed for debug output.
1438 *
1439 * On success, returns a newly-allocated RegisterMap. If the map is not
1440 * compatible for some reason, or fails to get smaller, this will return NULL.
1441 */
compressMapDifferential(const RegisterMap * pMap,const Method * meth)1442 static RegisterMap* compressMapDifferential(const RegisterMap* pMap,
1443 const Method* meth)
1444 {
1445 RegisterMap* pNewMap = NULL;
1446 int origSize = computeRegisterMapSize(pMap);
1447 u1* tmpPtr;
1448 int addrWidth, regWidth, numEntries;
1449 bool debug = false;
1450
1451 if (false &&
1452 strcmp(meth->clazz->descriptor, "Landroid/text/StaticLayout;") == 0 &&
1453 strcmp(meth->name, "generate") == 0)
1454 {
1455 debug = true;
1456 }
1457
1458 u1 format = dvmRegisterMapGetFormat(pMap);
1459 switch (format) {
1460 case kRegMapFormatCompact8:
1461 addrWidth = 1;
1462 break;
1463 case kRegMapFormatCompact16:
1464 addrWidth = 2;
1465 break;
1466 default:
1467 ALOGE("ERROR: can't compress map with format=%d", format);
1468 return NULL;
1469 }
1470
1471 regWidth = dvmRegisterMapGetRegWidth(pMap);
1472 numEntries = dvmRegisterMapGetNumEntries(pMap);
1473
1474 if (debug) {
1475 ALOGI("COMPRESS: %s.%s aw=%d rw=%d ne=%d",
1476 meth->clazz->descriptor, meth->name,
1477 addrWidth, regWidth, numEntries);
1478 dumpRegisterMap(pMap, -1);
1479 }
1480
1481 if (numEntries <= 1) {
1482 ALOGV("Can't compress map with 0 or 1 entries");
1483 return NULL;
1484 }
1485
1486 /*
1487 * We don't know how large the compressed data will be. It's possible
1488 * for it to expand and become larger than the original. The header
1489 * itself is variable-sized, so we generate everything into a temporary
1490 * buffer and then copy it to form-fitting storage once we know how big
1491 * it will be (and that it's smaller than the original).
1492 *
1493 * If we use a size that is equal to the size of the input map plus
1494 * a value longer than a single entry can possibly expand to, we need
1495 * only check for overflow at the end of each entry. The worst case
1496 * for a single line is (1 + <ULEB8 address> + <full copy of vector>).
1497 * Addresses are 16 bits, so that's (1 + 3 + regWidth).
1498 *
1499 * The initial address offset and bit vector will take up less than
1500 * or equal to the amount of space required when uncompressed -- large
1501 * initial offsets are rejected.
1502 */
1503 UniquePtr<u1[]> tmpBuf(new u1[origSize + (1 + 3 + regWidth)]);
1504 if (tmpBuf.get() == NULL)
1505 return NULL;
1506
1507 tmpPtr = tmpBuf.get();
1508
1509 const u1* mapData = pMap->data;
1510 const u1* prevBits;
1511 u2 addr, prevAddr;
1512
1513 addr = *mapData++;
1514 if (addrWidth > 1)
1515 addr |= (*mapData++) << 8;
1516
1517 if (addr >= 128) {
1518 ALOGV("Can't compress map with starting address >= 128");
1519 return NULL;
1520 }
1521
1522 /*
1523 * Start by writing the initial address and bit vector data. The high
1524 * bit of the initial address is used to indicate the required address
1525 * width (which the decoder can't otherwise determine without parsing
1526 * the compressed data).
1527 */
1528 *tmpPtr++ = addr | (addrWidth > 1 ? 0x80 : 0x00);
1529 memcpy(tmpPtr, mapData, regWidth);
1530
1531 prevBits = mapData;
1532 prevAddr = addr;
1533
1534 tmpPtr += regWidth;
1535 mapData += regWidth;
1536
1537 /*
1538 * Loop over all following entries.
1539 */
1540 for (int entry = 1; entry < numEntries; entry++) {
1541 int addrDiff;
1542 u1 key;
1543
1544 /*
1545 * Pull out the address and figure out how to encode it.
1546 */
1547 addr = *mapData++;
1548 if (addrWidth > 1)
1549 addr |= (*mapData++) << 8;
1550
1551 if (debug)
1552 ALOGI(" addr=0x%04x ent=%d (aw=%d)", addr, entry, addrWidth);
1553
1554 addrDiff = addr - prevAddr;
1555 assert(addrDiff > 0);
1556 if (addrDiff < 8) {
1557 /* small difference, encode in 3 bits */
1558 key = addrDiff -1; /* set 00000AAA */
1559 if (debug)
1560 ALOGI(" : small %d, key=0x%02x", addrDiff, key);
1561 } else {
1562 /* large difference, output escape code */
1563 key = 0x07; /* escape code for AAA */
1564 if (debug)
1565 ALOGI(" : large %d, key=0x%02x", addrDiff, key);
1566 }
1567
1568 int numBitsChanged, firstBitChanged, lebSize;
1569
1570 lebSize = computeBitDiff(prevBits, mapData, regWidth,
1571 &firstBitChanged, &numBitsChanged, NULL);
1572
1573 if (debug) {
1574 ALOGI(" : diff fbc=%d nbc=%d ls=%d (rw=%d)",
1575 firstBitChanged, numBitsChanged, lebSize, regWidth);
1576 }
1577
1578 if (numBitsChanged == 0) {
1579 /* set B to 1 and CCCC to zero to indicate no bits were changed */
1580 key |= 0x08;
1581 if (debug) ALOGI(" : no bits changed");
1582 } else if (numBitsChanged == 1 && firstBitChanged < 16) {
1583 /* set B to 0 and CCCC to the index of the changed bit */
1584 key |= firstBitChanged << 4;
1585 if (debug) ALOGI(" : 1 low bit changed");
1586 } else if (numBitsChanged < 15 && lebSize < regWidth) {
1587 /* set B to 1 and CCCC to the number of bits */
1588 key |= 0x08 | (numBitsChanged << 4);
1589 if (debug) ALOGI(" : some bits changed");
1590 } else {
1591 /* set B to 1 and CCCC to 0x0f so we store the entire vector */
1592 key |= 0x08 | 0xf0;
1593 if (debug) ALOGI(" : encode original");
1594 }
1595
1596 /*
1597 * Encode output. Start with the key, follow with the address
1598 * diff (if it didn't fit in 3 bits), then the changed bit info.
1599 */
1600 *tmpPtr++ = key;
1601 if ((key & 0x07) == 0x07)
1602 tmpPtr = writeUnsignedLeb128(tmpPtr, addrDiff);
1603
1604 if ((key & 0x08) != 0) {
1605 int bitCount = key >> 4;
1606 if (bitCount == 0) {
1607 /* nothing changed, no additional output required */
1608 } else if (bitCount == 15) {
1609 /* full vector is most compact representation */
1610 memcpy(tmpPtr, mapData, regWidth);
1611 tmpPtr += regWidth;
1612 } else {
1613 /* write bit indices in LEB128 format */
1614 (void) computeBitDiff(prevBits, mapData, regWidth,
1615 NULL, NULL, tmpPtr);
1616 tmpPtr += lebSize;
1617 }
1618 } else {
1619 /* single-bit changed, value encoded in key byte */
1620 }
1621
1622 prevBits = mapData;
1623 prevAddr = addr;
1624 mapData += regWidth;
1625
1626 /*
1627 * See if we've run past the original size.
1628 */
1629 if (tmpPtr - tmpBuf.get() >= origSize) {
1630 if (debug) {
1631 ALOGD("Compressed size >= original (%d vs %d): %s.%s",
1632 tmpPtr - tmpBuf.get(), origSize,
1633 meth->clazz->descriptor, meth->name);
1634 }
1635 return NULL;
1636 }
1637 }
1638
1639 /*
1640 * Create a RegisterMap with the contents.
1641 *
1642 * TODO: consider using a threshold other than merely ">=". We would
1643 * get poorer compression but potentially use less native heap space.
1644 */
1645 static const int kHeaderSize = offsetof(RegisterMap, data);
1646 int newDataSize = tmpPtr - tmpBuf.get();
1647 int newMapSize;
1648
1649 newMapSize = kHeaderSize + unsignedLeb128Size(newDataSize) + newDataSize;
1650 if (newMapSize >= origSize) {
1651 if (debug) {
1652 ALOGD("Final comp size >= original (%d vs %d): %s.%s",
1653 newMapSize, origSize, meth->clazz->descriptor, meth->name);
1654 }
1655 return NULL;
1656 }
1657
1658 pNewMap = (RegisterMap*) malloc(newMapSize);
1659 if (pNewMap == NULL)
1660 return NULL;
1661 dvmRegisterMapSetFormat(pNewMap, kRegMapFormatDifferential);
1662 dvmRegisterMapSetOnHeap(pNewMap, true);
1663 dvmRegisterMapSetRegWidth(pNewMap, regWidth);
1664 dvmRegisterMapSetNumEntries(pNewMap, numEntries);
1665
1666 tmpPtr = pNewMap->data;
1667 tmpPtr = writeUnsignedLeb128(tmpPtr, newDataSize);
1668 memcpy(tmpPtr, tmpBuf.get(), newDataSize);
1669
1670 if (REGISTER_MAP_VERBOSE) {
1671 ALOGD("Compression successful (%d -> %d) from aw=%d rw=%d ne=%d",
1672 computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap),
1673 addrWidth, regWidth, numEntries);
1674 }
1675
1676 return pNewMap;
1677 }
1678
1679 /*
1680 * Toggle the value of the "idx"th bit in "ptr".
1681 */
toggleBit(u1 * ptr,int idx)1682 static inline void toggleBit(u1* ptr, int idx)
1683 {
1684 ptr[idx >> 3] ^= 1 << (idx & 0x07);
1685 }
1686
1687 /*
1688 * Expand a compressed map to an uncompressed form.
1689 *
1690 * Returns a newly-allocated RegisterMap on success, or NULL on failure.
1691 *
1692 * TODO: consider using the linear allocator or a custom allocator with
1693 * LRU replacement for these instead of the native heap.
1694 */
uncompressMapDifferential(const RegisterMap * pMap)1695 static RegisterMap* uncompressMapDifferential(const RegisterMap* pMap)
1696 {
1697 static const int kHeaderSize = offsetof(RegisterMap, data);
1698 u1 format = dvmRegisterMapGetFormat(pMap);
1699 RegisterMapFormat newFormat;
1700 int regWidth, numEntries, newAddrWidth, newMapSize;
1701
1702 if (format != kRegMapFormatDifferential) {
1703 ALOGE("Not differential (%d)", format);
1704 return NULL;
1705 }
1706
1707 regWidth = dvmRegisterMapGetRegWidth(pMap);
1708 numEntries = dvmRegisterMapGetNumEntries(pMap);
1709
1710 /* get the data size; we can check this at the end */
1711 const u1* srcPtr = pMap->data;
1712 int expectedSrcLen = readUnsignedLeb128(&srcPtr);
1713 const u1* srcStart = srcPtr;
1714
1715 /* get the initial address and the 16-bit address flag */
1716 int addr = *srcPtr & 0x7f;
1717 if ((*srcPtr & 0x80) == 0) {
1718 newFormat = kRegMapFormatCompact8;
1719 newAddrWidth = 1;
1720 } else {
1721 newFormat = kRegMapFormatCompact16;
1722 newAddrWidth = 2;
1723 }
1724 srcPtr++;
1725
1726 /* now we know enough to allocate the new map */
1727 if (REGISTER_MAP_VERBOSE) {
1728 ALOGI("Expanding to map aw=%d rw=%d ne=%d",
1729 newAddrWidth, regWidth, numEntries);
1730 }
1731 newMapSize = kHeaderSize + (newAddrWidth + regWidth) * numEntries;
1732 RegisterMap* pNewMap = (RegisterMap*) malloc(newMapSize);
1733
1734 if (pNewMap == NULL)
1735 return NULL;
1736
1737 dvmRegisterMapSetFormat(pNewMap, newFormat);
1738 dvmRegisterMapSetOnHeap(pNewMap, true);
1739 dvmRegisterMapSetRegWidth(pNewMap, regWidth);
1740 dvmRegisterMapSetNumEntries(pNewMap, numEntries);
1741
1742 /*
1743 * Write the start address and initial bits to the new map.
1744 */
1745 u1* dstPtr = pNewMap->data;
1746
1747 *dstPtr++ = addr & 0xff;
1748 if (newAddrWidth > 1)
1749 *dstPtr++ = (u1) (addr >> 8);
1750
1751 memcpy(dstPtr, srcPtr, regWidth);
1752
1753 int prevAddr = addr;
1754 const u1* prevBits = dstPtr; /* point at uncompressed data */
1755
1756 dstPtr += regWidth;
1757 srcPtr += regWidth;
1758
1759 /*
1760 * Walk through, uncompressing one line at a time.
1761 */
1762 int entry;
1763 for (entry = 1; entry < numEntries; entry++) {
1764 int addrDiff;
1765 u1 key;
1766
1767 key = *srcPtr++;
1768
1769 /* get the address */
1770 if ((key & 0x07) == 7) {
1771 /* address diff follows in ULEB128 */
1772 addrDiff = readUnsignedLeb128(&srcPtr);
1773 } else {
1774 addrDiff = (key & 0x07) +1;
1775 }
1776
1777 addr = prevAddr + addrDiff;
1778 *dstPtr++ = addr & 0xff;
1779 if (newAddrWidth > 1)
1780 *dstPtr++ = (u1) (addr >> 8);
1781
1782 /* unpack the bits */
1783 if ((key & 0x08) != 0) {
1784 int bitCount = (key >> 4);
1785 if (bitCount == 0) {
1786 /* no bits changed, just copy previous */
1787 memcpy(dstPtr, prevBits, regWidth);
1788 } else if (bitCount == 15) {
1789 /* full copy of bit vector is present; ignore prevBits */
1790 memcpy(dstPtr, srcPtr, regWidth);
1791 srcPtr += regWidth;
1792 } else {
1793 /* copy previous bits and modify listed indices */
1794 memcpy(dstPtr, prevBits, regWidth);
1795 while (bitCount--) {
1796 int bitIndex = readUnsignedLeb128(&srcPtr);
1797 toggleBit(dstPtr, bitIndex);
1798 }
1799 }
1800 } else {
1801 /* copy previous bits and modify the specified one */
1802 memcpy(dstPtr, prevBits, regWidth);
1803
1804 /* one bit, from 0-15 inclusive, was changed */
1805 toggleBit(dstPtr, key >> 4);
1806 }
1807
1808 prevAddr = addr;
1809 prevBits = dstPtr;
1810 dstPtr += regWidth;
1811 }
1812
1813 if (dstPtr - (u1*) pNewMap != newMapSize) {
1814 ALOGE("ERROR: output %d bytes, expected %d",
1815 dstPtr - (u1*) pNewMap, newMapSize);
1816 free(pNewMap);
1817 return NULL;
1818 }
1819
1820 if (srcPtr - srcStart != expectedSrcLen) {
1821 ALOGE("ERROR: consumed %d bytes, expected %d",
1822 srcPtr - srcStart, expectedSrcLen);
1823 free(pNewMap);
1824 return NULL;
1825 }
1826
1827 if (REGISTER_MAP_VERBOSE) {
1828 ALOGD("Expansion successful (%d -> %d)",
1829 computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap));
1830 }
1831
1832 return pNewMap;
1833 }
1834