Skip to content
  • Jemma Issroff's avatar
    c1ab6ddc
    Transition complex objects to "too complex" shape · c1ab6ddc
    Jemma Issroff authored
    
    
    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: default avatarAaron Patterson <tenderlove@ruby-lang.org>
    c1ab6ddc
    Transition complex objects to "too complex" shape
    Jemma Issroff authored
    
    
    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: default avatarAaron Patterson <tenderlove@ruby-lang.org>
Loading