Skip to content

instance_eval should defer creation of singleton class #8638

Description

@headius

Currently, when calling instance_eval against an object, JRuby will eagerly create a singleton class in preparation for any method definitions that might be coming. CRuby, on the other hand, defers creation until methods actually need to be defined, making instance_eval much cheaper in the absence of defs.

We can see this effect by doing instance_eval against chilled strings, which triggers verbose warnings under 3.4 (JRuby 10):

[] jruby $ cx 3.4 ruby -v -e '"".instance_eval { }'
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
[] jruby $ ruby -v -e '"".instance_eval { }'       
jruby 10.0.0.0-SNAPSHOT (3.4.0) 2025-02-18 493d0005c4 OpenJDK 64-Bit Server VM 21.0.5+11-LTS on 21.0.5+11-LTS +indy +jit [arm64-darwin]
-e:1: warning: literal string will be frozen in the future

In addition to causing warnings (and eventually errors) for tests that instance_eval against "frozen" strings, it greatly increases the overhead of non-def instance_eval:

[] jruby $ cx 3.4 ruby -v -rbenchmark -e '5.times { puts Benchmark.measure { 10_000_000.times { Object.new.instance_eval {} } } }'
ruby 3.4.1 (2024-12-25 revision 48d4efcb85) +PRISM [arm64-darwin24]
  1.497619   0.009447   1.507066 (  1.512211)
  1.511998   0.011041   1.523039 (  1.632321)
  1.525667   0.017188   1.542855 (  1.581538)
  1.527588   0.011892   1.539480 (  1.554302)
  1.519021   0.012526   1.531547 (  1.571109)
[] jruby $ ruby -v -rbenchmark -e '5.times { puts Benchmark.measure { 10_000_000.times { Object.new.instance_eval {} } } }' 
jruby 10.0.0.0-SNAPSHOT (3.4.0) 2025-02-18 493d0005c4 OpenJDK 64-Bit Server VM 21.0.5+11-LTS on 21.0.5+11-LTS +indy +jit [arm64-darwin]
  8.730000   0.470000   9.200000 (  4.080593)
  6.840000   0.470000   7.310000 (  3.754422)
  8.690000   0.440000   9.130000 (  4.102935)
  6.740000   1.020000   7.760000 (  3.863980)
  8.910000   0.740000   9.650000 (  4.235179)

CRuby avoids creating the singleton eagerly by setting a singleton flag into the cref scope here:

https://github.com/ruby/ruby/blob/4ac75f6f6453bbf3c89f5b9ae02a03085b506ed5/vm_eval.c#L2233

This flag is later used when acquiring the class to be used for method definitions:

https://github.com/ruby/ruby/blob/4ac75f6f6453bbf3c89f5b9ae02a03085b506ed5/eval_intern.h#L192-L201

The performance improvement for def-less instance_eval alone would be worth making this change, but we eventually must eliminate the errors that happen for instance_eval against frozen objects (and in the shorter term, the warnings that come from instance_eval on a "chilled" string).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions