Skip to content

Commit

Permalink
Merge pull request jruby#8480 from headius/optimize_subclasses_walk
Browse files Browse the repository at this point in the history
Provide concrete-only traversal for Class#subclasses
  • Loading branch information
headius authored Dec 4, 2024
2 parents 422bb1c + 470dd56 commit 9d63c22
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 5 deletions.
16 changes: 16 additions & 0 deletions bench/bench_subclasses.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
require 'benchmark/ips'

Custom = Class.new(Object)
# create these once and hold references
SINGLETON_COUNT = 1000
many_singletons = SINGLETON_COUNT.times.map { c = Custom.new; class << c; end; c }

Benchmark.ips do |bm|
[1, 5, 10, 50].each do |count|
bm.report("#{count} thread Numeric.subclasses") do
Expand All @@ -24,5 +29,16 @@
}
}.each(&:join)
end
bm.report("#{count} thread Custom.subclasses with #{SINGLETON_COUNT} singletons") do
count.times.map {
Thread.new {
i = 10_000 / count
while i > 0
Custom.subclasses
i-=1
end
}
}.each(&:join)
end
end
end
13 changes: 8 additions & 5 deletions core/src/main/java/org/jruby/RubyClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -1106,7 +1106,7 @@ private int concreteSubclasses(RubyArray<RubyClass> subs) {
int clearedCount = 0;
while (subclassNode != null) {
RubyClass klass = subclassNode.ref.get();
subclassNode = subclassNode.next;
subclassNode = subclassNode.nextConcrete;

if (klass == null) {
clearedCount++;
Expand Down Expand Up @@ -1153,22 +1153,25 @@ private static SubclassNode rebuildSubclasses(SubclassNode subclassNode) {
RubyClass klass = ref.get();
subclassNode = subclassNode.next;
if (klass == null) continue;
newTop = new SubclassNode(ref, newTop);
newTop = new SubclassNode(klass, ref, newTop);
}
return newTop;
}

// TODO: make into a Record
static class SubclassNode {
final SubclassNode next;
final SubclassNode nextConcrete;
final boolean concrete;
final WeakReference<RubyClass> ref;
SubclassNode(RubyClass klass, SubclassNode next) {
ref = new WeakReference<>(klass);
this.next = next;
this(klass, new WeakReference<>(klass), next);
}
SubclassNode(WeakReference<RubyClass> ref, SubclassNode next) {
SubclassNode(RubyClass klass, WeakReference<RubyClass> ref, SubclassNode next) {
this.ref = ref;
this.next = next;
this.nextConcrete = next == null ? null : next.concrete ? next : next.nextConcrete;
this.concrete = !klass.isSingleton();
}
}

Expand Down

0 comments on commit 9d63c22

Please sign in to comment.