@@ -1014,7 +1014,7 @@ public IRubyObject initialize_copy(IRubyObject original) {
10141014 public IRubyObject subclasses (ThreadContext context ) {
10151015 RubyArray <RubyClass > subs = newConcreteSubclassesArray (context );
10161016 int clearedCount = concreteSubclasses (subs );
1017- finishConcreteSubclasses (subs , clearedCount );
1017+ finishConcreteSubclasses (context , subs , clearedCount );
10181018
10191019 return subs ;
10201020 }
@@ -1059,7 +1059,7 @@ public Collection<RubyClass> subclasses(boolean includeDescendants) {
10591059 }
10601060
10611061 private RubyArray <RubyClass > newConcreteSubclassesArray (ThreadContext context ) {
1062- RubyArray <RubyClass > subs = RubyArray .newArray (context . runtime , this .concreteSubclassesEstimate );
1062+ RubyArray <RubyClass > subs = RubyArray .newArrayRaw (context , this .concreteSubclassesEstimate );
10631063 return subs ;
10641064 }
10651065
@@ -1103,39 +1103,44 @@ private void finishSubclasses(Collection<RubyClass> mine, int clearedCount, bool
11031103
11041104 private int concreteSubclasses (RubyArray <RubyClass > subs ) {
11051105 SubclassNode subclassNode = this .subclassNode ;
1106+
1107+ // skip first entry if not concrete
1108+ if (!subclassNode .concrete ) subclassNode = subclassNode .nextConcrete ;
1109+
11061110 int clearedCount = 0 ;
11071111 while (subclassNode != null ) {
11081112 RubyClass klass = subclassNode .ref .get ();
11091113 subclassNode = subclassNode .nextConcrete ;
11101114
11111115 if (klass == null ) {
11121116 clearedCount ++;
1113- continue ;
1117+ } else {
1118+ processConcreteSubclass (subs , klass );
11141119 }
11151120
1116- processConcreteSubclass (subs , klass );
11171121 }
11181122 return clearedCount ;
11191123 }
11201124
11211125 private static void processConcreteSubclass (RubyArray <RubyClass > subs , RubyClass klass ) {
1122- if ( !klass .isSingleton ()) {
1123- if ( klass . isIncluded () || klass . isPrepended ()) {
1124- klass .concreteSubclasses ( subs );
1125- } else {
1126- subs . append ( klass );
1127- }
1126+ assert !klass .isSingleton ();
1127+
1128+ if ( klass . isIncluded () || klass .isPrepended ()) {
1129+ klass . concreteSubclasses ( subs );
1130+ } else {
1131+ subs . append ( klass );
11281132 }
11291133 }
11301134
1131- private void finishConcreteSubclasses (RubyArray <RubyClass > subs , int clearedCount ) {
1135+ private void finishConcreteSubclasses (ThreadContext context , RubyArray <RubyClass > subs , int clearedCount ) {
1136+ subs .fillRestWithNil (context );
11321137 int newSize = subs .size ();
1133- concreteSubclassesEstimate = newSize + 4 ;
1138+ concreteSubclassesEstimate = newSize ;
11341139 cleanSubclasses (newSize , clearedCount );
11351140 }
11361141
11371142 private void cleanSubclasses (int size , int vacated ) {
1138- // tidy up if more than 25% cleared references
1143+ // tidy up if more than threshold of cleared references
11391144 if ((double ) vacated / size > SUBCLASSES_CLEAN_FACTOR ) {
11401145 SubclassNode subclassNode = this .subclassNode ;
11411146 SubclassNode newTop = rebuildSubclasses (subclassNode );
0 commit comments