Skip to content

Commit

Permalink
Use RubyVM.stat to invalidate module hosts cache
Browse files Browse the repository at this point in the history
Or its JRuby counterpart (jruby/jruby#4384).

Truffle doesn't seem to have anything comparable, so this breaks compatibility.
  • Loading branch information
dgutov committed Mar 27, 2024
1 parent d507b24 commit 27d84d2
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 56 deletions.
2 changes: 0 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ jobs:
include:
- ruby: jruby-head
experimental: true
- ruby: truffleruby-head
experimental: true

steps:
- name: Checkout Robe
Expand Down
79 changes: 25 additions & 54 deletions lib/robe/sash/includes_tracker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,72 +3,43 @@
module Robe
class Sash
class IncludesTracker
def self.method_owner_and_inst(owner, name_cache)
includers = maybe_scan
class << self
attr_accessor :vm_stats
attr_accessor :hosts

mod, inst = includers[owner].first
def method_owner_and_inst(owner, name_cache)
rescan_maybe

if mod
[name_cache[mod], inst]
else
[nil, true]
end
end

def self.reset!
@@hosts = nil
end

def self.maybe_scan
includers = @@hosts
mod, inst = hosts[owner].first

unless includers
@@hosts = includers = Hash.new { |h, k| h[k] = [] }
return [nil, true] unless mod

ObjectSpace.each_object(Module) do |cl|
next unless cl.respond_to?(:included_modules)
next if cl.singleton_class?
cl.included_modules.each { |mod| includers[mod] << [cl, true] }
sc = cl.__singleton_class__
sc.included_modules.each { |mod| includers[mod] << [cl, nil] }
end
[name_cache[mod], inst]
end

includers
end
def rescan_maybe
return hosts if vm_stats == current_vm_stats

if Module.respond_to?(:prepend)
module Invalidator
private
self.hosts = Hash.new { |h, k| h[k] = [] }
self.vm_stats = current_vm_stats

def included(other)
IncludesTracker.reset!
super(other)
end
ObjectSpace.each_object(Module) do |mod|
next unless mod.respond_to?(:included_modules)
next if mod.singleton_class?

def extended(other)
IncludesTracker.reset!
super(other)
mod.included_modules.each { |imod| hosts[imod] << [mod, true] }
sc = mod.__singleton_class__
sc.included_modules.each { |imod| hosts[imod] << [mod, nil] }
end
end

Module.send(:prepend, Invalidator)
else
Module.class_eval do
alias_method :__orig_included, :included
alias_method :__orig_extended, :extended

private

# Cannot hook into this method without :prepend.
def included(other)
IncludesTracker.reset!
__orig_included(other)
end
self.hosts
end

def extended(other)
IncludesTracker.reset!
__orig_extended(other)
def current_vm_stats
if RUBY_ENGINE == 'jruby'
JRuby::Util::cache_stats
else
RubyVM.stat
end
end
end
Expand Down

0 comments on commit 27d84d2

Please sign in to comment.