1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
ruby--ruby/bootstraptest/test_constant_cache.rb
Kevin Newton 6068da8937 Finer-grained constant cache invalidation (take 2)
This commit reintroduces finer-grained constant cache invalidation.
After 8008fb7 got merged, it was causing issues on token-threaded
builds (such as on Windows).

The issue was that when you're iterating through instruction sequences
and using the translator functions to get back the instruction structs,
you're either using `rb_vm_insn_null_translator` or
`rb_vm_insn_addr2insn2` depending if it's a direct-threading build.
`rb_vm_insn_addr2insn2` does some normalization to always return to
you the non-trace version of whatever instruction you're looking at.
`rb_vm_insn_null_translator` does not do that normalization.

This means that when you're looping through the instructions if you're
trying to do an opcode comparison, it can change depending on the type
of threading that you're using. This can be very confusing. So, this
commit creates a new translator function
`rb_vm_insn_normalizing_translator` to always return the non-trace
version so that opcode comparisons don't have to worry about different
configurations.

[Feature #18589]
2022-04-01 14:48:22 -04:00

187 lines
2.3 KiB
Ruby

# Constant lookup is cached.
assert_equal '1', %q{
CONST = 1
def const
CONST
end
const
const
}
# Invalidate when a constant is set.
assert_equal '2', %q{
CONST = 1
def const
CONST
end
const
CONST = 2
const
}
# Invalidate when a constant of the same name is set.
assert_equal '1', %q{
CONST = 1
def const
CONST
end
const
class Container
CONST = 2
end
const
}
# Invalidate when a constant is removed.
assert_equal 'missing', %q{
class Container
CONST = 1
def const
CONST
end
def self.const_missing(name)
'missing'
end
new.const
remove_const :CONST
end
Container.new.const
}
# Invalidate when a constant's visibility changes.
assert_equal 'missing', %q{
class Container
CONST = 1
def self.const_missing(name)
'missing'
end
end
def const
Container::CONST
end
const
Container.private_constant :CONST
const
}
# Invalidate when a constant's visibility changes even if the call to the
# visibility change method fails.
assert_equal 'missing', %q{
class Container
CONST1 = 1
def self.const_missing(name)
'missing'
end
end
def const1
Container::CONST1
end
const1
begin
Container.private_constant :CONST1, :CONST2
rescue NameError
end
const1
}
# Invalidate when a module is included.
assert_equal 'INCLUDE', %q{
module Include
CONST = :INCLUDE
end
class Parent
CONST = :PARENT
end
class Child < Parent
def const
CONST
end
new.const
include Include
end
Child.new.const
}
# Invalidate when const_missing is hit.
assert_equal '2', %q{
module Container
Foo = 1
Bar = 2
class << self
attr_accessor :count
def const_missing(name)
@count += 1
@count == 1 ? Foo : Bar
end
end
@count = 0
end
def const
Container::Baz
end
const
const
}
# Invalidate when the iseq gets cleaned up.
assert_equal '2', %q{
CONSTANT = 1
iseq = RubyVM::InstructionSequence.compile(<<~RUBY)
CONSTANT
RUBY
iseq.eval
iseq = nil
GC.start
CONSTANT = 2
}
# Invalidate when the iseq gets cleaned up even if it was never in the cache.
assert_equal '2', %q{
CONSTANT = 1
iseq = RubyVM::InstructionSequence.compile(<<~RUBY)
CONSTANT
RUBY
iseq = nil
GC.start
CONSTANT = 2
}