ruby/internal
Jemma Issroff c1ab6ddc9a Transition complex objects to "too complex" shape
When an object becomes "too complex" (in other words it has too many
variations in the shape tree), we transition it to use a "too complex"
shape and use a hash for storing instance variables.

Without this patch, there were rare cases where shape tree growth could
"explode" and cause performance degradation on what would otherwise have
been cached fast paths.

This patch puts a limit on shape tree growth, and gracefully degrades in
the rare case where there could be a factorial growth in the shape tree.

For example:

```ruby
class NG; end

HUGE_NUMBER.times do
  NG.new.instance_variable_set(:"@unique_ivar_#{_1}", 1)
end
```

We consider objects to be "too complex" when the object's class has more
than SHAPE_MAX_VARIATIONS (currently 8) leaf nodes in the shape tree and
the object introduces a new variation (a new leaf node) associated with
that class.

For example, new variations on instances of the following class would be
considered "too complex" because those instances create more than 8
leaves in the shape tree:

```ruby
class Foo; end
9.times { Foo.new.instance_variable_set(":@uniq_#{_1}", 1) }
```

However, the following class is *not* too complex because it only has
one leaf in the shape tree:

```ruby
class Foo
  def initialize
    @a = @b = @c = @d = @e = @f = @g = @h = @i = nil
  end
end
9.times { Foo.new }
``

This case is rare, so we don't expect this change to impact performance
of most applications, but it needs to be handled.

Co-Authored-By: Aaron Patterson <tenderlove@ruby-lang.org>
2022-12-15 10:06:04 -08:00
..
array.h Add Data class implementation: Simple immutable value object 2022-09-30 18:23:19 +09:00
basic_operators.h Fix parens on LIKELY in basic operators 2022-12-12 14:05:43 -08:00
bignum.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
bits.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
class.h Add variation_count on classes 2022-12-15 10:06:04 -08:00
cmdlineopt.h YJIT: Lazily enable YJIT after prelude (#6597) 2022-10-24 12:20:44 -04:00
compar.h Introduce BOP_CMP for optimized comparison 2022-12-06 12:37:23 -08:00
compile.h `RubyVM.keep_script_lines` 2021-10-21 16:17:39 +09:00
compilers.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
complex.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
cont.h Introduce `Fiber#storage` for inheritable fiber-scoped variables. (#6612) 2022-12-01 23:00:33 +13:00
dir.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
enc.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
encoding.h parenthesize to macro 2022-12-02 01:31:27 +09:00
enum.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
enumerator.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
error.h suppress GCC's -Wsuggest-attribute=format 2021-09-10 20:00:06 +09:00
eval.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
file.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
fixnum.h Fix rb_fix_mul_fix on OpenBSD/mips64 2022-07-03 09:42:44 -07:00
gc.h Transition complex objects to "too complex" shape 2022-12-15 10:06:04 -08:00
hash.h Restore Hash#compare_by_identity mode [Bug #18171] 2021-10-02 11:43:35 +09:00
imemo.h Revert this until we can figure out WB issues or remove shapes from GC 2022-09-26 16:10:11 -07:00
inits.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
io.h Move some function declaration to internal/io.h 2021-09-28 18:08:08 +13:00
load.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
loadpath.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
math.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
missing.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
numeric.h Use `roomof` macro for rounding up divisions 2022-10-14 19:23:25 +09:00
object.h Revert "Revert "This commit implements the Object Shapes technique in CRuby."" 2022-10-11 08:40:56 -07:00
parse.h Enhance keep_tokens option for RubyVM::AbstractSyntaxTree parsing methods 2022-11-21 09:01:34 +09:00
proc.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
process.h process.c: Add Process._fork (#5017) 2021-10-25 20:47:19 +09:00
ractor.h internal/ractor.h: Added 2022-03-30 16:50:46 +09:00
random.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
range.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
rational.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
re.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
sanitizers.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
serial.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
signal.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
static_assert.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
string.h Use shared flags of the type 2022-11-02 11:03:21 -04:00
struct.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
symbol.h Ensure _id2ref finds symbols with the correct type 2022-07-20 10:38:44 -07:00
thread.h Add `eval: true/false` flag to `Coverage.setup`. 2022-09-29 09:44:14 +13:00
time.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
transcode.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
util.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00
variable.h Transition complex objects to "too complex" shape 2022-12-15 10:06:04 -08:00
vm.h Remove unused class serial 2022-10-21 14:56:48 -07:00
warnings.h internal/*.h: skip doxygen 2021-09-10 20:00:06 +09:00