Skip to content

Commit 9d63c22

Browse files
authored
Merge pull request jruby#8480 from headius/optimize_subclasses_walk
Provide concrete-only traversal for Class#subclasses
2 parents 422bb1c + 470dd56 commit 9d63c22

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

bench/bench_subclasses.rb

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
require 'benchmark/ips'
22

3+
Custom = Class.new(Object)
4+
# create these once and hold references
5+
SINGLETON_COUNT = 1000
6+
many_singletons = SINGLETON_COUNT.times.map { c = Custom.new; class << c; end; c }
7+
38
Benchmark.ips do |bm|
49
[1, 5, 10, 50].each do |count|
510
bm.report("#{count} thread Numeric.subclasses") do
@@ -24,5 +29,16 @@
2429
}
2530
}.each(&:join)
2631
end
32+
bm.report("#{count} thread Custom.subclasses with #{SINGLETON_COUNT} singletons") do
33+
count.times.map {
34+
Thread.new {
35+
i = 10_000 / count
36+
while i > 0
37+
Custom.subclasses
38+
i-=1
39+
end
40+
}
41+
}.each(&:join)
42+
end
2743
end
2844
end

core/src/main/java/org/jruby/RubyClass.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1106,7 +1106,7 @@ private int concreteSubclasses(RubyArray<RubyClass> subs) {
11061106
int clearedCount = 0;
11071107
while (subclassNode != null) {
11081108
RubyClass klass = subclassNode.ref.get();
1109-
subclassNode = subclassNode.next;
1109+
subclassNode = subclassNode.nextConcrete;
11101110

11111111
if (klass == null) {
11121112
clearedCount++;
@@ -1153,22 +1153,25 @@ private static SubclassNode rebuildSubclasses(SubclassNode subclassNode) {
11531153
RubyClass klass = ref.get();
11541154
subclassNode = subclassNode.next;
11551155
if (klass == null) continue;
1156-
newTop = new SubclassNode(ref, newTop);
1156+
newTop = new SubclassNode(klass, ref, newTop);
11571157
}
11581158
return newTop;
11591159
}
11601160

11611161
// TODO: make into a Record
11621162
static class SubclassNode {
11631163
final SubclassNode next;
1164+
final SubclassNode nextConcrete;
1165+
final boolean concrete;
11641166
final WeakReference<RubyClass> ref;
11651167
SubclassNode(RubyClass klass, SubclassNode next) {
1166-
ref = new WeakReference<>(klass);
1167-
this.next = next;
1168+
this(klass, new WeakReference<>(klass), next);
11681169
}
1169-
SubclassNode(WeakReference<RubyClass> ref, SubclassNode next) {
1170+
SubclassNode(RubyClass klass, WeakReference<RubyClass> ref, SubclassNode next) {
11701171
this.ref = ref;
11711172
this.next = next;
1173+
this.nextConcrete = next == null ? null : next.concrete ? next : next.nextConcrete;
1174+
this.concrete = !klass.isSingleton();
11721175
}
11731176
}
11741177

0 commit comments

Comments
 (0)