001    /*
002     *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003     *
004     *  This file is licensed to You under the Eclipse Public License (EPL);
005     *  You may not use this file except in compliance with the License. You
006     *  may obtain a copy of the License at
007     *
008     *      http://www.opensource.org/licenses/eclipse-1.0.php
009     *
010     *  See the COPYRIGHT.txt file distributed with this work for information
011     *  regarding copyright ownership.
012     */
013    package org.jikesrvm.compilers.baseline;
014    
015    import org.jikesrvm.ArchitectureSpecific.BaselineConstants;
016    import org.jikesrvm.VM;
017    import org.jikesrvm.classloader.RVMArray;
018    import org.jikesrvm.classloader.RVMMethod;
019    import org.jikesrvm.classloader.NormalMethod;
020    import org.jikesrvm.classloader.TypeReference;
021    import org.jikesrvm.scheduler.SpinLock;
022    import org.vmmagic.pragma.Interruptible;
023    import org.vmmagic.pragma.Uninterruptible;
024    import org.vmmagic.unboxed.Offset;
025    
026    /**
027     * class that provides stack (and local var) map for a baseline compiled method
028     * GC uses the methods provided here
029     */
030    @Uninterruptible
031    public final class ReferenceMaps implements BaselineConstants {
032    
033      public static final byte JSR_MASK = -128;     // byte = x'80'
034      public static final byte JSR_INDEX_MASK = 0x7F;
035    
036      public static final int STARTINDEX = 0;
037      public static final int NOMORE = 0;
038      /** Kinds of merge operation when merging delta maps into table maps */
039      private static enum MergeOperation {
040        OR, NAND, COPY
041      }
042    
043      /** Serializes JSR processing */
044      public static final SpinLock jsrLock = new SpinLock();   // for serialization of JSR processing
045    
046      /** Number of bits in each map element */
047      private static final int BITS_PER_MAP_ELEMENT = 8;
048      private byte[] referenceMaps;
049      private int[] MCSites;
050      /** Number of bits in each map */
051      private final int bitsPerMap;
052      /** Number of maps */
053      private int mapCount;
054      private JSRInfo jsrInfo;
055    
056      /**
057       * size of individual maps
058       */
059      private int bytesPerMap() {
060        return ((bitsPerMap + 7) / 8) + 1;
061      }
062    
063      ReferenceMaps(BaselineCompiledMethod cm, int[] stackHeights, byte[] localTypes) {
064    
065        NormalMethod method = (NormalMethod) cm.getMethod();
066        // save input information and compute related data
067        this.bitsPerMap = (method.getLocalWords() + method.getOperandWords() + 1); // +1 for jsr bit
068    
069        //   this.startLocal0Offset = BaselineCompilerImpl.getStartLocalOffset(method);
070    
071        if (VM.TraceStkMaps) {
072          VM.sysWrite("ReferenceMaps constructor. Method name is:");
073          VM.sysWrite(method.getName());
074          VM.sysWrite(" -Class name is :");
075          VM.sysWrite(method.getDeclaringClass().getDescriptor());
076          VM.sysWrite("\n");
077          VM.sysWrite(" bytesPerMap = ", bytesPerMap());
078          VM.sysWrite(" - bitsPerMap = ", bitsPerMap);
079    //      VM.sysWriteln(" - startLocal0Offset = ", startLocal0Offset);
080        }
081    
082        // define the basic blocks
083        BuildBB buildBB = new BuildBB();
084        buildBB.determineTheBasicBlocks(method);
085    
086        BuildReferenceMaps buildRefMaps = new BuildReferenceMaps();
087        buildRefMaps.buildReferenceMaps(method, stackHeights, localTypes, this, buildBB);
088    
089        if (VM.ReferenceMapsBitStatistics) {
090          showReferenceMapStatistics(method);
091        }
092      }
093    
094      /**
095       * Given a machine code instruction offset, return an index to
096       * identify the stack map closest to the offset ( but not beyond).<p>
097       *
098       * Usage note: "machCodeOffset" must point to the instruction *following*
099       *              the actual instruction
100       * whose stack map is sought. This allows us to properly handle the case where
101       * the only address we have to work with is a return address (i.e. from a stackframe)
102       * or an exception address (i.e. from a null pointer dereference, array bounds check,
103       * or divide by zero) on a machine architecture with variable length instructions.
104       * In such situations we'd have no idea how far to back up the instruction pointer
105       * to point to the "call site" or "exception site".<p>
106       *
107       * If the located site is within the scope of a jsr subroutine
108       *  the index value returned is a negative number.
109       */
110      public int locateGCPoint(Offset machCodeOffset, RVMMethod method) {
111    
112        machCodeOffset = machCodeOffset.minus(1 << LG_INSTRUCTION_WIDTH);  // this assumes that machCodeOffset points
113        // to "next" instruction eg bal type instruction
114    
115        if (VM.TraceStkMaps) {
116          VM.sysWrite("ReferenceMaps-locateGCPoint for machine code offset = ");
117          VM.sysWrite(machCodeOffset);
118          VM.sysWrite("  --- in  method = ");
119          VM.sysWrite(method.getName());
120          VM.sysWrite("\n");
121        }
122    
123        //  Scan the list of machine code addresses to find the
124        //  closest site offset BEFORE the input machine code index ( offset in the code)
125        Offset distance = Offset.zero();
126        int index = 0;
127        // get the first possible location
128        for (int i = 0; i < mapCount; i++) {
129          // get an initial non zero distance
130          distance = machCodeOffset.minus(MCSites[i]);
131          if (distance.sGE(Offset.zero())) {
132            index = i;
133            break;
134          }
135        }
136        // scan to find any better location i.e. closer to the site
137        for (int i = index + 1; i < mapCount; i++) {
138          Offset dist = machCodeOffset.minus(MCSites[i]);
139          if (dist.sLT(Offset.zero())) continue;
140          if (dist.sLE(distance)) {
141            index = i;
142            distance = dist;
143          }
144        }
145    
146        if (VM.TraceStkMaps) {
147          showInfo();
148          VM.sysWrite(" ReferenceMaps-locateGCPoint located index  = ");
149          VM.sysWrite(index);
150          VM.sysWrite("  byte  = ");
151          VM.sysWrite(referenceMaps[index]);
152          VM.sysWrite("\n");
153          if (index - 1 >= 0) {
154            VM.sysWrite(" MCSites[index-1] = ");
155            VM.sysWrite(machCodeOffset.minus(MCSites[index - 1]));
156            VM.sysWrite("\n");
157          }
158          VM.sysWrite(" MCSites[index  ] = ");
159          VM.sysWrite(machCodeOffset.minus(MCSites[index]));
160          VM.sysWrite("\n");
161          if (index + 1 < MCSites.length) {
162            VM.sysWrite(" MCSites[index+1] = ");
163            VM.sysWrite(machCodeOffset.minus(MCSites[index + 1]));
164            VM.sysWrite("\n");
165          }
166        }
167    
168        // test for a site within a jsr subroutine
169        if ((0x000000FF & (referenceMaps[index * bytesPerMap()] & JSR_MASK)) ==
170            (0x000000FF & JSR_MASK)) { // test for jsr map
171          index = -index;                       // indicate site within a jsr to caller
172          if (VM.TraceStkMaps) {
173            VM.sysWrite(" ReferenceMaps-locateGCPoint jsr mapid = ");
174            VM.sysWrite(-index);
175            VM.sysWrite("\n");
176          }
177        }
178    
179        if (VM.TraceStkMaps) {
180          VM.sysWrite(" ReferenceMaps-locateGCPoint  machine offset = ");
181          VM.sysWrite(machCodeOffset);
182          VM.sysWrite("  - return map index = ");
183          VM.sysWrite(index);
184          VM.sysWrite("\n");
185        }
186    
187        return index;
188      }
189    
190      /**
191       * @param index offset in the reference stack frame,
192       * @param siteindex index that indicates the callsite (siteindex),
193       * @return return the offset where the next reference can be found.
194       * @return NOMORE when no more pointers can be found
195       */
196      public int getNextRefIndex(int index, int siteindex) {
197        if (VM.TraceStkMaps) {
198          VM.sysWrite("ReferenceMaps-getNextRef-inputs index = ");
199          VM.sysWrite(index);
200          VM.sysWrite(" -siteindex = ");
201          VM.sysWrite(siteindex);
202          VM.sysWrite("\n");
203        }
204    
205        // use index to locate the gc point of interest
206        if (bytesPerMap() == 0) return 0;           // no map ie no refs
207        int mapindex = siteindex * bytesPerMap();
208    
209        int bitnum;
210        if (index == STARTINDEX) {
211          // this is the initial scan for the map
212          int mapByteNum = mapindex;
213          int startbitnumb = 1;      // start search from beginning
214          bitnum = scanForNextRef(startbitnumb, mapByteNum, bitsPerMap, referenceMaps);
215    
216          if (VM.TraceStkMaps) {
217            VM.sysWriteln("ReferenceMaps-getNextRef-initial call bitnum = ", bitnum);
218          }
219        } else {
220          // get bitnum and determine mapword to restart scan
221          bitnum = index + 1; // +1 for jsr bit
222    
223          if (VM.TraceStkMaps) {
224            VM.sysWriteln("ReferenceMaps-getnextref- not initial- entry index,bitnum  = ", index, " ", bitnum);
225          }
226    
227          // scan forward from current position to next ref
228          bitnum = scanForNextRef(bitnum + 1, mapindex, (bitsPerMap - (bitnum - 1)), referenceMaps);
229    
230          if (VM.TraceStkMaps) {
231            VM.sysWriteln("ReferenceMaps-getnextref- not initial- scan returned bitnum = ", bitnum);
232          }
233        }
234    
235        if (bitnum == NOMORE) {
236          if (VM.TraceStkMaps) VM.sysWriteln("  NOMORE");
237          return NOMORE;
238        } else {
239          int ans = bitnum - 1; //-1 for jsr bit
240          if (VM.TraceStkMaps) VM.sysWriteln("  result = ", ans);
241          return ans;
242        }
243      }
244    
245      /**
246       * Given an offset in the jsr reference map,
247       * return the offset where the next returnAddress can be found.<p>
248    
249       *  NOTE: There is only one JSR map for the entire method because it has to
250       *       be constructed at GC time and would normally require additional
251       *       storage.
252       * <p>
253       *       To avoid this, the space for one map is pre-allocated and the map
254       *       is built in that space.  When multiple threads exist and if GC runs
255       *       in multiple threads concurrently, then the MethodMap must be locked
256       *       when a JSR map is being scanned.  This should be a low probability
257       *       event.
258       *
259       * @param index offset in the JSR reference map,
260       * @return The offset where the next reference can be found or
261       *  <code>NOMORE</code> when no more pointers can be found
262       *
263       */
264      public int getNextJSRRefIndex(int index) {
265        // user index to locate the gc point of interest
266        if (bytesPerMap() == 0) return 0;           // no map ie no refs
267        int mapword = jsrInfo.mergedReferenceMap;
268    
269        int bitnum;
270        if (index == STARTINDEX) {
271          // this is the initial scan for the map
272          int startbitnumb = 1;      // start search from beginning
273          bitnum = scanForNextRef(startbitnumb, mapword, bitsPerMap, jsrInfo.unusualReferenceMaps);
274          if (VM.TraceStkMaps) {
275            VM.sysWrite("ReferenceMaps-getJSRNextRef-initial call - startbitnum =", startbitnumb);
276            VM.sysWrite("  mapword = ", mapword);
277            VM.sysWrite(" bitspermap = ", bitsPerMap);
278            VM.sysWrite("      bitnum = ", bitnum);
279          }
280        } else {
281          // get bitnum and determine mapword to restart scan
282          bitnum = index;  // get the bit number from last time
283    
284          // scan forward from current position to next ref
285          if (VM.TraceStkMaps) {
286            VM.sysWrite("ReferenceMaps.getJSRnextref - not initial- starting (index,bitnum) = ");
287            VM.sysWrite(index);
288            VM.sysWrite(", ");
289            VM.sysWrite(bitnum);
290          }
291    
292          bitnum = scanForNextRef(bitnum + 1, mapword, (bitsPerMap - (bitnum - 1)), jsrInfo.unusualReferenceMaps);
293        }
294    
295        if (bitnum == NOMORE) {
296          if (VM.TraceStkMaps) VM.sysWriteln("  NOMORE");
297          return NOMORE;
298        } else {
299          int ans = bitnum;
300          if (VM.TraceStkMaps) VM.sysWriteln("  result = ", ans);
301          return ans;
302        }
303      }
304    
305      /**
306       * Given an offset in the jsr returnAddress map,
307       *   return the offset where the next returnAddress can be found.<p>
308       *
309       * NOTE: there is only one jsr returnAddress map for the entire method because it has to be
310       *       be constructed a GC time and would normally require additional storage.
311       *       To avoid this, the space for one map is pre-allocated and the map
312       *       is built in that space. When multiple threads exist and if GC runs
313       *       in multiple threads concurrently, then the MethodMap must be locked
314       *       when a jsr map is being scanned.
315       *       This should be a low probability event.<p>
316       *
317       * NOTE: return addresses are handled separately from references because they point
318       *       inside an object ( internal pointers)
319       *
320       * @param index offset in the JSR returnAddress map,
321       * @return The offset where the next reference can be found or
322       *  <code>NOMORE</code> when no more pointers can be found
323       */
324      public int getNextJSRReturnAddrIndex(int index) {
325        // use the preallocated map to locate the current point of interest
326        int mapword = jsrInfo.mergedReturnAddressMap;
327        if (bytesPerMap() == 0) {
328          if (VM.TraceStkMaps) {
329            VM.sysWriteln("ReferenceMaps-getJSRNextReturnAddr-initial call no returnaddresses");
330          }
331          return 0;  // no map ie no refs
332        }
333    
334        int bitnum;
335        if (index == STARTINDEX) {
336          // this is the initial scan for the map
337          int startbitnumb = 1;      // start search from beginning
338          bitnum = scanForNextRef(startbitnumb, mapword, bitsPerMap, jsrInfo.unusualReferenceMaps);
339          if (VM.TraceStkMaps) {
340            VM.sysWrite("ReferenceMaps-getJSRNextReturnAddr-initial call startbitnum, mapword, bitspermap = ");
341            VM.sysWrite(startbitnumb);
342            VM.sysWrite(" , ");
343            VM.sysWrite(mapword);
344            VM.sysWrite(" , ");
345            VM.sysWrite(bitsPerMap);
346            VM.sysWrite(" \n ");
347            VM.sysWrite("ReferenceMaps-getJSRNextReturnAddr-initial call return bitnum = ");
348            VM.sysWrite(bitnum);
349            VM.sysWrite("\n");
350          }
351        } else {
352          // get bitnum and determine mapword to restart scan
353          bitnum = index;  // get the bit number
354          if (VM.TraceStkMaps) {
355            VM.sysWriteln("ReferenceMaps-getJSRnextReturnAddr- not initial- starting index, starting bitnum  = ",
356                          index,
357                          " ",
358                          bitnum);
359          }
360    
361          // scan forward from current position to next ref
362          bitnum = scanForNextRef(bitnum + 1, mapword, (bitsPerMap - (bitnum - 1)), jsrInfo.unusualReferenceMaps);
363    
364          if (VM.TraceStkMaps) {
365            VM.sysWriteln("ReferenceMaps-getJSRnextref- not initial- scan returned bitnum = ", bitnum);
366          }
367        }
368    
369        if (bitnum == NOMORE) {
370          if (VM.TraceStkMaps) VM.sysWriteln("  NOMORE");
371          return NOMORE;
372        } else {
373          int ans = bitnum;
374          if (VM.TraceStkMaps) VM.sysWrite("ReferenceMaps-getJSRNextReturnAddr-return = ", ans);
375          return ans;
376        }
377      }
378    
379      /**
380       * For debugging (used with CheckRefMaps)
381       *  Note: all maps are the same size
382       */
383      public int getStackDepth(int mapid) {
384        return bytesPerMap();
385      }
386    
387      @Interruptible
388      public int size() {
389        int size = TypeReference.ReferenceMaps.peekType().asClass().getInstanceSize();
390        if (MCSites != null) size += RVMArray.IntArray.getInstanceSize(MCSites.length);
391        if (referenceMaps != null) size += RVMArray.ByteArray.getInstanceSize(referenceMaps.length);
392        if (jsrInfo != null && jsrInfo.unusualReferenceMaps != null) {
393          size += RVMArray.JavaLangObjectArray.getInstanceSize(jsrInfo.unusualReferenceMaps.length);
394        }
395        return size;
396      }
397    
398      /**
399       * start setting up the reference maps for this method.
400       */
401      @Interruptible
402      public void startNewMaps(int gcPointCount, int jsrCount, int parameterWords) {
403        //  normal map information
404        mapCount = 0;
405        MCSites = new int[gcPointCount];
406        referenceMaps = new byte[gcPointCount * bytesPerMap()];
407    
408        if (VM.TraceStkMaps) {
409          VM.sysWrite("ReferenceMaps-startNewMaps-  gcPointCount =  ");
410          VM.sysWrite(gcPointCount);
411          VM.sysWrite(" -jsrCount = ");
412          VM.sysWrite(jsrCount);
413          VM.sysWrite("\n");
414        }
415    
416        if (jsrCount > 0) {
417    
418          jsrInfo = new JSRInfo(2 * jsrCount);
419    
420          // reserve a map for merging maps
421          jsrInfo.tempIndex = getNextMapElement();
422    
423          // reserve map words for merged reference map
424          jsrInfo.mergedReferenceMap = getNextMapElement();
425    
426          // reserve map words for merged return address map
427          jsrInfo.mergedReturnAddressMap = getNextMapElement();
428    
429          //reserve maps for the jsrInfo.extraUnusualMapObject
430          // the reference map
431          int mapstart = getNextMapElement();
432          jsrInfo.extraUnusualMap.setReferenceMapIndex(mapstart);
433    
434          //the set of non reference stores
435          mapstart = getNextMapElement();
436          jsrInfo.extraUnusualMap.setNonReferenceMapIndex(mapstart);
437    
438          // the return address map
439          mapstart = getNextMapElement();
440          jsrInfo.extraUnusualMap.setReturnAddressMapIndex(mapstart);
441    
442        }
443    
444      }
445    
446      /**
447       * Given the information about a GC point, record the information in the proper tables.
448       * @param byteindex the index in the bytecode of this site
449       * @param byteMap a byte array that describes the contents of the local variables and the java stack
450       * @param BBLastPtr the last offset of a byte that contains information about the map
451       * @param replacemap whether this map is a replacement for a currently
452       *        existing map
453       */
454      @Interruptible
455      public void recordStkMap(int byteindex, byte[] byteMap, int BBLastPtr, boolean replacemap) {
456    
457        int mapNum = 0;
458    
459        if (VM.TraceStkMaps) {
460          VM.sysWrite(" ReferenceMaps-recordStkMap bytecode offset = ");
461          VM.sysWrite(byteindex);
462          VM.sysWrite("\n");
463          VM.sysWrite(" input byte map = ");
464          for (int j = 0; j <= BBLastPtr; j++) {
465            VM.sysWrite(byteMap[j]);
466          }
467          VM.sysWrite("\n");
468          if (replacemap) {
469            VM.sysWrite(" ReferenceMaps-recordStkMap- replacing map at byteindex = ");
470            VM.sysWrite(byteindex);
471            VM.sysWrite("\n");
472          }
473        }
474    
475        if (replacemap) {
476          // replace a map that already exists in the table
477          //  locate the site
478          for (mapNum = 0; mapNum < mapCount; mapNum++) {
479            if (MCSites[mapNum] == byteindex) {
480              // location found -clear out old map
481              int start = mapNum * bytesPerMap();  // get starting byte in map
482              for (int i = start; i < start + bytesPerMap(); i++) {
483                referenceMaps[i] = 0;
484              }
485              if (VM.TraceStkMaps) {
486                VM.sysWrite(" ReferenceMaps-recordStkMap replacing map number = ", mapNum);
487                VM.sysWriteln("  for machinecode index = ", MCSites[mapNum]);
488              }
489              break;
490            }
491          }
492        } else {
493          // add a map to the table - its a new site
494          //  allocate a new site
495          mapNum = mapCount++;
496          // fill in basic information
497          MCSites[mapNum] = byteindex; // gen and save bytecode offset
498          if (BBLastPtr == -1) return;   // empty map for this gc point
499        }
500    
501        if (VM.TraceStkMaps) {
502          VM.sysWrite(" ReferenceMaps-recordStkMap map id  = ");
503          VM.sysWrite(mapNum);
504          VM.sysWrite("\n");
505        }
506    
507        // convert Boolean array into array of bits ie create the map
508        int mapslot = mapNum * bytesPerMap();
509        int len = (BBLastPtr + 1);      // get last ptr in map
510        int offset = 0;              // offset from origin
511        int convertLength;                             //to start in the map
512        int word = mapslot;
513    
514        // convert first byte of map
515        // get correct length for first map byte - smaller of bits in first byte or size of map
516        if (len < (BITS_PER_MAP_ELEMENT - 1)) {
517          convertLength = len;
518        } else {
519          convertLength = BITS_PER_MAP_ELEMENT - 1;
520        }
521        byte firstByte = convertMapElement(byteMap, offset, convertLength, BuildReferenceMaps.REFERENCE);
522        referenceMaps[word] = (byte) ((0x000000ff & firstByte) >>> 1); // shift for jsr bit ie set it to 0
523    
524        if (VM.TraceStkMaps) {
525          VM.sysWrite(" ReferenceMaps-recordStkMap convert first map bytes- byte number = ");
526          VM.sysWrite(word);
527          VM.sysWrite(" byte value in map = ");
528          VM.sysWrite(referenceMaps[word]);
529          VM.sysWrite(" - before shift = ");
530          VM.sysWrite(firstByte);
531          VM.sysWrite("\n");
532        }
533    
534        // update indexes for additional bytes
535        word++;                                // next byte in bit map
536        len -= (BITS_PER_MAP_ELEMENT - 1);   // remaining count
537        offset += (BITS_PER_MAP_ELEMENT - 1);   // offset into input array
538    
539        // convert remaining byte array to bit array -
540        while (len > 0) {
541          // map takes multiple bytes -convert 1  at a time
542          if (len <= (BITS_PER_MAP_ELEMENT - 1)) {
543            convertLength = len;
544          } else {
545            convertLength = BITS_PER_MAP_ELEMENT;
546          }
547          // map takes multiple bytes -convert 1  at a time
548          referenceMaps[word] = convertMapElement(byteMap, offset, convertLength, BuildReferenceMaps.REFERENCE);
549    
550          if (VM.TraceStkMaps) {
551            VM.sysWriteln(" ReferenceMaps-recordStkMap convert another map byte- byte number = ",
552                          word,
553                          " byte value = ",
554                          referenceMaps[word]);
555          }
556    
557          len -= BITS_PER_MAP_ELEMENT;                // update remaining words
558          offset += BITS_PER_MAP_ELEMENT;                // and offset
559          word++;
560        }  // end of while
561    
562        // update stats
563        if (VM.ReferenceMapsStatistics) {
564          if (!replacemap) {
565          }
566        }
567      }
568    
569      /**
570       * Record a map for a point within a JSR Subroutine. This requires setting up one
571       * of the unusual maps.
572       * @param byteindex         index into the byte code array of the point for the map
573       * @param currReferenceMap  map of references and return addresses that were set
574       *                          within the JSR Subroutine
575       * @param BBLastPtr         map runs from -1  to BBLastPtr inclusively
576       * @param returnAddrIndex   Index in the stack where the return address
577       *                            for the jsr routine (in which this gcpoint is located)
578       *                            can be found
579       * @param replacemap        {@code false} if this is the first time this map point has been
580       *                          recorded.
581       */
582      @Interruptible
583      public void recordJSRSubroutineMap(int byteindex, byte[] currReferenceMap, int BBLastPtr, int returnAddrIndex,
584                                         boolean replacemap) {
585        int mapNum = 0;
586        int unusualMapIndex = 0;
587        int internalReturnIndex;
588        UnusualMaps jsrSiteMap;
589    
590        if (replacemap) {
591          // update an already existing map
592          //  locate existing site  in table
593          jsrSiteMap = null;
594          findJSRSiteMap:
595          for (mapNum = 0; mapNum < mapCount; mapNum++) {
596            if (MCSites[mapNum] == byteindex) {
597              // GC site found - get index in unusual map table and the unusual Map
598              unusualMapIndex = JSR_INDEX_MASK & referenceMaps[mapNum * bytesPerMap()];
599              internalReturnIndex = returnAddrIndex - 1; //-1 for jsrbit
600              if (unusualMapIndex == JSR_INDEX_MASK) {
601                // greater than 127 jsrInfo.unusualMaps- sequential scan of locate others unusual map
602                for (unusualMapIndex = JSR_INDEX_MASK; unusualMapIndex < jsrInfo.numberUnusualMaps; unusualMapIndex++) {
603                  if (jsrInfo.unusualMaps[unusualMapIndex].getReturnAddressIndex() == internalReturnIndex) {
604                    jsrSiteMap = jsrInfo.unusualMaps[unusualMapIndex];
605                    break findJSRSiteMap;
606                  }
607                }
608                VM.sysFail(" can't find unusual map !!!!!!! - should never occur");
609              } else {
610                jsrSiteMap = jsrInfo.unusualMaps[unusualMapIndex];
611                break;
612              }
613            }
614          }
615        } else {
616          // new map, add to end of table
617          mapNum = mapCount++;          // get slot and update count
618          MCSites[mapNum] = byteindex;  // gen and save bytecode offset
619    
620          // generate an UnusualMap for the site
621          jsrSiteMap = new UnusualMaps();
622    
623          // add unusual map to UnusualMap table (table may need to be expanded)
624          unusualMapIndex = addUnusualMap(jsrSiteMap);
625    
626          // set back pointer i.e. pointer from unusual maps back into referencemaps
627          jsrSiteMap.setNormalMapIndex(mapNum);
628    
629          // setup index in reference maps
630          if (unusualMapIndex > JSR_INDEX_MASK) {
631            unusualMapIndex = JSR_INDEX_MASK;
632          }
633          referenceMaps[mapNum * bytesPerMap()] = (byte) ((byte) unusualMapIndex | JSR_MASK);
634    
635          // setup new unusual Map
636          internalReturnIndex = returnAddrIndex - 1 + 2; // -1 for jsrbit  +2  to convert to our index
637          jsrSiteMap.setReturnAddressIndex(internalReturnIndex);
638    
639          if (VM.TraceStkMaps) {
640            VM.sysWrite("ReferenceMaps-recordJSRSubroutineMap- input map = ");
641            for (int i = 0; i < BBLastPtr + 1; i++) {
642              VM.sysWrite(currReferenceMap[i]);
643            }
644            VM.sysWrite("\n");
645            VM.sysWrite("ReferenceMaps-recordJSRSubroutineMap- mapNum = ");
646            VM.sysWrite(mapNum);
647            VM.sysWrite(" - byteindex = ");
648            VM.sysWrite(byteindex);
649            VM.sysWrite(" - return address index = ");
650            VM.sysWrite(internalReturnIndex);
651            VM.sysWrite(" - reference map byte = ");
652            VM.sysWrite(referenceMaps[mapNum * bytesPerMap()]);
653            VM.sysWrite("\n");
654          }
655        }    // end else clause - add new map
656    
657        // for new maps, setup maps in UnusualMap, for existing map replace them
658    
659        // setup Reference Map
660        int refindex =
661            scanByteArray(currReferenceMap,
662                          BBLastPtr,
663                          BuildReferenceMaps.SET_TO_REFERENCE,
664                          jsrSiteMap.getReferenceMapIndex(),
665                          true);
666        jsrSiteMap.setReferenceMapIndex(refindex);
667    
668        if (VM.TraceStkMaps) {
669          VM.sysWrite("                 - reference map index = ");
670          VM.sysWrite(refindex);
671          VM.sysWrite(" - reference map  = ");
672          for (int i = refindex; i < refindex + bytesPerMap(); i++) {
673            VM.sysWrite(jsrInfo.unusualReferenceMaps[i]);
674          }
675          VM.sysWrite("\n");
676        }
677    
678        // setup NONReference Map
679        int nonrefindex =
680            scanByteArray(currReferenceMap,
681                          BBLastPtr,
682                          BuildReferenceMaps.SET_TO_NONREFERENCE,
683                          jsrSiteMap.getNonReferenceMapIndex(),
684                          true);
685        jsrSiteMap.setNonReferenceMapIndex(nonrefindex);
686    
687        if (VM.TraceStkMaps) {
688          VM.sysWrite("                 - NONreference map index = ");
689          VM.sysWrite(nonrefindex);
690          VM.sysWrite(" - NON reference map  = ");
691          for (int i = nonrefindex; i < nonrefindex + bytesPerMap(); i++) {
692            VM.sysWrite(jsrInfo.unusualReferenceMaps[i]);
693          }
694          VM.sysWrite("\n");
695        }
696    
697        // setup returnAddress Map
698        int addrindex =
699            scanByteArray(currReferenceMap,
700                          BBLastPtr,
701                          BuildReferenceMaps.RETURN_ADDRESS,
702                          jsrSiteMap.getReturnAddressMapIndex(),
703                          false);
704        jsrSiteMap.setReturnAddressMapIndex(addrindex);
705    
706        if (VM.TraceStkMaps) {
707          VM.sysWrite("                 - returnAddress map index = ");
708          VM.sysWrite(addrindex);
709          VM.sysWrite(" - return Address map  = ");
710          for (int i = addrindex; i < addrindex + bytesPerMap(); i++) {
711            VM.sysWrite(jsrInfo.unusualReferenceMaps[i]);
712          }
713          VM.sysWrite("\n");
714        }
715    
716        if (VM.TraceStkMaps) {
717          VM.sysWrite("ReferenceMaps-recordJSRSubroutineMap- unusualmap index = ");
718          VM.sysWrite(unusualMapIndex);
719          VM.sysWrite("\n");
720        }
721    
722        // update stats
723        if (VM.ReferenceMapsStatistics) {
724          if (!replacemap) {
725          }
726        }
727      }
728    
729      /**
730       * Add an UnusualMap to the array of unusual maps, expand the array
731       * and referencemap array if necessary
732       *
733       * @param jsrSiteMap   unusualMap to be added to array
734       */
735      @Interruptible
736      private int addUnusualMap(UnusualMaps jsrSiteMap) {
737        if (jsrInfo.unusualMaps == null) {
738          // start up code
739          jsrInfo.unusualMaps = new UnusualMaps[5];
740          jsrInfo.numberUnusualMaps = 0;
741        }
742        // add to array and bump count
743        jsrInfo.unusualMaps[jsrInfo.numberUnusualMaps] = jsrSiteMap;
744        int returnnumber = jsrInfo.numberUnusualMaps;
745        jsrInfo.numberUnusualMaps++;
746    
747        // do we need to extend the maps
748        if (jsrInfo.numberUnusualMaps == jsrInfo.unusualMaps.length) {
749          // array is full, expand arrays for jsrInfo.unusualMaps and unusual referencemaps
750          UnusualMaps[] temp = new UnusualMaps[jsrInfo.numberUnusualMaps + 5];
751          for (int i = 0; i < jsrInfo.numberUnusualMaps; i++) {
752            temp[i] = jsrInfo.unusualMaps[i];
753          }
754          jsrInfo.unusualMaps = temp;
755    
756          byte[] temp2 = new byte[jsrInfo.unusualReferenceMaps.length + (5 * bytesPerMap() * 3)];
757          for (int i = 0; i < jsrInfo.unusualReferenceMaps.length; i++) {
758            temp2[i] = jsrInfo.unusualReferenceMaps[i];
759          }
760          jsrInfo.unusualReferenceMaps = temp2;
761        }
762        return returnnumber;
763      }
764    
765      /**
766       * Setup a map  within a JSR Subroutine. This requires using up one
767       * of the unusual maps. This routine is called when the caller gets a
768       * negative mapindex value return from {@link #locateGCPoint}. This routine
769       * searches the map tables and uses its stack frameAddress input to build
770       * reference and returnAddress maps. The caller uses the getNext...
771       * routines to scan these maps for offsets in the frame of the
772       * related references.<p>
773       *
774       * Steps for this routine:
775       * <ol>
776       *   <li>use the mapid to get index of the Unusual Map
777       *   <li>from the unusual map and the frame - get the location of the jsr invoker
778       *   <li>from the invoker address and the code base address - get the machine code offset
779       *   from the machine code offset locate the map for that instruction
780       *   <li>if the invoker was itself in a jsr- merge the delta maps of each jsr and
781       *     compute the new total delta maps
782       *   <li>else the invoker was not already in a jsr merge the unusual map differences
783       *     with the invoker map
784       * </ol>
785       *
786       * @param mapid             Index of map of instruction where map is required
787       *                          ( this value was returned by locateGCpoint)
788       */
789      public int setupJSRSubroutineMap(int mapid) {
790    
791        // first clear the  maps in the jsrInfo.extraUnusualMap
792        int j = jsrInfo.extraUnusualMap.getReferenceMapIndex();
793        int k = jsrInfo.extraUnusualMap.getNonReferenceMapIndex();
794        int l = jsrInfo.extraUnusualMap.getReturnAddressMapIndex();
795        for (int i = 0; i < bytesPerMap(); i++) {
796          jsrInfo.unusualReferenceMaps[j + i] = 0;
797          jsrInfo.unusualReferenceMaps[k + i] = 0;
798          jsrInfo.unusualReferenceMaps[l + i] = 0;
799        }
800    
801        // use the mapid to get index of the Unusual Map
802        //
803        if (VM.TraceStkMaps) {
804          VM.sysWriteln("ReferenceMaps-setupJSRSubroutineMap- mapid = ", mapid, "   - mapid = ", -mapid);
805          VM.sysWriteln("  -referenceMaps[(- mapid) * bytesPerMap] = ", referenceMaps[(-mapid) * bytesPerMap()]);
806          VM.sysWriteln("        unusual mapid index = ", referenceMaps[(-mapid) * bytesPerMap()] & JSR_INDEX_MASK);
807        }
808    
809        int unusualMapid = (referenceMaps[(-mapid) * bytesPerMap()] & JSR_INDEX_MASK);
810    
811        // if jsr map is > 127 go search for the right one
812        if (unusualMapid == JSR_INDEX_MASK) {
813          unusualMapid = findUnusualMap(-mapid);
814        }
815    
816        UnusualMaps unusualMap = jsrInfo.unusualMaps[unusualMapid];
817        unusualMapcopy(unusualMap); // deep copy unusual map into the extra map
818    
819        // from the unusual map and the frame - get the location of the jsr invoker
820        //
821        return unusualMap.getReturnAddressIndex();
822      }
823    
824      public int getNextJSRAddressIndex(Offset nextMachineCodeOffset, NormalMethod m) {
825        int jsrMapid = locateGCPoint(nextMachineCodeOffset, m);
826    
827        if (jsrMapid >= 0) {
828          finalMergeMaps((jsrMapid * bytesPerMap()), jsrInfo.extraUnusualMap);
829    
830          if (VM.TraceStkMaps) {
831            VM.sysWriteln("ReferenceMaps-setupJSRsubroutineMap- afterfinalMerge jsrInfo.extraUnusualMap = ");
832            jsrInfo.extraUnusualMap.showInfo();
833            VM.sysWriteln();
834            VM.sysWriteln("     jsrInfo.mergedReferenceMap Index = ", jsrInfo.mergedReferenceMap);
835            VM.sysWrite("     jsrInfo.mergedReferenceMap  = ");
836            jsrInfo.showAnUnusualMap(jsrInfo.mergedReferenceMap, bytesPerMap());
837            VM.sysWriteln(jsrInfo.unusualReferenceMaps[jsrInfo.mergedReferenceMap]);
838            VM.sysWriteln("     jsrInfo.mergedReturnAddressMap Index = ", jsrInfo.mergedReturnAddressMap);
839            VM.sysWriteln("    jsrInfo.mergedReturnAddressMap  = ",
840                          jsrInfo.unusualReferenceMaps[jsrInfo.mergedReturnAddressMap]);
841            showInfo();
842            jsrInfo.showUnusualMapInfo(bytesPerMap());
843          }
844          return 0;
845        }
846    
847        jsrMapid = -jsrMapid;
848    
849        if (VM.TraceStkMaps) {
850          VM.sysWriteln("ReferenceMaps-setupJSRsubroutineMap- outer MapIndex = ",
851                        jsrMapid,
852                        "  unusualMapIndex = ",
853                        referenceMaps[jsrMapid]);
854        }
855    
856        // merge unusual maps- occurs in nested jsr conditions
857        //  merge each nested delta into the maps of the extraUnusualmap
858        int unusualMapIndex = JSR_INDEX_MASK & referenceMaps[jsrMapid * bytesPerMap()];
859        if (unusualMapIndex == JSR_INDEX_MASK) {
860          unusualMapIndex = findUnusualMap(jsrMapid);
861        }
862        jsrInfo.extraUnusualMap = combineDeltaMaps(unusualMapIndex);
863    
864        // Locate the next JSR from the current
865        //
866        UnusualMaps thisMap = jsrInfo.unusualMaps[unusualMapIndex];
867        if (VM.TraceStkMaps) {
868          VM.sysWriteln("ReferenceMaps-setupJSRsubroutineMap- nested jsrs jsrInfo.extraUnusualMap = ");
869          jsrInfo.extraUnusualMap.showInfo();
870          VM.sysWriteln();
871          VM.sysWriteln("ReferenceMaps-setupJSRsubroutineMap- nested jsrs thisMap = ");
872          thisMap.showInfo();
873          VM.sysWriteln();
874        }
875        return thisMap.getReturnAddressIndex();
876      }
877    
878      /**
879       * Called when all the recording for this map is complete. Can now
880       * sort or perform other cleanups
881       */
882      public void recordingComplete() {
883      }
884    
885      /**
886       * After code is generated, translate the bytecode indices
887       * recorded in MCSites array into real machine code offsets.
888       */
889      public void translateByte2Machine(int[] b2m) {
890        for (int i = 0; i < MCSites.length; i++) {
891          MCSites[i] = b2m[MCSites[i]] << LG_INSTRUCTION_WIDTH;
892        }
893      }
894    
895      /**
896       * convert a portion of an array word of Bytes into a bitmap of references
897       * i.e. given a byte array,
898       *    a starting offset in the array,
899       *    the length to scan,
900       *    and the type of byte to scan for
901       *   ... convert the area in the array to a
902       *        word of bits ... max length is 31 i.e. BITS_PER_MAP_ELEMENT
903       */
904      private byte convertMapElement(byte[] curBBMap, int offset, int len, byte reftype) {
905        byte bitmap = 0;
906        byte mask = JSR_MASK;     // starting bit mask
907        for (int i = offset; i < offset + len; i++) {
908          if (curBBMap[i] == reftype) {
909            bitmap = (byte) (bitmap | mask);  // add bit to mask
910          }
911          mask = (byte) ((0x000000ff & mask) >>> 1);             // shift for next byte and bit
912        }
913        return bitmap;
914      }
915    
916      /**
917       * get Next free word in referencemaps for GC call sites
918       */
919      @Interruptible
920      private int getNextMapElement() {
921        if (jsrInfo.unusualReferenceMaps == null) {
922          // start up code
923          jsrInfo.unusualReferenceMaps = new byte[((6 * 3) + 1) * bytesPerMap()];  // 3 maps per unusual map
924        }
925    
926        if (jsrInfo.freeMapSlot >= jsrInfo.unusualReferenceMaps.length) {
927          // map is full - get new array, twice the size
928          byte[] newArray = new byte[jsrInfo.unusualReferenceMaps.length << 1];
929          // copy array from old to new
930          for (int i = 0; i < jsrInfo.unusualReferenceMaps.length; i++) {
931            newArray[i] = jsrInfo.unusualReferenceMaps[i];
932          }
933          // replace old array with the new
934          jsrInfo.unusualReferenceMaps = newArray;   // replace array
935        }
936    
937        int allocate = jsrInfo.freeMapSlot;
938        jsrInfo.freeMapSlot = jsrInfo.freeMapSlot + bytesPerMap();
939        return allocate;
940      }
941    
942      /**
943       * given a index in the local area (biased : local0 has index 1)
944       *   this routine determines the correspondig offset in the stack
945       */
946      /*  public int convertIndexToOffset(int index)   {
947          if (index == 0) return NOMORE; //invalid
948    
949          // convert from top of local words
950          int offset = startLocal0Offset - (index <<LOG_BYTES_IN_ADDRESS); // no jsrbit here
951          if (VM.TraceStkMaps) {
952            VM.sysWriteln("convertIndexToOffset- input index = ", index, "  offset = ", offset);
953          }
954          return offset;
955        }
956      */
957    
958      /**
959       * Scans the map for the next reference.
960       *
961       * @param bitnum starting bitnumber in a map (inclusive)
962       * @param wordnum index of the corresponding byte,
963       * @param remaining remaining number of bits in the map,
964       * @param map map to search
965       * @return TODO document me
966       */
967      private int scanForNextRef(int bitnum, int wordnum, int remaining, byte[] map) {
968        int retbit, count = 0;
969    
970        // adjust bitnum and wordnum to bit within word
971        while (bitnum > BITS_PER_MAP_ELEMENT) {
972          wordnum++;
973          bitnum -= BITS_PER_MAP_ELEMENT;
974          count += BITS_PER_MAP_ELEMENT;
975        }
976    
977        // determine remaining bits in this byte - first byte of scan
978        int remain = (BITS_PER_MAP_ELEMENT + 1) - bitnum;    // remaining bits in this word
979        if (remain >= remaining) {
980          // last word in this map
981          retbit = scanByte(bitnum, wordnum, remaining, map);
982          if (retbit == 0) return 0;
983          return (retbit + count);
984        }
985        // search at least the rest of this byte
986        int startbit = bitnum;    // start at this bit
987        retbit = scanByte(startbit, wordnum, remain, map);
988        if (retbit != 0) return (retbit + count);
989    
990        // search additional bytes of map
991        startbit = 1;            // start from beginning from now on
992        remaining -= remain;     // remaing bits in map
993        count += BITS_PER_MAP_ELEMENT; // remember you did the first byte
994        while (remaining > BITS_PER_MAP_ELEMENT) {
995          wordnum++;       // bump to next word
996          remaining -= BITS_PER_MAP_ELEMENT; // search this wordd
997          retbit = scanByte(startbit, wordnum, BITS_PER_MAP_ELEMENT, map);
998          if (retbit != 0) return (retbit + count);
999          count += BITS_PER_MAP_ELEMENT;
1000        } // end while
1001    
1002        // scan last byte of map
1003        wordnum++;
1004        retbit = scanByte(startbit, wordnum, remaining, map); // last word
1005        if (retbit != 0) return (retbit + count);
1006        return 0;
1007      }
1008    
1009      /**
1010       * Scans for a reference in a byte.
1011       *
1012       * @param bitnum bitnumber in the map
1013       * @param bytenum index of the corresponding map byte
1014       * @param toscan the remaining number of bits in the byte,
1015       * @param map the map
1016       * @return next ref in the byte or zero if not found
1017       */
1018      private int scanByte(int bitnum, int bytenum, int toscan, byte[] map) {
1019        int count = 0, mask;
1020    
1021        if (VM.TraceStkMaps) {
1022          VM.sysWrite(" scanByte- inputs  bitnum = ", bitnum);
1023          VM.sysWrite("  bytenum = ", bytenum);
1024          VM.sysWriteln(" toscan = ", toscan);
1025          VM.sysWriteln("     stackmap byte = ", map[bytenum]);
1026        }
1027    
1028        // convert bitnum to mask
1029        mask = (1 << (BITS_PER_MAP_ELEMENT - bitnum));  // generate mask
1030    
1031        // scan rest of word
1032        while (toscan > 0) {
1033          if ((mask & map[bytenum]) == 0) {
1034            // this bit not a ref
1035            mask = mask >>> 1; // move mask bit
1036            count++;        // inc count of bits checked
1037            toscan--;    // decrement remaining count
1038          } else {
1039            // ref bit found
1040            if (VM.TraceStkMaps) {
1041              VM.sysWriteln(" scanByte- return bit number = ", bitnum + count);
1042            }
1043            return bitnum + count;
1044          }
1045        } // end while
1046        return 0;   // no more refs
1047      }
1048    
1049      /**
1050       * Scans the byte array to look for the type of information that was requested. Builds a
1051       * bit array in the stack maps with the information.
1052       *
1053       * @param byteMap bytearray where each byte describes the corresponding word on a stack
1054       * @param BBLastPtr length of the byte array
1055       * @param refType type of information that is to be scanned
1056       * @param mapslot slot where map should be stored, 0 for next free slot
1057       * @param skipOneBit should a bit in the bitarray be skipped? Necessary for setRef and
1058       * setNonRef maps so so they are properly merged with jsr base maps.
1059       * @return index of the map in the reference map
1060       */
1061      @Interruptible
1062      int scanByteArray(byte[] byteMap, int BBLastPtr, byte refType, int mapslot, boolean skipOneBit) {
1063        skipOneBit = false;
1064    
1065        if (BBLastPtr == -1) return -1;     // no map for this jsr
1066    
1067        // get a place to hold the map if necessary
1068        if (mapslot == 0) {
1069          mapslot = getNextMapElement();     // get first word of map
1070        }
1071    
1072        // initialize search variables
1073        int len = (BBLastPtr + 1);      // get length of map
1074        int offset = 0;                    // offset from origin
1075        int word = mapslot;                // first word of map
1076    
1077        // map may take multiple words -convert 1 at a time
1078        while (len > 0) {
1079          boolean doSkip = (offset == 0 && skipOneBit);  // skip a bit if first word and skipOneBit is set
1080          int bitsToDo = doSkip ? BITS_PER_MAP_ELEMENT - 1 : BITS_PER_MAP_ELEMENT;
1081          if (len < bitsToDo) {
1082            bitsToDo = len;
1083          }
1084    
1085          byte result = convertMapElement(byteMap, offset, bitsToDo, refType);
1086          if (doSkip) {
1087            result =
1088                (byte) ((0x000000ff & result) >>>
1089                        1);   // shift right to skip high bit for jsr to be consistent with normal maps
1090          }
1091          jsrInfo.unusualReferenceMaps[word] = result;
1092    
1093          len -= bitsToDo;                // update remaining words
1094          offset += bitsToDo;                // and offset
1095          word++;                            // get next word
1096        }
1097        return mapslot;
1098      }
1099    
1100    
1101      /**
1102       * Makes a deep copy of {@code from} into {@code jsrInfo.extraUnusualMap}
1103       * @param from
1104       */
1105      private void unusualMapcopy(UnusualMaps from) {
1106        jsrInfo.extraUnusualMap.setReturnAddressIndex(from.getReturnAddressIndex());
1107        copyBitMap(jsrInfo.extraUnusualMap.getReferenceMapIndex(), from.getReferenceMapIndex());
1108        copyBitMap(jsrInfo.extraUnusualMap.getNonReferenceMapIndex(), from.getNonReferenceMapIndex());
1109        copyBitMap(jsrInfo.extraUnusualMap.getReturnAddressMapIndex(), from.getReturnAddressMapIndex());
1110      }
1111    
1112      /**
1113       * Copies a bit map into the extra unusualmap.
1114       * @param extramapindex  the index of the map in the jsrInfo.extraUnusualMap ie the "to" map
1115       * @param index he index of the map to copy ie the "from" map
1116       */
1117      private void copyBitMap(int extramapindex, int index) {
1118        if (VM.TraceStkMaps) {
1119          VM.sysWriteln(" copyBitMap from map index = ",
1120                        index,
1121                        " copyBitMap from value = ",
1122                        jsrInfo.unusualReferenceMaps[index]);
1123        }
1124    
1125        // copy the map over to the extra map
1126        for (int i = 0; i < bytesPerMap(); i++) {
1127          jsrInfo.unusualReferenceMaps[extramapindex + i] = jsrInfo.unusualReferenceMaps[index + i];
1128        }
1129    
1130        if (VM.TraceStkMaps) {
1131          VM.sysWriteln(" extraUnusualBitMap index = ",
1132                        extramapindex,
1133                        " extraunusualBitMap value = ",
1134                        jsrInfo.unusualReferenceMaps[extramapindex]);
1135        }
1136      }
1137    
1138      /**
1139       *
1140       *  m
1141       *  NOTE: while the routine is written to combine 2 jsrInfo.unusualMaps in general
1142       *      in reality the target map is always the same ( the jsrInfo.extraUnusualMap)
1143       */
1144    
1145      /**
1146       * Merges unusual maps (occurs in nested jsr conditions) by merging each nested
1147       * delta map ( as represented by the jsrMapid of the location site) into the
1148       * jsrInfo.extraUnusualMap where the deltas are accumulated
1149       *
1150       * @param jsrUnusualMapid the delta map's id
1151       * @return merged map
1152       */
1153      private UnusualMaps combineDeltaMaps(int jsrUnusualMapid) {
1154        //get the delta unusualMap
1155        UnusualMaps deltaMap = jsrInfo.unusualMaps[jsrUnusualMapid];
1156    
1157        // get the map indicies of the inner jsr map
1158        int reftargetindex = jsrInfo.extraUnusualMap.getReferenceMapIndex();
1159        int nreftargetindex = jsrInfo.extraUnusualMap.getNonReferenceMapIndex();
1160        int addrtargetindex = jsrInfo.extraUnusualMap.getReturnAddressMapIndex();
1161    
1162        // get the map indices of the outer jsr map
1163        int refdeltaindex = deltaMap.getReferenceMapIndex();
1164        int nrefdeltaindex = deltaMap.getNonReferenceMapIndex();
1165        int addrdeltaindex = deltaMap.getReturnAddressMapIndex();
1166    
1167        if (VM.TraceStkMaps) {
1168          // display original maps
1169          VM.sysWriteln("combineDeltaMaps- original ref map id  = ", reftargetindex);
1170          VM.sysWrite("combineDeltaMaps- original ref map  = ");
1171          for (int i = 0; i < bytesPerMap(); i++) {
1172            VM.sysWrite(jsrInfo.unusualReferenceMaps[reftargetindex + i]);
1173          }
1174          VM.sysWriteln();
1175          VM.sysWriteln("combineDeltaMaps- original nref map id  = ", nreftargetindex);
1176          VM.sysWrite("combineDeltaMaps original nref map  = ");
1177          for (int i = 0; i < bytesPerMap(); i++) {
1178            VM.sysWrite(jsrInfo.unusualReferenceMaps[nreftargetindex + i]);
1179          }
1180          VM.sysWriteln();
1181          VM.sysWriteln("combineDeltaMaps- original retaddr map id  = ", addrtargetindex);
1182          VM.sysWrite("combineDeltaMaps original retaddr map  = ");
1183          for (int i = 0; i < bytesPerMap(); i++) {
1184            VM.sysWrite(jsrInfo.unusualReferenceMaps[addrtargetindex + i]);
1185          }
1186          VM.sysWriteln();
1187    
1188          VM.sysWriteln("combineDeltaMaps- delta ref map id  = ", refdeltaindex);
1189          VM.sysWrite("combineDeltaMaps- original delta  ref map  = ");
1190          for (int i = 0; i < bytesPerMap(); i++) {
1191            VM.sysWrite(jsrInfo.unusualReferenceMaps[refdeltaindex + i]);
1192          }
1193          VM.sysWriteln();
1194          VM.sysWriteln("combineDeltaMaps- delta nref map id  = ", nrefdeltaindex);
1195          VM.sysWrite("combineDeltaMaps original delta nref map  = ");
1196          for (int i = 0; i < bytesPerMap(); i++) {
1197            VM.sysWrite(jsrInfo.unusualReferenceMaps[nrefdeltaindex + i]);
1198          }
1199          VM.sysWriteln();
1200          VM.sysWriteln("combineDeltaMaps- delta retaddr map id  = ", addrdeltaindex);
1201          VM.sysWrite("combineDeltaMaps original  delta retaddr map  = ");
1202          for (int i = 0; i < bytesPerMap(); i++) {
1203            VM.sysWrite(jsrInfo.unusualReferenceMaps[addrdeltaindex + i]);
1204          }
1205          VM.sysWriteln();
1206    
1207          // display indices
1208          VM.sysWriteln("combineDeltaMaps- ref target mapid  = ", reftargetindex);
1209          VM.sysWriteln("                        ref delta mapid = ", refdeltaindex);
1210          VM.sysWriteln("combineDeltaMaps- NONref target mapid  = ", nreftargetindex);
1211          VM.sysWriteln("                        NONref delta mapid = ", nrefdeltaindex);
1212          VM.sysWriteln("combineDeltaMaps- retaddr target mapid  = ", addrtargetindex);
1213          VM.sysWriteln("                         retaddr delta mapid = ", addrdeltaindex);
1214          VM.sysWriteln("                         jsrInfo.tempIndex = ", jsrInfo.tempIndex);
1215        }
1216    
1217        // merge the reference maps
1218        mergeMap(jsrInfo.tempIndex, reftargetindex, MergeOperation.COPY); // save refs made in inner jsr sub(s)
1219        mergeMap(reftargetindex, refdeltaindex, MergeOperation.OR);       // get refs from outer loop
1220        mergeMap(reftargetindex, nreftargetindex, MergeOperation.NAND);   // turn off non refs made in inner jsr sub(s)
1221        mergeMap(reftargetindex, addrtargetindex, MergeOperation.NAND);   // then the return adresses
1222        mergeMap(reftargetindex, jsrInfo.tempIndex, MergeOperation.OR);   // OR inrefs made in inner jsr sub(s)
1223    
1224        // merge the non reference maps
1225        mergeMap(jsrInfo.tempIndex, nreftargetindex, MergeOperation.COPY); // save nonrefs made in inner loop(s)
1226        mergeMap(nreftargetindex, nrefdeltaindex, MergeOperation.OR);      // get nrefs from outer loop
1227        mergeMap(nreftargetindex, reftargetindex, MergeOperation.NAND);    // turn off refs made in inner jsr sub(s)
1228        mergeMap(nreftargetindex, addrtargetindex, MergeOperation.NAND);   // then the return adresses
1229        mergeMap(nreftargetindex, jsrInfo.tempIndex, MergeOperation.OR);   // OR in non refs made in inner jsr sub(s)
1230    
1231        // merge return address maps
1232        mergeMap(addrtargetindex, addrdeltaindex, MergeOperation.OR);
1233    
1234        if (VM.TraceStkMaps) {
1235          //display final maps
1236          VM.sysWrite("setupjsrmap-combineDeltaMaps- merged ref map  = ");
1237          for (int i = 0; i < bytesPerMap(); i++) {
1238            VM.sysWrite(jsrInfo.unusualReferenceMaps[reftargetindex + i]);
1239          }
1240          VM.sysWriteln();
1241          VM.sysWrite("setupjsrmap-combineDeltaMaps- merged nonref map  = ");
1242          for (int i = 0; i < bytesPerMap(); i++) {
1243            VM.sysWrite(jsrInfo.unusualReferenceMaps[nreftargetindex + i]);
1244          }
1245          VM.sysWriteln();
1246          VM.sysWrite("setupjsrmap-combineDeltaMaps- merged retaddr map  = ");
1247          for (int i = 0; i < bytesPerMap(); i++) {
1248            VM.sysWrite(jsrInfo.unusualReferenceMaps[addrtargetindex + i]);
1249          }
1250          VM.sysWriteln();
1251        }
1252    
1253        return jsrInfo.extraUnusualMap;
1254      }
1255    
1256      /**
1257       * Merges a delta map into a target map.
1258       *
1259       * @param targetindex the delta map's index in the reference map table
1260       * @param deltaindex the target map's index in the reference map tbale
1261       * @param Op the merge operation to use
1262       */
1263      private void mergeMap(int targetindex, int deltaindex, MergeOperation Op) {
1264        int i;
1265        // Merge the maps
1266        if (Op == MergeOperation.COPY) {
1267          for (i = 0; i < bytesPerMap(); i++) {
1268            jsrInfo.unusualReferenceMaps[targetindex + i] = jsrInfo.unusualReferenceMaps[deltaindex + i];
1269          }
1270        }
1271        if (Op == MergeOperation.OR) {
1272          for (i = 0; i < bytesPerMap(); i++) {
1273            jsrInfo.unusualReferenceMaps[targetindex + i] =
1274                (byte) (jsrInfo.unusualReferenceMaps[targetindex + i] | jsrInfo.unusualReferenceMaps[deltaindex + i]);
1275          }
1276        }
1277        if (Op == MergeOperation.NAND) {
1278          for (i = 0; i < bytesPerMap(); i++) {
1279            short temp = (byte) (~(jsrInfo.unusualReferenceMaps[deltaindex + i]));
1280            jsrInfo.unusualReferenceMaps[targetindex + i] = (byte) (jsrInfo.unusualReferenceMaps[targetindex + i] & temp);
1281          }
1282        }
1283      }
1284    
1285      /**
1286       * This method will merge the jsr invoker's base map with changes
1287       * due to *all* nested jsr subroutines.<p>
1288       *
1289       * The nested jsr subroutine maps were merged into a single delta
1290       * map prior to the calling of this method.  We therefore know that
1291       * the base map can never be due to a subroutine (since all
1292       * subroutines have been merged), and therefore that there are no
1293       * return address maps due to the invoker (since return addresses
1294       * are only due to the subroutine maps).
1295       *
1296       * @param jsrBaseMapIndex The map index for the invoker
1297       * @param deltaMap The map for the invoked subroutine/s (all nested
1298       * subroutine maps are guaranteed to have been combined prior to
1299       * calling this)
1300       */
1301      private void finalMergeMaps(int jsrBaseMapIndex, UnusualMaps deltaMap) {
1302        int i;
1303    
1304        /* clear out the destination (merged) maps */
1305        for (i = 0; i < bytesPerMap(); i++) {
1306          jsrInfo.unusualReferenceMaps[jsrInfo.mergedReferenceMap + i] = 0;
1307          jsrInfo.unusualReferenceMaps[jsrInfo.mergedReturnAddressMap + i] = 0;
1308        }
1309    
1310        /* get the indices of the maps for the combined subroutine map */
1311        int refMapIndex = deltaMap.getReferenceMapIndex();
1312        int nonRefMapIndex = deltaMap.getNonReferenceMapIndex();
1313        int returnAddressMapIndex = deltaMap.getReturnAddressMapIndex();
1314    
1315        /* merge the subroutine delta map into the invoker (base) map */
1316        for (i = 0; i < bytesPerMap(); i++) {
1317          /* first establish the change in the maps due to the combined subroutines */
1318          byte deltaRef = jsrInfo.unusualReferenceMaps[refMapIndex + i];
1319          byte deltaNonRef = jsrInfo.unusualReferenceMaps[nonRefMapIndex + i];
1320          byte deltaRtnAddr = jsrInfo.unusualReferenceMaps[returnAddressMapIndex + i];
1321          byte deltaAny = (byte) (deltaRef | deltaNonRef | deltaRtnAddr);
1322    
1323          /* There is no merging to be done for the return address map
1324           * since the invoker cannot have any return addressses since it
1325           * is guaranteed not to be a subroutine (and only subroutines
1326           * can generate return address map entries) */
1327          jsrInfo.unusualReferenceMaps[jsrInfo.mergedReturnAddressMap + i] = deltaRtnAddr;
1328    
1329          /* Get the base reference map (the high bit is used to denote jsr) */
1330          byte thisBase = referenceMaps[jsrBaseMapIndex + i];
1331          byte nextBase = (i + 1 < bytesPerMap()) ? referenceMaps[jsrBaseMapIndex + i + 1] : 0;
1332          byte baseRef = (byte) ((thisBase << 1) | ((0xff & nextBase) >>> 7));
1333    
1334          /* Merge the reference maps */
1335          byte mergedRef = (byte) (deltaRef | (baseRef & ~deltaAny));
1336          jsrInfo.unusualReferenceMaps[jsrInfo.mergedReferenceMap + i] = mergedRef;
1337    
1338          /*
1339             VM.sysWrite(" **** thisBase = "); VM.sysWrite(thisBase);
1340             VM.sysWrite("     nextBase = "); VM.sysWrite(nextBase);
1341             VM.sysWrite("     deltaRef = "); VM.sysWrite(deltaRef);
1342             VM.sysWrite("     deltaNonRef = "); VM.sysWrite(deltaNonRef);
1343             VM.sysWrite("     base = "); VM.sysWrite(base);
1344             VM.sysWrite("     newRef = "); VM.sysWrite(newRef);
1345             VM.sysWrite("\n");
1346           */
1347        }
1348    
1349        if (VM.TraceStkMaps) {
1350          //Note: this displays each byte as a word ... only look at low order byte
1351          VM.sysWrite("finalmergemaps-jsr total set2ref delta map  = ");
1352          for (i = 0; i < bytesPerMap(); i++) {
1353            VM.sysWrite(jsrInfo.unusualReferenceMaps[refMapIndex + i]);
1354          }
1355          VM.sysWrite("\n");
1356    
1357          VM.sysWrite("              -jsr total set2nonref delta map  = ");
1358          for (i = 0; i < bytesPerMap(); i++) {
1359            VM.sysWrite(jsrInfo.unusualReferenceMaps[nonRefMapIndex + i]);
1360          }
1361          VM.sysWrite("\n");
1362    
1363          VM.sysWrite("              -jsr base map  = ");
1364          for (i = 0; i < bytesPerMap(); i++)
1365          // ORIGINAL VM.sysWrite( jsrInfo.unusualReferenceMaps[jsrBaseMapIndex + i]);
1366          {
1367            VM.sysWrite(referenceMaps[jsrBaseMapIndex + i]);
1368          }
1369          VM.sysWrite("\n");
1370    
1371          VM.sysWrite("              -combined merged ref map  = ");
1372          for (i = 0; i < bytesPerMap(); i++) {
1373            VM.sysWrite(jsrInfo.unusualReferenceMaps[jsrInfo.mergedReferenceMap + i]);
1374          }
1375          VM.sysWrite("\n");
1376    
1377          VM.sysWrite("              -combined merged return address map  = ");
1378          for (i = 0; i < bytesPerMap(); i++) {
1379            VM.sysWrite(jsrInfo.unusualReferenceMaps[jsrInfo.mergedReturnAddressMap + i]);
1380          }
1381          VM.sysWrite("\n");
1382        }
1383      }
1384    
1385      /**
1386       * This routine is used to clean out the MethodMap of structures that
1387       * were allocated from temporary storage. Temporary storage is freed up
1388       *  between stack frames as the GC scans the stack.
1389       */
1390      public void cleanupPointers() {
1391        if (VM.TraceStkMaps) VM.sysWrite("ReferenceMaps- cleanupPointers\n");
1392      }
1393    
1394      /**
1395       * This routine is used to find an Unusual map with an index
1396       * greater than 127
1397       *
1398       */
1399    
1400      /**
1401       * Finds an unsual map with an index greater than 127. It returns the index
1402       * by doing a sequential scan and looking for the mapid in the normal map
1403       * directory.
1404       *
1405       * @param mapid the map's id
1406       * @return the map's index
1407       */
1408      int findUnusualMap(int mapid) {
1409        int i;
1410        // Greater than 127 map sites- can't use direct index.
1411        // Do sequential scan for rest of maps.  It's slow but should almost never
1412        // happen.
1413    
1414        for (i = JSR_INDEX_MASK; i < jsrInfo.numberUnusualMaps; i++) {
1415          if (jsrInfo.unusualMaps[i].getNormalMapIndex() == mapid) {
1416            break;
1417          }
1418        }
1419        if (i >= jsrInfo.numberUnusualMaps) {
1420          VM.sysFail(" can't find jsr map - PANIC !!!!");
1421        }
1422        return i;
1423      }
1424    
1425      /**
1426       * Shows the basic information for each of the maps.
1427       * This is for testing use.
1428       */
1429      public void showInfo() {
1430        VM.sysWriteln("showInfo- reference maps");
1431        if (MCSites == null) {
1432          VM.sysWrite(" no MCSites array - assume using cached data - can't do showInfo()");
1433          return;
1434        }
1435    
1436        VM.sysWrite(" MCSites.length = ", MCSites.length);
1437        VM.sysWrite(" mapCount = ", mapCount);
1438    //    VM.sysWriteln(" startLocal0Offset = ", startLocal0Offset);
1439    
1440        for (int i = 0; i < mapCount; i++) {
1441          VM.sysWrite("mapid = ", i);
1442          VM.sysWrite(" - machine  code offset ", MCSites[i]);
1443          VM.sysWrite("  -reference Map  =  ");
1444          for (int j = 0; j < bytesPerMap(); j++) {
1445            VM.sysWriteHex(referenceMaps[(i * bytesPerMap()) + j]);
1446          }
1447          VM.sysWriteln();
1448        }
1449      }
1450    
1451      /**
1452       * Show the basic information for a single map. This is for testing
1453       * use.
1454       */
1455      public void showAMap(int MCSiteIndex) {
1456        VM.sysWriteln("show the map for MCSite index= ", MCSiteIndex);
1457        VM.sysWrite("machine code offset = ", MCSites[MCSiteIndex]);
1458        VM.sysWrite("   reference Map  =  ");
1459        for (int i = 0; i < bytesPerMap(); i++) {
1460          VM.sysWrite(referenceMaps[(MCSiteIndex * bytesPerMap()) + i]);
1461        }
1462        VM.sysWriteln();
1463      }
1464    
1465      /**
1466       * Show the offsets for all the maps. This is for test use.
1467       */
1468      public void showOffsets() {
1469        VM.sysWrite("in showOffset- #maps = ");
1470        VM.sysWrite(mapCount);
1471        VM.sysWrite("\n");
1472        int i, tindex = 0;
1473    
1474        if (mapCount == 0) {
1475          VM.sysWrite(" no maps for method");
1476          return;
1477        }
1478        for (i = 0; i < mapCount; i++) {
1479          tindex = getNextRefIndex(tindex, i);
1480          VM.sysWrite("initial offset  = ");
1481          VM.sysWrite(tindex);
1482          VM.sysWrite(" for map ");
1483          VM.sysWrite(i);
1484          VM.sysWrite("\n");
1485          while (tindex != 0) {
1486            tindex = getNextRefIndex(tindex, i);
1487            VM.sysWrite("next offset = ");
1488            VM.sysWrite(tindex);
1489            if (tindex == 0) VM.sysWrite("---------------- end of map");
1490          }
1491        }
1492      }
1493    
1494      @Interruptible
1495      public int showReferenceMapStatistics(RVMMethod method) {
1496        int index = 0;
1497        int totalCount = 0;
1498        int count;
1499    
1500        VM.sysWrite("-- Number of refs for method =  ");
1501        VM.sysWrite(method.getDeclaringClass().getDescriptor());
1502        VM.sysWrite(".");
1503        VM.sysWrite(method.getName());
1504        VM.sysWrite("---------------------------\n");
1505    
1506        for (int i = 0; i < mapCount; i++) {
1507          byte mapindex = referenceMaps[i * bytesPerMap()];
1508          if (mapindex < 0) {
1509            // check for non jsr map
1510            VM.sysWrite("  -----skipping jsr map------- \n ");
1511            continue;
1512          }
1513          index = getNextRefIndex(index, i);
1514          count = 0;
1515          while (index != 0) {
1516            totalCount++;
1517            count++;
1518            index = getNextRefIndex(index, i);
1519            // display number of refs at each site - very noisy
1520            if (index == 0) {
1521              VM.sysWriteln("  -----map machine code offset = ", MCSites[i], "    number of refs in this map = ", count);
1522            }
1523          }
1524        }
1525        VM.sysWrite("----- Total number of refs in method  = ");
1526        VM.sysWrite(totalCount);
1527        VM.sysWrite("  total number of maps in method = ");
1528        VM.sysWrite(mapCount);
1529        VM.sysWrite("\n");
1530    
1531        return totalCount;
1532      }
1533    
1534      /* Interface for general queries such as given a GC point, if a stack slot
1535       * or a local variable is a reference.
1536       */
1537    
1538      /**
1539       * Query if a local variable has a reference type value
1540       * @param method  The method we're asking about.
1541       * @param mcoff  The machine code offset of the instruction *following* the
1542       *               actual instruction.
1543       * @param lidx the local index
1544       * @return {@code true}, if it is a reference type. {@code false}, otherwise
1545       */
1546      public boolean isLocalRefType(RVMMethod method, Offset mcoff, int lidx) {
1547        int bytenum, bitnum;
1548        byte[] maps;
1549    
1550        if (bytesPerMap() == 0) return false;           // no map ie no refs
1551        int mapid = locateGCPoint(mcoff, method);
1552    
1553        if (mapid >= 0) {
1554          // normal case
1555          bytenum = mapid * bytesPerMap();
1556          bitnum = lidx + 1 + 1; // 1 for being 1 based +1 for jsr bit
1557          maps = referenceMaps;
1558        } else {
1559          // in JSR
1560          bytenum = jsrInfo.mergedReferenceMap;
1561          bitnum = lidx + 1; // 1 for being 1 based
1562          maps = jsrInfo.unusualReferenceMaps;
1563        }
1564    
1565        // adjust bitnum and wordnum to bit within word
1566        while (bitnum > BITS_PER_MAP_ELEMENT) {
1567          bytenum++;
1568          bitnum -= BITS_PER_MAP_ELEMENT;
1569        }
1570    
1571        int mask = (1 << (BITS_PER_MAP_ELEMENT - bitnum));  // generate mask
1572    
1573        return ((mask & maps[bytenum]) != 0);
1574      }
1575    }