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 /* Make compiler happy */
512 addr = 0;
513 }
514
515 const RegType* regs = vdata->registerLines[addr].regTypes;
516 if (regs == NULL) {
517 ALOGE("GLITCH: addr %d has no data", addr);
518 return false;
519 }
520
521 u1 val = 0;
522 int i;
523
524 for (i = 0; i < vdata->method->registersSize; i++) {
525 bool bitIsRef, regIsRef;
526
527 val >>= 1;
528 if ((i & 0x07) == 0) {
529 /* load next byte of data */
530 val = *rawMap++;
531 }
532
533 bitIsRef = val & 0x01;
534
535 RegType type = regs[i];
536 regIsRef = isReferenceType(type);
537
538 if (bitIsRef != regIsRef) {
539 ALOGE("GLITCH: addr %d reg %d: bit=%d reg=%d(%d)",
540 addr, i, bitIsRef, regIsRef, type);
541 return false;
542 }
543 }
544
545 /* rawMap now points to the address field of the next entry */
546 }
547
548 if (dumpMap)
549 dumpRegisterMap(pMap, vdata->method->registersSize);
550
551 return true;
552 }
553
554
555 /*
556 * ===========================================================================
557 * DEX generation & parsing
558 * ===========================================================================
559 */
560
561 /*
562 * Advance "ptr" to ensure 32-bit alignment.
563 */
align32(u1 * ptr)564 static inline u1* align32(u1* ptr)
565 {
566 return (u1*) (((int) ptr + 3) & ~0x03);
567 }
568
569 /*
570 * Compute the size, in bytes, of a register map.
571 */
computeRegisterMapSize(const RegisterMap * pMap)572 static size_t computeRegisterMapSize(const RegisterMap* pMap)
573 {
574 static const int kHeaderSize = offsetof(RegisterMap, data);
575 u1 format = dvmRegisterMapGetFormat(pMap);
576 u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
577
578 assert(pMap != NULL);
579
580 switch (format) {
581 case kRegMapFormatNone:
582 return 1;
583 case kRegMapFormatCompact8:
584 return kHeaderSize + (1 + pMap->regWidth) * numEntries;
585 case kRegMapFormatCompact16:
586 return kHeaderSize + (2 + pMap->regWidth) * numEntries;
587 case kRegMapFormatDifferential:
588 {
589 /* kHeaderSize + decoded ULEB128 length */
590 const u1* ptr = pMap->data;
591 int len = readUnsignedLeb128(&ptr);
592 return len + (ptr - (u1*) pMap);
593 }
594 default:
595 ALOGE("Bad register map format %d", format);
596 dvmAbort();
597 return 0;
598 }
599 }
600
601 /*
602 * Output the map for a single method, if it has one.
603 *
604 * Abstract and native methods have no map. All others are expected to
605 * have one, since we know the class verified successfully.
606 *
607 * This strips the "allocated on heap" flag from the format byte, so that
608 * direct-mapped maps are correctly identified as such.
609 */
writeMapForMethod(const Method * meth,u1 ** pPtr)610 static bool writeMapForMethod(const Method* meth, u1** pPtr)
611 {
612 if (meth->registerMap == NULL) {
613 if (!dvmIsAbstractMethod(meth) && !dvmIsNativeMethod(meth)) {
614 ALOGW("Warning: no map available for %s.%s",
615 meth->clazz->descriptor, meth->name);
616 /* weird, but keep going */
617 }
618 *(*pPtr)++ = kRegMapFormatNone;
619 return true;
620 }
621
622 /* serialize map into the buffer */
623 size_t mapSize = computeRegisterMapSize(meth->registerMap);
624 memcpy(*pPtr, meth->registerMap, mapSize);
625
626 /* strip the "on heap" flag out of the format byte, which is always first */
627 assert(**pPtr == meth->registerMap->format);
628 **pPtr &= ~(kRegMapFormatOnHeap);
629
630 *pPtr += mapSize;
631
632 return true;
633 }
634
635 /*
636 * Write maps for all methods in the specified class to the buffer, which
637 * can hold at most "length" bytes. "*pPtr" will be advanced past the end
638 * of the data we write.
639 */
writeMapsAllMethods(DvmDex * pDvmDex,const ClassObject * clazz,u1 ** pPtr,size_t length)640 static bool writeMapsAllMethods(DvmDex* pDvmDex, const ClassObject* clazz,
641 u1** pPtr, size_t length)
642 {
643 RegisterMapMethodPool* pMethodPool;
644 u1* ptr = *pPtr;
645 int i, methodCount;
646
647 /* artificial limit */
648 if (clazz->virtualMethodCount + clazz->directMethodCount >= 65536) {
649 ALOGE("Too many methods in %s", clazz->descriptor);
650 return false;
651 }
652
653 pMethodPool = (RegisterMapMethodPool*) ptr;
654 ptr += offsetof(RegisterMapMethodPool, methodData);
655 methodCount = 0;
656
657 /*
658 * Run through all methods, direct then virtual. The class loader will
659 * traverse them in the same order. (We could split them into two
660 * distinct pieces, but there doesn't appear to be any value in doing
661 * so other than that it makes class loading slightly less fragile.)
662 *
663 * The class loader won't know about miranda methods at the point
664 * where it parses this, so we omit those.
665 *
666 * TODO: consider omitting all native/abstract definitions. Should be
667 * safe, though we lose the ability to sanity-check against the
668 * method counts in the DEX file.
669 */
670 for (i = 0; i < clazz->directMethodCount; i++) {
671 const Method* meth = &clazz->directMethods[i];
672 if (dvmIsMirandaMethod(meth))
673 continue;
674 if (!writeMapForMethod(&clazz->directMethods[i], &ptr)) {
675 return false;
676 }
677 methodCount++;
678 //ptr = align32(ptr);
679 }
680
681 for (i = 0; i < clazz->virtualMethodCount; i++) {
682 const Method* meth = &clazz->virtualMethods[i];
683 if (dvmIsMirandaMethod(meth))
684 continue;
685 if (!writeMapForMethod(&clazz->virtualMethods[i], &ptr)) {
686 return false;
687 }
688 methodCount++;
689 //ptr = align32(ptr);
690 }
691
692 pMethodPool->methodCount = methodCount;
693
694 *pPtr = ptr;
695 return true;
696 }
697
698 /*
699 * Write maps for all classes to the specified buffer, which can hold at
700 * most "length" bytes.
701 *
702 * Returns the actual length used, or 0 on failure.
703 */
writeMapsAllClasses(DvmDex * pDvmDex,u1 * basePtr,size_t length)704 static size_t writeMapsAllClasses(DvmDex* pDvmDex, u1* basePtr, size_t length)
705 {
706 DexFile* pDexFile = pDvmDex->pDexFile;
707 u4 count = pDexFile->pHeader->classDefsSize;
708 RegisterMapClassPool* pClassPool;
709 u4* offsetTable;
710 u1* ptr = basePtr;
711 u4 idx;
712
713 assert(gDvm.optimizing);
714
715 pClassPool = (RegisterMapClassPool*) ptr;
716 ptr += offsetof(RegisterMapClassPool, classDataOffset);
717 offsetTable = (u4*) ptr;
718 ptr += count * sizeof(u4);
719
720 pClassPool->numClasses = count;
721
722 /*
723 * We want an entry for every class, loaded or not.
724 */
725 for (idx = 0; idx < count; idx++) {
726 const DexClassDef* pClassDef;
727 const char* classDescriptor;
728 ClassObject* clazz;
729
730 pClassDef = dexGetClassDef(pDexFile, idx);
731 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
732
733 /*
734 * All classes have been loaded into the bootstrap class loader.
735 * If we can find it, and it was successfully pre-verified, we
736 * run through its methods and add the register maps.
737 *
738 * If it wasn't pre-verified then we know it can't have any
739 * register maps. Classes that can't be loaded or failed
740 * verification get an empty slot in the index.
741 */
742 clazz = NULL;
743 if ((pClassDef->accessFlags & CLASS_ISPREVERIFIED) != 0)
744 clazz = dvmLookupClass(classDescriptor, NULL, false);
745
746 if (clazz != NULL) {
747 offsetTable[idx] = ptr - basePtr;
748 LOGVV("%d -> offset %d (%p-%p)",
749 idx, offsetTable[idx], ptr, basePtr);
750
751 if (!writeMapsAllMethods(pDvmDex, clazz, &ptr,
752 length - (ptr - basePtr)))
753 {
754 return 0;
755 }
756
757 ptr = align32(ptr);
758 LOGVV("Size %s (%d+%d methods): %d", clazz->descriptor,
759 clazz->directMethodCount, clazz->virtualMethodCount,
760 (ptr - basePtr) - offsetTable[idx]);
761 } else {
762 ALOGV("%4d NOT mapadding '%s'", idx, classDescriptor);
763 assert(offsetTable[idx] == 0);
764 }
765 }
766
767 if (ptr - basePtr >= (int)length) {
768 /* a bit late */
769 ALOGE("Buffer overrun");
770 dvmAbort();
771 }
772
773 return ptr - basePtr;
774 }
775
776 /*
777 * Generate a register map set for all verified classes in "pDvmDex".
778 */
dvmGenerateRegisterMaps(DvmDex * pDvmDex)779 RegisterMapBuilder* dvmGenerateRegisterMaps(DvmDex* pDvmDex)
780 {
781 RegisterMapBuilder* pBuilder;
782
783 pBuilder = (RegisterMapBuilder*) calloc(1, sizeof(RegisterMapBuilder));
784 if (pBuilder == NULL)
785 return NULL;
786
787 /*
788 * We have a couple of options here:
789 * (1) Compute the size of the output, and malloc a buffer.
790 * (2) Create a "large-enough" anonymous mmap region.
791 *
792 * The nice thing about option #2 is that we don't have to traverse
793 * all of the classes and methods twice. The risk is that we might
794 * not make the region large enough. Since the pages aren't mapped
795 * until used we can allocate a semi-absurd amount of memory without
796 * worrying about the effect on the rest of the system.
797 *
798 * The basic encoding on the largest jar file requires about 1MB of
799 * storage. We map out 4MB here. (TODO: guarantee that the last
800 * page of the mapping is marked invalid, so we reliably fail if
801 * we overrun.)
802 */
803 if (sysCreatePrivateMap(4 * 1024 * 1024, &pBuilder->memMap) != 0) {
804 free(pBuilder);
805 return NULL;
806 }
807
808 /*
809 * Create the maps.
810 */
811 size_t actual = writeMapsAllClasses(pDvmDex, (u1*)pBuilder->memMap.addr,
812 pBuilder->memMap.length);
813 if (actual == 0) {
814 dvmFreeRegisterMapBuilder(pBuilder);
815 return NULL;
816 }
817
818 ALOGV("TOTAL size of register maps: %d", actual);
819
820 pBuilder->data = pBuilder->memMap.addr;
821 pBuilder->size = actual;
822 return pBuilder;
823 }
824
825 /*
826 * Free the builder.
827 */
dvmFreeRegisterMapBuilder(RegisterMapBuilder * pBuilder)828 void dvmFreeRegisterMapBuilder(RegisterMapBuilder* pBuilder)
829 {
830 if (pBuilder == NULL)
831 return;
832
833 sysReleaseShmem(&pBuilder->memMap);
834 free(pBuilder);
835 }
836
837
838 /*
839 * Find the data for the specified class.
840 *
841 * If there's no register map data, or none for this class, we return NULL.
842 */
dvmRegisterMapGetClassData(const DexFile * pDexFile,u4 classIdx,u4 * pNumMaps)843 const void* dvmRegisterMapGetClassData(const DexFile* pDexFile, u4 classIdx,
844 u4* pNumMaps)
845 {
846 const RegisterMapClassPool* pClassPool;
847 const RegisterMapMethodPool* pMethodPool;
848
849 pClassPool = (const RegisterMapClassPool*) pDexFile->pRegisterMapPool;
850 if (pClassPool == NULL)
851 return NULL;
852
853 if (classIdx >= pClassPool->numClasses) {
854 ALOGE("bad class index (%d vs %d)", classIdx, pClassPool->numClasses);
855 dvmAbort();
856 }
857
858 u4 classOffset = pClassPool->classDataOffset[classIdx];
859 if (classOffset == 0) {
860 ALOGV("+++ no map for classIdx=%d", classIdx);
861 return NULL;
862 }
863
864 pMethodPool =
865 (const RegisterMapMethodPool*) (((u1*) pClassPool) + classOffset);
866 if (pNumMaps != NULL)
867 *pNumMaps = pMethodPool->methodCount;
868 return pMethodPool->methodData;
869 }
870
871 /*
872 * This advances "*pPtr" and returns its original value.
873 */
dvmRegisterMapGetNext(const void ** pPtr)874 const RegisterMap* dvmRegisterMapGetNext(const void** pPtr)
875 {
876 const RegisterMap* pMap = (const RegisterMap*) *pPtr;
877
878 *pPtr = /*align32*/(((u1*) pMap) + computeRegisterMapSize(pMap));
879 LOGVV("getNext: %p -> %p (f=%#x w=%d e=%d)",
880 pMap, *pPtr, pMap->format, pMap->regWidth,
881 dvmRegisterMapGetNumEntries(pMap));
882 return pMap;
883 }
884
885
886 /*
887 * ===========================================================================
888 * Utility functions
889 * ===========================================================================
890 */
891
892 /*
893 * Return the data for the specified address, or NULL if not found.
894 *
895 * The result must be released with dvmReleaseRegisterMapLine().
896 */
dvmRegisterMapGetLine(const RegisterMap * pMap,int addr)897 const u1* dvmRegisterMapGetLine(const RegisterMap* pMap, int addr)
898 {
899 int addrWidth, lineWidth;
900 u1 format = dvmRegisterMapGetFormat(pMap);
901 u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
902
903 assert(numEntries > 0);
904
905 switch (format) {
906 case kRegMapFormatNone:
907 return NULL;
908 case kRegMapFormatCompact8:
909 addrWidth = 1;
910 break;
911 case kRegMapFormatCompact16:
912 addrWidth = 2;
913 break;
914 default:
915 ALOGE("Unknown format %d", format);
916 dvmAbort();
917 return NULL;
918 }
919
920 lineWidth = addrWidth + pMap->regWidth;
921
922 /*
923 * Find the appropriate entry. Many maps are very small, some are very
924 * large.
925 */
926 static const int kSearchThreshold = 8;
927 const u1* data = NULL;
928 int lineAddr;
929
930 if (numEntries < kSearchThreshold) {
931 int i;
932 data = pMap->data;
933 for (i = numEntries; i > 0; i--) {
934 lineAddr = data[0];
935 if (addrWidth > 1)
936 lineAddr |= data[1] << 8;
937 if (lineAddr == addr)
938 return data + addrWidth;
939
940 data += lineWidth;
941 }
942 assert(data == pMap->data + lineWidth * numEntries);
943 } else {
944 int hi, lo, mid;
945
946 lo = 0;
947 hi = numEntries -1;
948
949 while (hi >= lo) {
950 mid = (hi + lo) / 2;
951 data = pMap->data + lineWidth * mid;
952
953 lineAddr = data[0];
954 if (addrWidth > 1)
955 lineAddr |= data[1] << 8;
956
957 if (addr > lineAddr) {
958 lo = mid + 1;
959 } else if (addr < lineAddr) {
960 hi = mid - 1;
961 } else {
962 return data + addrWidth;
963 }
964 }
965 }
966
967 return NULL;
968 }
969
970 /*
971 * Compare two register maps.
972 *
973 * Returns 0 if they're equal, nonzero if not.
974 */
compareMaps(const RegisterMap * pMap1,const RegisterMap * pMap2)975 static int compareMaps(const RegisterMap* pMap1, const RegisterMap* pMap2)
976 {
977 size_t size1, size2;
978
979 size1 = computeRegisterMapSize(pMap1);
980 size2 = computeRegisterMapSize(pMap2);
981 if (size1 != size2) {
982 ALOGI("compareMaps: size mismatch (%zd vs %zd)", size1, size2);
983 return -1;
984 }
985
986 if (memcmp(pMap1, pMap2, size1) != 0) {
987 ALOGI("compareMaps: content mismatch");
988 return -1;
989 }
990
991 return 0;
992 }
993
994
995 /*
996 * Get the expanded form of the register map associated with the method.
997 *
998 * If the map is already in one of the uncompressed formats, we return
999 * immediately. Otherwise, we expand the map and replace method's register
1000 * map pointer, freeing it if it was allocated on the heap.
1001 *
1002 * NOTE: this function is not synchronized; external locking is mandatory
1003 * (unless we're in the zygote, where single-threaded access is guaranteed).
1004 */
dvmGetExpandedRegisterMap0(Method * method)1005 const RegisterMap* dvmGetExpandedRegisterMap0(Method* method)
1006 {
1007 const RegisterMap* curMap = method->registerMap;
1008 RegisterMap* newMap;
1009
1010 if (curMap == NULL)
1011 return NULL;
1012
1013 /* sanity check to ensure this isn't called w/o external locking */
1014 /* (if we use this at a time other than during GC, fix/remove this test) */
1015 if (true) {
1016 if (!gDvm.zygote && dvmTryLockMutex(&gDvm.gcHeapLock) == 0) {
1017 ALOGE("GLITCH: dvmGetExpandedRegisterMap not called at GC time");
1018 dvmAbort();
1019 }
1020 }
1021
1022 RegisterMapFormat format = dvmRegisterMapGetFormat(curMap);
1023 switch (format) {
1024 case kRegMapFormatCompact8:
1025 case kRegMapFormatCompact16:
1026 if (REGISTER_MAP_VERBOSE) {
1027 if (dvmRegisterMapGetOnHeap(curMap)) {
1028 ALOGD("RegMap: already expanded: %s.%s",
1029 method->clazz->descriptor, method->name);
1030 } else {
1031 ALOGD("RegMap: stored w/o compression: %s.%s",
1032 method->clazz->descriptor, method->name);
1033 }
1034 }
1035 return curMap;
1036 case kRegMapFormatDifferential:
1037 newMap = uncompressMapDifferential(curMap);
1038 break;
1039 default:
1040 ALOGE("Unknown format %d in dvmGetExpandedRegisterMap", format);
1041 dvmAbort();
1042 newMap = NULL; // make gcc happy
1043 }
1044
1045 if (newMap == NULL) {
1046 ALOGE("Map failed to uncompress (fmt=%d) %s.%s",
1047 format, method->clazz->descriptor, method->name);
1048 return NULL;
1049 }
1050
1051 #ifdef REGISTER_MAP_STATS
1052 /*
1053 * Gather and display some stats.
1054 */
1055 {
1056 MapStats* pStats = (MapStats*) gDvm.registerMapStats;
1057 pStats->numExpandedMaps++;
1058 pStats->totalExpandedMapSize += computeRegisterMapSize(newMap);
1059 ALOGD("RMAP: count=%d size=%d",
1060 pStats->numExpandedMaps, pStats->totalExpandedMapSize);
1061 }
1062 #endif
1063
1064 IF_ALOGV() {
1065 char* desc = dexProtoCopyMethodDescriptor(&method->prototype);
1066 ALOGV("Expanding map -> %s.%s:%s",
1067 method->clazz->descriptor, method->name, desc);
1068 free(desc);
1069 }
1070
1071 /*
1072 * Update method, and free compressed map if it was sitting on the heap.
1073 */
1074 dvmSetRegisterMap(method, newMap);
1075
1076 if (dvmRegisterMapGetOnHeap(curMap))
1077 dvmFreeRegisterMap((RegisterMap*) curMap);
1078
1079 return newMap;
1080 }
1081
1082
1083 /*
1084 * ===========================================================================
1085 * Map compression
1086 * ===========================================================================
1087 */
1088
1089 /*
1090 Notes on map compression
1091
1092 The idea is to create a compressed form that will be uncompressed before
1093 use, with the output possibly saved in a cache. This means we can use an
1094 approach that is unsuited for random access if we choose.
1095
1096 In the event that a map simply does not work with our compression scheme,
1097 it's reasonable to store the map without compression. In the future we
1098 may want to have more than one compression scheme, and try each in turn,
1099 retaining the best. (We certainly want to keep the uncompressed form if it
1100 turns out to be smaller or even slightly larger than the compressed form.)
1101
1102 Each entry consists of an address and a bit vector. Adjacent entries are
1103 strongly correlated, suggesting differential encoding.
1104
1105
1106 Ideally we would avoid outputting adjacent entries with identical
1107 bit vectors. However, the register values at a given address do not
1108 imply anything about the set of valid registers at subsequent addresses.
1109 We therefore cannot omit an entry.
1110
1111 If the thread stack has a PC at an address without a corresponding
1112 entry in the register map, we must conservatively scan the registers in
1113 that thread. This can happen when single-stepping in the debugger,
1114 because the debugger is allowed to invoke arbitrary methods when
1115 a thread is stopped at a breakpoint. If we can guarantee that a GC
1116 thread scan will never happen while the debugger has that thread stopped,
1117 then we can lift this restriction and simply omit entries that don't
1118 change the bit vector from its previous state.
1119
1120 Each entry advances the address value by at least 1 (measured in 16-bit
1121 "code units"). Looking at the bootclasspath entries, advancing by 2 units
1122 is most common. Advances by 1 unit are far less common than advances by
1123 2 units, but more common than 5, and things fall off rapidly. Gaps of
1124 up to 220 code units appear in some computationally intensive bits of code,
1125 but are exceedingly rare.
1126
1127 If we sum up the number of transitions in a couple of ranges in framework.jar:
1128 [1,4]: 188998 of 218922 gaps (86.3%)
1129 [1,7]: 211647 of 218922 gaps (96.7%)
1130 Using a 3-bit delta, with one value reserved as an escape code, should
1131 yield good results for the address.
1132
1133 These results would change dramatically if we reduced the set of GC
1134 points by e.g. removing instructions like integer divide that are only
1135 present because they can throw and cause an allocation.
1136
1137 We also need to include an "initial gap", because the first few instructions
1138 in a method may not be GC points.
1139
1140
1141 By observation, many entries simply repeat the previous bit vector, or
1142 change only one or two bits. (This is with type-precise information;
1143 the rate of change of bits will be different if live-precise information
1144 is factored in).
1145
1146 Looking again at adjacent entries in framework.jar:
1147 0 bits changed: 63.0%
1148 1 bit changed: 32.2%
1149 After that it falls off rapidly, e.g. the number of entries with 2 bits
1150 changed is usually less than 1/10th of the number of entries with 1 bit
1151 changed. A solution that allows us to encode 0- or 1- bit changes
1152 efficiently will do well.
1153
1154 We still need to handle cases where a large number of bits change. We
1155 probably want a way to drop in a full copy of the bit vector when it's
1156 smaller than the representation of multiple bit changes.
1157
1158
1159 The bit-change information can be encoded as an index that tells the
1160 decoder to toggle the state. We want to encode the index in as few bits
1161 as possible, but we need to allow for fairly wide vectors (e.g. we have a
1162 method with 175 registers). We can deal with this in a couple of ways:
1163 (1) use an encoding that assumes few registers and has an escape code
1164 for larger numbers of registers; or (2) use different encodings based
1165 on how many total registers the method has. The choice depends to some
1166 extent on whether methods with large numbers of registers tend to modify
1167 the first 16 regs more often than the others.
1168
1169 The last N registers hold method arguments. If the bytecode is expected
1170 to be examined in a debugger, "dx" ensures that the contents of these
1171 registers won't change. Depending upon the encoding format, we may be
1172 able to take advantage of this. We still have to encode the initial
1173 state, but we know we'll never have to output a bit change for the last
1174 N registers.
1175
1176 Considering only methods with 16 or more registers, the "target octant"
1177 for register changes looks like this:
1178 [ 43.1%, 16.4%, 6.5%, 6.2%, 7.4%, 8.8%, 9.7%, 1.8% ]
1179 As expected, there are fewer changes at the end of the list where the
1180 arguments are kept, and more changes at the start of the list because
1181 register values smaller than 16 can be used in compact Dalvik instructions
1182 and hence are favored for frequently-used values. In general, the first
1183 octant is considerably more active than later entries, the last octant
1184 is much less active, and the rest are all about the same.
1185
1186 Looking at all bit changes in all methods, 94% are to registers 0-15. The
1187 encoding will benefit greatly by favoring the low-numbered registers.
1188
1189
1190 Some of the smaller methods have identical maps, and space could be
1191 saved by simply including a pointer to an earlier definition. This would
1192 be best accomplished by specifying a "pointer" format value, followed by
1193 a 3-byte (or ULEB128) offset. Implementing this would probably involve
1194 generating a hash value for each register map and maintaining a hash table.
1195
1196 In some cases there are repeating patterns in the bit vector that aren't
1197 adjacent. These could benefit from a dictionary encoding. This doesn't
1198 really become useful until the methods reach a certain size though,
1199 and managing the dictionary may incur more overhead than we want.
1200
1201 Large maps can be compressed significantly. The trouble is that, when
1202 we need to use them, we have to uncompress them onto the heap. We may
1203 get a better trade-off between storage size and heap usage by refusing to
1204 compress large maps, so that they can be memory mapped and used directly.
1205 (OTOH, only about 2% of the maps will ever actually be used.)
1206
1207
1208 ----- differential format -----
1209
1210 // common header
1211 +00 1B format
1212 +01 1B regWidth
1213 +02 2B numEntries (little-endian)
1214 +04 nB length in bytes of the data that follows, in ULEB128 format
1215 (not strictly necessary; allows determination of size w/o full parse)
1216 +05+ 1B initial address (0-127), high bit set if max addr >= 256
1217 +06+ nB initial value for bit vector
1218
1219 // for each entry
1220 +00: CCCCBAAA
1221
1222 AAA: address difference. Values from 0 to 6 indicate an increment of 1
1223 to 7. A value of 7 indicates that the address difference is large,
1224 and the next byte is a ULEB128-encoded difference value.
1225
1226 B: determines the meaning of CCCC.
1227
1228 CCCC: if B is 0, this is the number of the bit to toggle (0-15).
1229 If B is 1, this is a count of the number of changed bits (1-14). A value
1230 of 0 means that no bits were changed, and a value of 15 indicates
1231 that enough bits were changed that it required less space to output
1232 the entire bit vector.
1233
1234 +01: (optional) ULEB128-encoded address difference
1235
1236 +01+: (optional) one or more ULEB128-encoded bit numbers, OR the entire
1237 bit vector.
1238
1239 The most common situation is an entry whose address has changed by 2-4
1240 code units, has no changes or just a single bit change, and the changed
1241 register is less than 16. We should therefore be able to encode a large
1242 number of entries with a single byte, which is half the size of the
1243 Compact8 encoding method.
1244 */
1245
1246 /*
1247 * Compute some stats on an uncompressed register map.
1248 */
1249 #ifdef REGISTER_MAP_STATS
computeMapStats(RegisterMap * pMap,const Method * method)1250 static void computeMapStats(RegisterMap* pMap, const Method* method)
1251 {
1252 MapStats* pStats = (MapStats*) gDvm.registerMapStats;
1253 const u1 format = dvmRegisterMapGetFormat(pMap);
1254 const u2 numEntries = dvmRegisterMapGetNumEntries(pMap);
1255 const u1* rawMap = pMap->data;
1256 const u1* prevData = NULL;
1257 int ent, addr, prevAddr = -1;
1258
1259 for (ent = 0; ent < numEntries; ent++) {
1260 switch (format) {
1261 case kRegMapFormatCompact8:
1262 addr = *rawMap++;
1263 break;
1264 case kRegMapFormatCompact16:
1265 addr = *rawMap++;
1266 addr |= (*rawMap++) << 8;
1267 break;
1268 default:
1269 /* shouldn't happen */
1270 ALOGE("GLITCH: bad format (%d)", format);
1271 dvmAbort();
1272 }
1273
1274 const u1* dataStart = rawMap;
1275
1276 pStats->totalGcPointCount++;
1277
1278 /*
1279 * Gather "gap size" stats, i.e. the difference in addresses between
1280 * successive GC points.
1281 */
1282 if (prevData != NULL) {
1283 assert(prevAddr >= 0);
1284 int addrDiff = addr - prevAddr;
1285
1286 if (addrDiff < 0) {
1287 ALOGE("GLITCH: address went backward (0x%04x->0x%04x, %s.%s)",
1288 prevAddr, addr, method->clazz->descriptor, method->name);
1289 } else if (addrDiff > kMaxGcPointGap) {
1290 if (REGISTER_MAP_VERBOSE) {
1291 ALOGI("HEY: addrDiff is %d, max %d (0x%04x->0x%04x %s.%s)",
1292 addrDiff, kMaxGcPointGap, prevAddr, addr,
1293 method->clazz->descriptor, method->name);
1294 }
1295 /* skip this one */
1296 } else {
1297 pStats->gcPointGap[addrDiff]++;
1298 }
1299 pStats->gcGapCount++;
1300
1301
1302 /*
1303 * Compare bit vectors in adjacent entries. We want to count
1304 * up the number of bits that differ (to see if we frequently
1305 * change 0 or 1 bits) and get a sense for which part of the
1306 * vector changes the most often (near the start, middle, end).
1307 *
1308 * We only do the vector position quantization if we have at
1309 * least 16 registers in the method.
1310 */
1311 int numDiff = 0;
1312 float div = (float) kNumUpdatePosns / method->registersSize;
1313 int regByte;
1314 for (regByte = 0; regByte < pMap->regWidth; regByte++) {
1315 int prev, cur, bit;
1316
1317 prev = prevData[regByte];
1318 cur = dataStart[regByte];
1319
1320 for (bit = 0; bit < 8; bit++) {
1321 if (((prev >> bit) & 1) != ((cur >> bit) & 1)) {
1322 numDiff++;
1323
1324 int bitNum = regByte * 8 + bit;
1325
1326 if (bitNum < 16)
1327 pStats->updateLT16++;
1328 else
1329 pStats->updateGE16++;
1330
1331 if (method->registersSize < 16)
1332 continue;
1333
1334 if (bitNum >= method->registersSize) {
1335 /* stuff off the end should be zero in both */
1336 ALOGE("WEIRD: bit=%d (%d/%d), prev=%02x cur=%02x",
1337 bit, regByte, method->registersSize,
1338 prev, cur);
1339 assert(false);
1340 }
1341 int idx = (int) (bitNum * div);
1342 if (!(idx >= 0 && idx < kNumUpdatePosns)) {
1343 ALOGE("FAIL: bitNum=%d (of %d) div=%.3f idx=%d",
1344 bitNum, method->registersSize, div, idx);
1345 assert(false);
1346 }
1347 pStats->updatePosn[idx]++;
1348 }
1349 }
1350 }
1351
1352 if (numDiff > kMaxDiffBits) {
1353 if (REGISTER_MAP_VERBOSE) {
1354 ALOGI("WOW: numDiff is %d, max %d", numDiff, kMaxDiffBits);
1355 }
1356 } else {
1357 pStats->numDiffBits[numDiff]++;
1358 }
1359 }
1360
1361 /* advance to start of next line */
1362 rawMap += pMap->regWidth;
1363
1364 prevAddr = addr;
1365 prevData = dataStart;
1366 }
1367 }
1368 #endif
1369
1370 /*
1371 * Compute the difference between two bit vectors.
1372 *
1373 * If "lebOutBuf" is non-NULL, we output the bit indices in ULEB128 format
1374 * as we go. Otherwise, we just generate the various counts.
1375 *
1376 * The bit vectors are compared byte-by-byte, so any unused bits at the
1377 * end must be zero.
1378 *
1379 * Returns the number of bytes required to hold the ULEB128 output.
1380 *
1381 * If "pFirstBitChanged" or "pNumBitsChanged" are non-NULL, they will
1382 * receive the index of the first changed bit and the number of changed
1383 * bits, respectively.
1384 */
computeBitDiff(const u1 * bits1,const u1 * bits2,int byteWidth,int * pFirstBitChanged,int * pNumBitsChanged,u1 * lebOutBuf)1385 static int computeBitDiff(const u1* bits1, const u1* bits2, int byteWidth,
1386 int* pFirstBitChanged, int* pNumBitsChanged, u1* lebOutBuf)
1387 {
1388 int numBitsChanged = 0;
1389 int firstBitChanged = -1;
1390 int lebSize = 0;
1391 int byteNum;
1392
1393 /*
1394 * Run through the vectors, first comparing them at the byte level. This
1395 * will yield a fairly quick result if nothing has changed between them.
1396 */
1397 for (byteNum = 0; byteNum < byteWidth; byteNum++) {
1398 u1 byte1 = *bits1++;
1399 u1 byte2 = *bits2++;
1400 if (byte1 != byte2) {
1401 /*
1402 * Walk through the byte, identifying the changed bits.
1403 */
1404 int bitNum;
1405 for (bitNum = 0; bitNum < 8; bitNum++) {
1406 if (((byte1 >> bitNum) & 0x01) != ((byte2 >> bitNum) & 0x01)) {
1407 int bitOffset = (byteNum << 3) + bitNum;
1408
1409 if (firstBitChanged < 0)
1410 firstBitChanged = bitOffset;
1411 numBitsChanged++;
1412
1413 if (lebOutBuf == NULL) {
1414 lebSize += unsignedLeb128Size(bitOffset);
1415 } else {
1416 u1* curBuf = lebOutBuf;
1417 lebOutBuf = writeUnsignedLeb128(lebOutBuf, bitOffset);
1418 lebSize += lebOutBuf - curBuf;
1419 }
1420 }
1421 }
1422 }
1423 }
1424
1425 if (numBitsChanged > 0)
1426 assert(firstBitChanged >= 0);
1427
1428 if (pFirstBitChanged != NULL)
1429 *pFirstBitChanged = firstBitChanged;
1430 if (pNumBitsChanged != NULL)
1431 *pNumBitsChanged = numBitsChanged;
1432
1433 return lebSize;
1434 }
1435
1436 /*
1437 * Compress the register map with differential encoding.
1438 *
1439 * "meth" is only needed for debug output.
1440 *
1441 * On success, returns a newly-allocated RegisterMap. If the map is not
1442 * compatible for some reason, or fails to get smaller, this will return NULL.
1443 */
compressMapDifferential(const RegisterMap * pMap,const Method * meth)1444 static RegisterMap* compressMapDifferential(const RegisterMap* pMap,
1445 const Method* meth)
1446 {
1447 RegisterMap* pNewMap = NULL;
1448 int origSize = computeRegisterMapSize(pMap);
1449 u1* tmpPtr;
1450 int addrWidth, regWidth, numEntries;
1451 bool debug = false;
1452
1453 if (false &&
1454 strcmp(meth->clazz->descriptor, "Landroid/text/StaticLayout;") == 0 &&
1455 strcmp(meth->name, "generate") == 0)
1456 {
1457 debug = true;
1458 }
1459
1460 u1 format = dvmRegisterMapGetFormat(pMap);
1461 switch (format) {
1462 case kRegMapFormatCompact8:
1463 addrWidth = 1;
1464 break;
1465 case kRegMapFormatCompact16:
1466 addrWidth = 2;
1467 break;
1468 default:
1469 ALOGE("ERROR: can't compress map with format=%d", format);
1470 return NULL;
1471 }
1472
1473 regWidth = dvmRegisterMapGetRegWidth(pMap);
1474 numEntries = dvmRegisterMapGetNumEntries(pMap);
1475
1476 if (debug) {
1477 ALOGI("COMPRESS: %s.%s aw=%d rw=%d ne=%d",
1478 meth->clazz->descriptor, meth->name,
1479 addrWidth, regWidth, numEntries);
1480 dumpRegisterMap(pMap, -1);
1481 }
1482
1483 if (numEntries <= 1) {
1484 ALOGV("Can't compress map with 0 or 1 entries");
1485 return NULL;
1486 }
1487
1488 /*
1489 * We don't know how large the compressed data will be. It's possible
1490 * for it to expand and become larger than the original. The header
1491 * itself is variable-sized, so we generate everything into a temporary
1492 * buffer and then copy it to form-fitting storage once we know how big
1493 * it will be (and that it's smaller than the original).
1494 *
1495 * If we use a size that is equal to the size of the input map plus
1496 * a value longer than a single entry can possibly expand to, we need
1497 * only check for overflow at the end of each entry. The worst case
1498 * for a single line is (1 + <ULEB8 address> + <full copy of vector>).
1499 * Addresses are 16 bits, so that's (1 + 3 + regWidth).
1500 *
1501 * The initial address offset and bit vector will take up less than
1502 * or equal to the amount of space required when uncompressed -- large
1503 * initial offsets are rejected.
1504 */
1505 UniquePtr<u1[]> tmpBuf(new u1[origSize + (1 + 3 + regWidth)]);
1506 if (tmpBuf.get() == NULL)
1507 return NULL;
1508
1509 tmpPtr = tmpBuf.get();
1510
1511 const u1* mapData = pMap->data;
1512 const u1* prevBits;
1513 u2 addr, prevAddr;
1514
1515 addr = *mapData++;
1516 if (addrWidth > 1)
1517 addr |= (*mapData++) << 8;
1518
1519 if (addr >= 128) {
1520 ALOGV("Can't compress map with starting address >= 128");
1521 return NULL;
1522 }
1523
1524 /*
1525 * Start by writing the initial address and bit vector data. The high
1526 * bit of the initial address is used to indicate the required address
1527 * width (which the decoder can't otherwise determine without parsing
1528 * the compressed data).
1529 */
1530 *tmpPtr++ = addr | (addrWidth > 1 ? 0x80 : 0x00);
1531 memcpy(tmpPtr, mapData, regWidth);
1532
1533 prevBits = mapData;
1534 prevAddr = addr;
1535
1536 tmpPtr += regWidth;
1537 mapData += regWidth;
1538
1539 /*
1540 * Loop over all following entries.
1541 */
1542 for (int entry = 1; entry < numEntries; entry++) {
1543 int addrDiff;
1544 u1 key;
1545
1546 /*
1547 * Pull out the address and figure out how to encode it.
1548 */
1549 addr = *mapData++;
1550 if (addrWidth > 1)
1551 addr |= (*mapData++) << 8;
1552
1553 if (debug)
1554 ALOGI(" addr=0x%04x ent=%d (aw=%d)", addr, entry, addrWidth);
1555
1556 addrDiff = addr - prevAddr;
1557 assert(addrDiff > 0);
1558 if (addrDiff < 8) {
1559 /* small difference, encode in 3 bits */
1560 key = addrDiff -1; /* set 00000AAA */
1561 if (debug)
1562 ALOGI(" : small %d, key=0x%02x", addrDiff, key);
1563 } else {
1564 /* large difference, output escape code */
1565 key = 0x07; /* escape code for AAA */
1566 if (debug)
1567 ALOGI(" : large %d, key=0x%02x", addrDiff, key);
1568 }
1569
1570 int numBitsChanged, firstBitChanged, lebSize;
1571
1572 lebSize = computeBitDiff(prevBits, mapData, regWidth,
1573 &firstBitChanged, &numBitsChanged, NULL);
1574
1575 if (debug) {
1576 ALOGI(" : diff fbc=%d nbc=%d ls=%d (rw=%d)",
1577 firstBitChanged, numBitsChanged, lebSize, regWidth);
1578 }
1579
1580 if (numBitsChanged == 0) {
1581 /* set B to 1 and CCCC to zero to indicate no bits were changed */
1582 key |= 0x08;
1583 if (debug) ALOGI(" : no bits changed");
1584 } else if (numBitsChanged == 1 && firstBitChanged < 16) {
1585 /* set B to 0 and CCCC to the index of the changed bit */
1586 key |= firstBitChanged << 4;
1587 if (debug) ALOGI(" : 1 low bit changed");
1588 } else if (numBitsChanged < 15 && lebSize < regWidth) {
1589 /* set B to 1 and CCCC to the number of bits */
1590 key |= 0x08 | (numBitsChanged << 4);
1591 if (debug) ALOGI(" : some bits changed");
1592 } else {
1593 /* set B to 1 and CCCC to 0x0f so we store the entire vector */
1594 key |= 0x08 | 0xf0;
1595 if (debug) ALOGI(" : encode original");
1596 }
1597
1598 /*
1599 * Encode output. Start with the key, follow with the address
1600 * diff (if it didn't fit in 3 bits), then the changed bit info.
1601 */
1602 *tmpPtr++ = key;
1603 if ((key & 0x07) == 0x07)
1604 tmpPtr = writeUnsignedLeb128(tmpPtr, addrDiff);
1605
1606 if ((key & 0x08) != 0) {
1607 int bitCount = key >> 4;
1608 if (bitCount == 0) {
1609 /* nothing changed, no additional output required */
1610 } else if (bitCount == 15) {
1611 /* full vector is most compact representation */
1612 memcpy(tmpPtr, mapData, regWidth);
1613 tmpPtr += regWidth;
1614 } else {
1615 /* write bit indices in LEB128 format */
1616 (void) computeBitDiff(prevBits, mapData, regWidth,
1617 NULL, NULL, tmpPtr);
1618 tmpPtr += lebSize;
1619 }
1620 } else {
1621 /* single-bit changed, value encoded in key byte */
1622 }
1623
1624 prevBits = mapData;
1625 prevAddr = addr;
1626 mapData += regWidth;
1627
1628 /*
1629 * See if we've run past the original size.
1630 */
1631 if (tmpPtr - tmpBuf.get() >= origSize) {
1632 if (debug) {
1633 ALOGD("Compressed size >= original (%d vs %d): %s.%s",
1634 tmpPtr - tmpBuf.get(), origSize,
1635 meth->clazz->descriptor, meth->name);
1636 }
1637 return NULL;
1638 }
1639 }
1640
1641 /*
1642 * Create a RegisterMap with the contents.
1643 *
1644 * TODO: consider using a threshold other than merely ">=". We would
1645 * get poorer compression but potentially use less native heap space.
1646 */
1647 static const int kHeaderSize = offsetof(RegisterMap, data);
1648 int newDataSize = tmpPtr - tmpBuf.get();
1649 int newMapSize;
1650
1651 newMapSize = kHeaderSize + unsignedLeb128Size(newDataSize) + newDataSize;
1652 if (newMapSize >= origSize) {
1653 if (debug) {
1654 ALOGD("Final comp size >= original (%d vs %d): %s.%s",
1655 newMapSize, origSize, meth->clazz->descriptor, meth->name);
1656 }
1657 return NULL;
1658 }
1659
1660 pNewMap = (RegisterMap*) malloc(newMapSize);
1661 if (pNewMap == NULL)
1662 return NULL;
1663 dvmRegisterMapSetFormat(pNewMap, kRegMapFormatDifferential);
1664 dvmRegisterMapSetOnHeap(pNewMap, true);
1665 dvmRegisterMapSetRegWidth(pNewMap, regWidth);
1666 dvmRegisterMapSetNumEntries(pNewMap, numEntries);
1667
1668 tmpPtr = pNewMap->data;
1669 tmpPtr = writeUnsignedLeb128(tmpPtr, newDataSize);
1670 memcpy(tmpPtr, tmpBuf.get(), newDataSize);
1671
1672 if (REGISTER_MAP_VERBOSE) {
1673 ALOGD("Compression successful (%d -> %d) from aw=%d rw=%d ne=%d",
1674 computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap),
1675 addrWidth, regWidth, numEntries);
1676 }
1677
1678 return pNewMap;
1679 }
1680
1681 /*
1682 * Toggle the value of the "idx"th bit in "ptr".
1683 */
toggleBit(u1 * ptr,int idx)1684 static inline void toggleBit(u1* ptr, int idx)
1685 {
1686 ptr[idx >> 3] ^= 1 << (idx & 0x07);
1687 }
1688
1689 /*
1690 * Expand a compressed map to an uncompressed form.
1691 *
1692 * Returns a newly-allocated RegisterMap on success, or NULL on failure.
1693 *
1694 * TODO: consider using the linear allocator or a custom allocator with
1695 * LRU replacement for these instead of the native heap.
1696 */
uncompressMapDifferential(const RegisterMap * pMap)1697 static RegisterMap* uncompressMapDifferential(const RegisterMap* pMap)
1698 {
1699 static const int kHeaderSize = offsetof(RegisterMap, data);
1700 u1 format = dvmRegisterMapGetFormat(pMap);
1701 RegisterMapFormat newFormat;
1702 int regWidth, numEntries, newAddrWidth, newMapSize;
1703
1704 if (format != kRegMapFormatDifferential) {
1705 ALOGE("Not differential (%d)", format);
1706 return NULL;
1707 }
1708
1709 regWidth = dvmRegisterMapGetRegWidth(pMap);
1710 numEntries = dvmRegisterMapGetNumEntries(pMap);
1711
1712 /* get the data size; we can check this at the end */
1713 const u1* srcPtr = pMap->data;
1714 int expectedSrcLen = readUnsignedLeb128(&srcPtr);
1715 const u1* srcStart = srcPtr;
1716
1717 /* get the initial address and the 16-bit address flag */
1718 int addr = *srcPtr & 0x7f;
1719 if ((*srcPtr & 0x80) == 0) {
1720 newFormat = kRegMapFormatCompact8;
1721 newAddrWidth = 1;
1722 } else {
1723 newFormat = kRegMapFormatCompact16;
1724 newAddrWidth = 2;
1725 }
1726 srcPtr++;
1727
1728 /* now we know enough to allocate the new map */
1729 if (REGISTER_MAP_VERBOSE) {
1730 ALOGI("Expanding to map aw=%d rw=%d ne=%d",
1731 newAddrWidth, regWidth, numEntries);
1732 }
1733 newMapSize = kHeaderSize + (newAddrWidth + regWidth) * numEntries;
1734 RegisterMap* pNewMap = (RegisterMap*) malloc(newMapSize);
1735
1736 if (pNewMap == NULL)
1737 return NULL;
1738
1739 dvmRegisterMapSetFormat(pNewMap, newFormat);
1740 dvmRegisterMapSetOnHeap(pNewMap, true);
1741 dvmRegisterMapSetRegWidth(pNewMap, regWidth);
1742 dvmRegisterMapSetNumEntries(pNewMap, numEntries);
1743
1744 /*
1745 * Write the start address and initial bits to the new map.
1746 */
1747 u1* dstPtr = pNewMap->data;
1748
1749 *dstPtr++ = addr & 0xff;
1750 if (newAddrWidth > 1)
1751 *dstPtr++ = (u1) (addr >> 8);
1752
1753 memcpy(dstPtr, srcPtr, regWidth);
1754
1755 int prevAddr = addr;
1756 const u1* prevBits = dstPtr; /* point at uncompressed data */
1757
1758 dstPtr += regWidth;
1759 srcPtr += regWidth;
1760
1761 /*
1762 * Walk through, uncompressing one line at a time.
1763 */
1764 int entry;
1765 for (entry = 1; entry < numEntries; entry++) {
1766 int addrDiff;
1767 u1 key;
1768
1769 key = *srcPtr++;
1770
1771 /* get the address */
1772 if ((key & 0x07) == 7) {
1773 /* address diff follows in ULEB128 */
1774 addrDiff = readUnsignedLeb128(&srcPtr);
1775 } else {
1776 addrDiff = (key & 0x07) +1;
1777 }
1778
1779 addr = prevAddr + addrDiff;
1780 *dstPtr++ = addr & 0xff;
1781 if (newAddrWidth > 1)
1782 *dstPtr++ = (u1) (addr >> 8);
1783
1784 /* unpack the bits */
1785 if ((key & 0x08) != 0) {
1786 int bitCount = (key >> 4);
1787 if (bitCount == 0) {
1788 /* no bits changed, just copy previous */
1789 memcpy(dstPtr, prevBits, regWidth);
1790 } else if (bitCount == 15) {
1791 /* full copy of bit vector is present; ignore prevBits */
1792 memcpy(dstPtr, srcPtr, regWidth);
1793 srcPtr += regWidth;
1794 } else {
1795 /* copy previous bits and modify listed indices */
1796 memcpy(dstPtr, prevBits, regWidth);
1797 while (bitCount--) {
1798 int bitIndex = readUnsignedLeb128(&srcPtr);
1799 toggleBit(dstPtr, bitIndex);
1800 }
1801 }
1802 } else {
1803 /* copy previous bits and modify the specified one */
1804 memcpy(dstPtr, prevBits, regWidth);
1805
1806 /* one bit, from 0-15 inclusive, was changed */
1807 toggleBit(dstPtr, key >> 4);
1808 }
1809
1810 prevAddr = addr;
1811 prevBits = dstPtr;
1812 dstPtr += regWidth;
1813 }
1814
1815 if (dstPtr - (u1*) pNewMap != newMapSize) {
1816 ALOGE("ERROR: output %d bytes, expected %d",
1817 dstPtr - (u1*) pNewMap, newMapSize);
1818 free(pNewMap);
1819 return NULL;
1820 }
1821
1822 if (srcPtr - srcStart != expectedSrcLen) {
1823 ALOGE("ERROR: consumed %d bytes, expected %d",
1824 srcPtr - srcStart, expectedSrcLen);
1825 free(pNewMap);
1826 return NULL;
1827 }
1828
1829 if (REGISTER_MAP_VERBOSE) {
1830 ALOGD("Expansion successful (%d -> %d)",
1831 computeRegisterMapSize(pMap), computeRegisterMapSize(pNewMap));
1832 }
1833
1834 return pNewMap;
1835 }
1836