1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00

Fix inconsistency with opt_aref_with

opt_aref_with is an optimized instruction for accessing a Hash using a
non-frozen string key (ie. from a file without frozen_string_literal).
It attempts to avoid allocating the string, and instead silently using a
frozen string (hash string keys are always fstrings).

Because this is just an optimization, it should be invisible to the
user. However, previously this optimization was could be seen via hashes
with default procs.

For example, previously:

    h = Hash.new { |h, k| k.frozen? }
    str = "foo"
    h[str]   # false
    h["foo"] # true when optimizations enabled

This commit checks that the Hash doesn't have a default proc when using
opt_aref_with.
This commit is contained in:
John Hawthorn 2022-07-28 16:41:46 -07:00
parent 1e7a2415a4
commit 70b60d24b9
Notes: git 2022-08-05 06:49:07 +09:00
2 changed files with 16 additions and 1 deletions

View file

@ -304,6 +304,20 @@ class TestHash < Test::Unit::TestCase
assert_equal before, ObjectSpace.count_objects[:T_STRING]
end
def test_AREF_fstring_key_default_proc
assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
h = Hash.new do |h, k|
k.frozen?
end
str = "foo"
refute str.frozen? # assumes this file is frozen_string_literal: false
refute h[str]
refute h["foo"]
end;
end
def test_ASET_fstring_key
a, b = {}, {}
assert_equal 1, a["abc"] = 1

View file

@ -5458,7 +5458,8 @@ vm_opt_aref_with(VALUE recv, VALUE key)
{
if (!SPECIAL_CONST_P(recv) && RBASIC_CLASS(recv) == rb_cHash &&
BASIC_OP_UNREDEFINED_P(BOP_AREF, HASH_REDEFINED_OP_FLAG) &&
rb_hash_compare_by_id_p(recv) == Qfalse) {
rb_hash_compare_by_id_p(recv) == Qfalse &&
!FL_TEST(recv, RHASH_PROC_DEFAULT)) {
return rb_hash_aref(recv, key);
}
else {