@@ -278,11 +278,13 @@ private void generateTypeCheckSlots() {
278278 int [] slots = classIDMap .get (type );
279279 for (int i = 0 ; i < slots .length ; i ++) {
280280 typeCheckSlots [i ] = getShortValue (slots [i ]);
281+ assert typeCheckSlots [i ] < SLOT_CAPACITY ;
281282 }
282283 slots = interfaceIDMap .get (type );
283284 if (slots != null ) {
284285 for (int i = 0 ; i < slots .length ; i ++) {
285286 typeCheckSlots [numClassSlots + i ] = getShortValue (slots [i ]);
287+ assert typeCheckSlots [numClassSlots + i ] < SLOT_CAPACITY ;
286288 }
287289 }
288290
@@ -373,23 +375,25 @@ private static boolean shouldIncludeType(HostedType type) {
373375 * against non-interface types can be accomplished through a range check.
374376 * <p>
375377 * In our algorithm, in order to guarantee ID information can fit into two bytes, the type ids
376- * are spread out into multiple slots when the two byte capacity is exceeded.
378+ * are spread out into multiple slots when the two byte capacity is exceeded. To do so, the
379+ * concept of a reservedID is introduced. ReservedIDs are assigned backwards from the slot's
380+ * capacity and are used to guarantee subtyping works correct when a type's subtypes will
381+ * overfill the current slot.
377382 */
378383 private void calculateClassIDs () {
379384 ArrayList <Integer > currentIDs = new ArrayList <>();
380- ArrayList <Integer > reservedIDs = new ArrayList <>();
381- currentIDs .add (- 1 );
382- reservedIDs .add (SLOT_CAPACITY );
385+ ArrayList <Integer > numReservedIDs = new ArrayList <>();
386+ currentIDs .add (0 );
387+ numReservedIDs .add (0 );
383388 for (HostedType root : allReachableRoots ) {
384- assert !isInterface (root );
385- classIdHelper (root , currentIDs , reservedIDs );
389+ classIdHelper (root , currentIDs , numReservedIDs );
386390 }
387391
388392 /* Recording the number of slots reserved for class IDs. */
389393 assert numClassSlots == -1 ;
390394 numClassSlots = currentIDs .size ();
391395
392- /* Setting class slot for interfaces - will integrate this with classIDHelper eventually . */
396+ /* Setting class slot for interfaces to be the same as the object type . */
393397 for (HostedType type : allReachableTypes ) {
394398 if (isInterface (type )) {
395399 int dim = type .getArrayDimension ();
@@ -414,15 +418,13 @@ private ClassIDState(int reservedID, int slotNum, int assignedID, int maxSubtype
414418 }
415419
416420 /**
417- * This method assigns ids to class types. interfaces are performed using the information
421+ * This method assigns ids to class types. Interfaces are performed using the information
418422 * calculated in {@link #computeInterfaceSlots()}.
419423 */
420- private void classIdHelper (HostedType type , ArrayList <Integer > currentIDs , ArrayList <Integer > reservedIDs ) {
421- assert shouldIncludeType (type );
422- boolean isTypeInterface = isInterface (type );
423- assert !isTypeInterface ;
424+ private void classIdHelper (HostedType type , ArrayList <Integer > currentIDs , ArrayList <Integer > numReservedIDs ) {
425+ assert shouldIncludeType (type ) && !isInterface (type );
424426
425- ClassIDState state = generateClassIDState (type , currentIDs , reservedIDs );
427+ ClassIDState state = generateClassIDState (type , currentIDs , numReservedIDs );
426428 int reservedID = state .reservedID ;
427429 int slotNum = state .slotNum ;
428430 int assignedID = state .assignedID ;
@@ -441,67 +443,84 @@ private void classIdHelper(HostedType type, ArrayList<Integer> currentIDs, Array
441443 */
442444 continue ;
443445 }
444- classIdHelper (subtype , currentIDs , reservedIDs );
446+ classIdHelper (subtype , currentIDs , numReservedIDs );
445447
446448 assert currentIDs .get (slotNum ) >= assignedID ; // IDs should always be increasing.
447449 }
448450
449- /* Determining range of values assigned to subtypes. */
450- if (!isTypeInterface ) {
451- type .setTypeCheckSlot (getShortValue (slotNum ));
452- int currentID = currentIDs .get (slotNum );
453- assert currentID == maxSubtypeID ;
454- type .setTypeCheckRange (getShortValue (assignedID ), getShortValue (currentID - assignedID + 1 ));
455- }
456- if (reservedID != -1 ) {
457- currentIDs .set (slotNum , reservedID );
458- reservedIDs .set (slotNum , reservedID + 1 ); // setting back to original value
451+ /* Validating calculation of maxSubtypeID. */
452+ assert currentIDs .get (slotNum ) == maxSubtypeID ;
453+
454+ /* Record type's slot and range. */
455+ type .setTypeCheckSlot (getShortValue (slotNum ));
456+ type .setTypeCheckRange (getShortValue (assignedID ), getShortValue (maxSubtypeID - assignedID + 1 ));
457+ if (reservedID != 0 ) {
458+ /* Must distinguish subsequent ID assignments from this type. */
459+ assert numReservedIDs .get (slotNum ) == reservedID ;
460+ int newNumReservedIDs = reservedID - 1 ;
461+ numReservedIDs .set (slotNum , newNumReservedIDs );
462+ currentIDs .set (slotNum , newNumReservedIDs == 0 ? 0 : SLOT_CAPACITY - newNumReservedIDs );
459463 }
460464 }
461465
462- private ClassIDState generateClassIDState (HostedType type , ArrayList <Integer > currentIDs , ArrayList <Integer > reservedIDs ) {
463- int reservedID = -1 ;
466+ private ClassIDState generateClassIDState (HostedType type , ArrayList <Integer > currentIDs , ArrayList <Integer > numReservedIDs ) {
467+ /*
468+ * A reserved ID is assigned when this type's slot will overflow while assigning IDs to its
469+ * subtypes.
470+ */
471+ int reservedID = 0 ;
464472 int slotNum = currentIDs .size () - 1 ;
465473 int numDescendants = numClassDescendants .getOrDefault (type , 0 );
466- int assignedID = currentIDs .get (slotNum ) + 1 ; // need start at the next free stop
467- int currentReservedID = reservedIDs .get (slotNum ); // max value allowed at this spot
468- assert assignedID < currentReservedID ;
469-
470- if (assignedID + 1 == currentReservedID ) {
471- /* No more space left. Making filled slot's value different than predecessor. */
472- currentIDs .set (slotNum , assignedID );
474+ /* first trying to assign next sequential id. */
475+ int assignedID = currentIDs .get (slotNum ) + 1 ;
476+ /* Number of slot currently reserved. This effectively lowers the slot's capacity. */
477+ int currentNumReservedIDs = numReservedIDs .get (slotNum );
478+ int currentCapacity = SLOT_CAPACITY - currentNumReservedIDs ;
479+ assert assignedID <= currentCapacity ;
480+
481+ if (assignedID == currentCapacity ) {
482+ /*
483+ * No more space left. Assigning overflowed slot appropriate "end" value.
484+ */
485+ currentIDs .set (slotNum , currentNumReservedIDs == 0 ? 0 : SLOT_CAPACITY - currentNumReservedIDs );
473486 slotNum ++;
474- assignedID = 1 ;
475487 currentIDs .add (0 );
476- currentReservedID = SLOT_CAPACITY ;
477- reservedIDs .add (currentReservedID );
488+ currentNumReservedIDs = 0 ;
489+ currentCapacity = SLOT_CAPACITY ;
490+ numReservedIDs .add (currentNumReservedIDs );
491+ assignedID = 1 ;
478492 }
479493 int maxSubtypeID = assignedID + numDescendants ;
480- if (maxSubtypeID >= currentReservedID ) {
481- /* Means this types descendants will overfill this type. */
482- reservedID = currentReservedID - 1 ;
483- if (assignedID + 1 == reservedID ) {
494+ if (maxSubtypeID >= currentCapacity ) {
495+ /*
496+ * Means this types descendants will overfill this slot. In this case, need to reserved
497+ * an ID and force all descendants to have values between the current assignable and the
498+ * reserved ID (inclusive). Non-descendants are then assigned the next ID (mod
499+ * capacity).
500+ */
501+ if (assignedID + 1 == currentCapacity ) {
484502 /*
485- * Not enough space for reserved ID + new- slot filler -- move on to next slot. Also,
486- * making filled slot's value different than predecessor .
503+ * Not enough space to add a reserved slot at end of the list, so must move to next
504+ * slot.
487505 */
488- currentIDs .set (slotNum , reservedID );
506+ currentIDs .set (slotNum , currentNumReservedIDs == 0 ? 0 : SLOT_CAPACITY - currentNumReservedIDs );
489507 slotNum ++;
490- assignedID = 1 ;
491508 currentIDs .add (0 );
509+ currentNumReservedIDs = 0 ;
510+ currentCapacity = SLOT_CAPACITY ;
511+ numReservedIDs .add (currentNumReservedIDs );
512+ assignedID = 1 ;
492513 maxSubtypeID = assignedID + numDescendants ;
493- currentReservedID = SLOT_CAPACITY ;
494- reservedIDs .add (currentReservedID );
495- if (maxSubtypeID >= currentReservedID ) {
496- reservedID = currentReservedID - 1 ;
497- reservedIDs .set (slotNum , reservedID );
498- maxSubtypeID = reservedID - 1 ;
499- } else {
500- reservedID = -1 ;
501- }
502- } else {
503- reservedIDs .set (slotNum , reservedID );
504- maxSubtypeID = reservedID - 1 ;
514+ }
515+
516+ /*
517+ * Have to recheck whether a reservedID is needed since a new slot may have been added.
518+ */
519+ if (maxSubtypeID >= currentCapacity ) {
520+ currentNumReservedIDs ++;
521+ reservedID = currentNumReservedIDs ;
522+ maxSubtypeID = SLOT_CAPACITY - reservedID ;
523+ numReservedIDs .set (slotNum , currentNumReservedIDs );
505524 }
506525 }
507526
@@ -515,7 +534,7 @@ private ClassIDState generateClassIDState(HostedType type, ArrayList<Integer> cu
515534 * the slot capacity.
516535 */
517536 private static short getShortValue (int intValue ) {
518- assert SLOT_CAPACITY <= 1 << 16 && intValue < SLOT_CAPACITY ;
537+ assert intValue < ( 1 << 16 ) ;
519538 return (short ) intValue ;
520539 }
521540
0 commit comments