Fix excessive invalidation for opt_getinlinecache

YJIT expects the VM to invalidate opt_getinlinecache when updating the
constant cache, and the invalidation used to happen even when YJIT can't
use the cached value.

Once the first invalidation happens, the block for opt_getinlinecache
becomes a stub. When the stub is hit, YJIT fails to compile the
instruction as the cache is not usable. The stub becomes a block that
exits for opt_getinlinecache which can be invalidated again. Some
workloads that bust the interpreter's constant cache can create an
invalidation loop with this behavior.

Check if the cache is usable become doing invalidation to fix this
problem.

In the test harness, evaluate the test script in a lambda instead of a
proc so `return` doesn't return out of the harness.
This commit is contained in:
Alan Wu 2021-09-20 14:55:10 -04:00
parent 6ef1609fab
commit c46bda6f19
3 changed files with 36 additions and 3 deletions

View file

@ -394,6 +394,31 @@ class TestYJIT < Test::Unit::TestCase
RUBY
end
def test_no_excessive_opt_getinlinecache_invalidation
assert_compiles(<<~'RUBY', exits: :any, result: :ok)
objects = [Object.new, Object.new]
objects.each do |o|
class << o
def foo
Object
end
end
end
9000.times {
objects[0].foo
objects[1].foo
}
stats = YJIT.runtime_stats
return :ok unless stats[:all_stats]
return :ok if stats[:invalidation_count] < 10
:fail
RUBY
end
def assert_no_exits(script)
assert_compiles(script)
end
@ -437,7 +462,7 @@ class TestYJIT < Test::Unit::TestCase
script = <<~RUBY
#{"# frozen_string_literal: true" if frozen_string_literal}
_test_proc = proc {
_test_proc = -> {
#{test_script}
}
#{reset_stats}