📘

[Feature #21553] RubyVM の opt_aref_with / opt_aset_with の命令を削除するチケット

に公開

[Feature #21553] Remove opt_aref_with and opt_aset_with instructions

  • RubyVM の opt_aref_with opt_aset_with の命令を削除するチケット
  • これらの命令は hash["bar"]hash["bar"] = 42 で使用されるが文字列リテラルが freeze されていない場合のみ使用される
# こっちは freeze されていないので opt_aref_with を利用する
$ ruby --dump=insns -e 'foo["bar"]'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)>
0000 putself                                                          (   1)[Li]
0001 opt_send_without_block                 <calldata!mid:foo, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0003 opt_aref_with                          "bar", <calldata!mid:[], argc:1, ARGS_SIMPLE>
0006 leave
# こっちは freeze されているので opt_aref_with は利用されない
$ ruby --dump=insns -e 'foo["bar"]'
== disasm: #<ISeq:<main>@-e:1 (1,0)-(1,10)>
0000 putself                                                          (   1)[Li]
0001 opt_send_without_block                 <calldata!mid:foo, argc:0, FCALL|VCALL|ARGS_SIMPLE>
0003 opt_aref_with                          "bar", <calldata!mid:[], argc:1, ARGS_SIMPLE>
0006 leave
  • opt_aset_with / opt_aset_with を削除するモチベーションとしては JIT のコンパイラが簡素になることとチルド文字列で以下のようなケースで『警告が出ない』というバグが修正されれる点みたいですね
class Foo
  def self.[](x)
    x.gsub!(/hello/, "hi")
  end
end

# 本来であれば "hello world" はチルド文字列で定義され、これが破壊的変更がされると警告が出る
# Foo.[] ではキーの値を破壊的に変更しているので警告が出てほしいが警告がでないバグがある
Foo["hello world"]
  • #[]#[]= でキーが破壊的に変更されるようなコードはないとは思うんですがそれが本当かどうかを警告で検知する必要はありそうですかねえ
  • この提案は開発版の Ruby 3.5-dev で既に組み込まれているので上記のようなコードは警告が出るようになる
class Foo
  def self.[](x)
    x.gsub!(/hello/, "hi")
  end
end

Foo["hello world"]
# Ruby 3.4 => no warning
# Ruby 3.5 => warning: literal string will be frozen in the future (run with --debug-frozen-string-literal for more information)
GitHubで編集を提案

Discussion