diff --git a/NEWS.md b/NEWS.md index bc72ba55c25831..77ec892b661406 100644 --- a/NEWS.md +++ b/NEWS.md @@ -15,6 +15,8 @@ Note: We're only listing outstanding class updates. * `Array#pack` accepts a new format `R` and `r` for unpacking unsigned and signed LEB128 encoded integers. [[Feature #21785]] + * `Array#pack` accepts a new format `^` that returns the current offset. + Useful when combined with variable width formats like LEB128. [[Feature #21796]] * ENV @@ -164,6 +166,7 @@ A lot of work has gone into making Ractors more stable, performant, and usable. [Feature #15330]: https://bugs.ruby-lang.org/issues/15330 [Feature #21390]: https://bugs.ruby-lang.org/issues/21390 [Feature #21785]: https://bugs.ruby-lang.org/issues/21785 +[Feature #21796]: https://bugs.ruby-lang.org/issues/21796 [Feature #21853]: https://bugs.ruby-lang.org/issues/21853 [Feature #21861]: https://bugs.ruby-lang.org/issues/21861 [Feature #21932]: https://bugs.ruby-lang.org/issues/21932 diff --git a/error.c b/error.c index 52bd3629bf2d13..ed7394dbf5e756 100644 --- a/error.c +++ b/error.c @@ -1533,7 +1533,7 @@ exc_initialize(int argc, VALUE *argv, VALUE exc) * * x0 = StandardError.new('Boom') # => # * x1 = x0.exception # => # - * x0.__id__ == x1.__id__ # => true + * x0.equal?(x1) # => true * * With {string-convertible object}[rdoc-ref:implicit_conversion.rdoc@String-Convertible+Objects] * +message+ (even the same as the original message), @@ -1541,7 +1541,7 @@ exc_initialize(int argc, VALUE *argv, VALUE exc) * and whose message is the given +message+: * * x1 = x0.exception('Boom') # => # - * x0..equal?(x1) # => false + * x0.equal?(x1) # => false * */ diff --git a/lib/prism/lex_compat.rb b/lib/prism/lex_compat.rb index e1b04fc6cea1e7..7aacec037da5e0 100644 --- a/lib/prism/lex_compat.rb +++ b/lib/prism/lex_compat.rb @@ -23,6 +23,12 @@ module Prism # def self.[]: (Integer value) -> State # end # end + # + # class LineAndColumnCache + # def initialize: (Source source) -> void + # + # def line_and_column: (Integer byte_offset) -> [Integer, Integer] + # end # end # end @@ -837,6 +843,8 @@ def post_process_tokens(tokens, source, data_loc, bom, eof_token) prev_token_state = Translation::Ripper::Lexer::State[Translation::Ripper::EXPR_BEG] prev_token_end = bom ? 3 : 0 + cache = Translation::Ripper::LineAndColumnCache.new(source) + tokens.each do |token| # Skip missing heredoc ends. next if token[1] == :on_heredoc_end && token[2] == "" @@ -851,8 +859,7 @@ def post_process_tokens(tokens, source, data_loc, bom, eof_token) if start_offset > prev_token_end sp_value = source.slice(prev_token_end, start_offset - prev_token_end) - sp_line = source.line(prev_token_end) - sp_column = source.column(prev_token_end) + sp_line, sp_column = cache.line_and_column(prev_token_end) # Ripper reports columns on line 1 without counting the BOM sp_column -= 3 if sp_line == 1 && bom continuation_index = sp_value.byteindex("\\") diff --git a/lib/prism/parse_result.rb b/lib/prism/parse_result.rb index 7cf6630f4453ca..93d3c006b72b65 100644 --- a/lib/prism/parse_result.rb +++ b/lib/prism/parse_result.rb @@ -225,9 +225,7 @@ def deep_freeze freeze end - private - - # Binary search through the offsets to find the line number for the given + # Binary search through the offsets to find the index for the given # byte offset. #-- #: (Integer byte_offset) -> Integer diff --git a/lib/prism/translation/ripper.rb b/lib/prism/translation/ripper.rb index 77ee2c337d9517..0d79b244a6322b 100644 --- a/lib/prism/translation/ripper.rb +++ b/lib/prism/translation/ripper.rb @@ -346,7 +346,7 @@ def self.coerce_source(source) # :nodoc: "__ENCODING__", "__FILE__", "__LINE__" - ] + ].to_set # A list of all of the Ruby binary operators. BINARY_OPERATORS = [ @@ -371,7 +371,7 @@ def self.coerce_source(source) # :nodoc: :/, :*, :** - ] + ].to_set private_constant :KEYWORDS, :BINARY_OPERATORS @@ -445,6 +445,64 @@ def self.sexp_raw(src, filename = "-", lineno = 1, raise_errors: false) autoload :SexpBuilder, "prism/translation/ripper/sexp" autoload :SexpBuilderPP, "prism/translation/ripper/sexp" + # Provides optimized access to line and column information. + # Ripper bounds are mostly accessed in a linear fashion, so + # we can try a linear scan first and fall back to binary search. + class LineAndColumnCache # :nodoc: + # How many should it look ahead/behind before falling back to binary searching. + WINDOW = 8 + private_constant :WINDOW + + #: (Source source) -> void + def initialize(source) + @source = source + @offsets = source.offsets + @hint = 0 + end + + #: (Integer byte_offset) -> [Integer, Integer] + def line_and_column(byte_offset) + @hint = new_hint(byte_offset) || @source.find_line(byte_offset) + return [@hint + @source.start_line, byte_offset - @offsets[@hint]] + end + + private + + def new_hint(byte_offset) + if @offsets[@hint] <= byte_offset + # Same line? + if (@hint + 1 >= @offsets.size || @offsets[@hint + 1] > byte_offset) + return @hint + end + + # Scan forwards + limit = [@hint + WINDOW + 1, @offsets.size].min + idx = @hint + 1 + while idx < limit + if @offsets[idx] > byte_offset + return idx - 1 + end + if @offsets[idx] == byte_offset + return idx + end + idx += 1 + end + else + # Scan backwards + limit = @hint > WINDOW ? @hint - WINDOW : 0 + idx = @hint + while idx >= limit + 1 + if @offsets[idx - 1] <= byte_offset + return idx - 1 + end + idx -= 1 + end + end + + nil + end + end + # :stopdoc: # This is not part of the public API but used by some gems. @@ -488,6 +546,7 @@ def initialize(source, filename = "(ripper)", lineno = 1) @lineno = lineno @column = 0 @result = nil + @line_and_column_cache = nil end ########################################################################## @@ -961,7 +1020,7 @@ def visit_begin_node(node) on_stmts_add(on_stmts_new, on_void_stmt) else body = node.statements.body - body.unshift(nil) if void_stmt?(location, node.statements.body[0].location, allow_newline) + body = [nil, *body] if void_stmt?(location, node.statements.body[0].location, allow_newline) bounds(node.statements.location) visit_statements_node_body(body) @@ -978,7 +1037,7 @@ def visit_begin_node(node) [nil] else body = else_clause_node.statements.body - body.unshift(nil) if void_stmt?(else_clause_node.else_keyword_loc, else_clause_node.statements.body[0].location, allow_newline) + body = [nil, *body] if void_stmt?(else_clause_node.else_keyword_loc, else_clause_node.statements.body[0].location, allow_newline) body end @@ -1000,7 +1059,7 @@ def visit_begin_node(node) on_bodystmt(visit_statements_node_body([nil]), nil, nil, nil) when StatementsNode body = [*node.body] - body.unshift(nil) if void_stmt?(location, body[0].location, allow_newline) + body = [nil, *body] if void_stmt?(location, body[0].location, allow_newline) stmts = visit_statements_node_body(body) bounds(node.body.first.location) @@ -1049,7 +1108,7 @@ def visit_block_node(node) braces ? stmts : on_bodystmt(stmts, nil, nil, nil) when StatementsNode stmts = node.body.body - stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false) + stmts = [nil, *stmts] if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false) stmts = visit_statements_node_body(stmts) bounds(node.body.location) @@ -1249,7 +1308,7 @@ def visit_call_node(node) bounds(node.location) on_unary(:!, receiver) end - when *BINARY_OPERATORS + when BINARY_OPERATORS receiver = visit(node.receiver) bounds(node.message_loc) @@ -1976,7 +2035,7 @@ def visit_else_node(node) [nil] else body = node.statements.body - body.unshift(nil) if void_stmt?(node.else_keyword_loc, node.statements.body[0].location, false) + body = [nil, *body] if void_stmt?(node.else_keyword_loc, node.statements.body[0].location, false) body end @@ -2031,7 +2090,7 @@ def visit_ensure_node(node) [nil] else body = node.statements.body - body.unshift(nil) if void_stmt?(node.ensure_keyword_loc, body[0].location, false) + body = [nil, *body] if void_stmt?(node.ensure_keyword_loc, body[0].location, false) body end @@ -2814,7 +2873,7 @@ def visit_lambda_node(node) braces ? stmts : on_bodystmt(stmts, nil, nil, nil) when StatementsNode stmts = node.body.body - stmts.unshift(nil) if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false) + stmts = [nil, *stmts] if void_stmt?(node.parameters&.location || node.opening_loc, node.body.location, false) stmts = visit_statements_node_body(stmts) bounds(node.body.location) @@ -3308,7 +3367,7 @@ def visit_pre_execution_node(node) # The top-level program node. def visit_program_node(node) body = node.statements.body - body << nil if body.empty? + body = [nil] if body.empty? statements = visit_statements_node_body(body) bounds(node.location) @@ -4030,7 +4089,11 @@ def visit_yield_node(node) # Lazily initialize the parse result. def result - @result ||= Prism.parse(source, partial_script: true, version: "current") + @result ||= Prism.parse(source, partial_script: true, version: "current", freeze: true) + end + + def line_and_column_cache + @line_and_column_cache ||= LineAndColumnCache.new(result.source) end ########################################################################## @@ -4051,24 +4114,23 @@ def void_stmt?(left, right, allow_newline) # Visit the string content of a particular node. This method is used to # split into the various token types. def visit_token(token, allow_keywords = true) - case token - when "." + if token == "." on_period(token) - when "`" + elsif token == "`" on_backtick(token) - when *(allow_keywords ? KEYWORDS : []) + elsif allow_keywords && KEYWORDS.include?(token) on_kw(token) - when /^_/ + elsif token.start_with?("_") on_ident(token) - when /^[[:upper:]]\w*$/ + elsif token.match?(/^[[:upper:]]\w*$/) on_const(token) - when /^@@/ + elsif token.start_with?("@@") on_cvar(token) - when /^@/ + elsif token.start_with?("@") on_ivar(token) - when /^\$/ + elsif token.start_with?("$") on_gvar(token) - when /^[[:punct:]]/ + elsif token.match?(/^[[:punct:]]/) on_op(token) else on_ident(token) @@ -4133,12 +4195,8 @@ def visit_write_value(node) # This method is responsible for updating lineno and column information # to reflect the current node. - # - # This method could be drastically improved with some caching on the start - # of every line, but for now it's good enough. def bounds(location) - @lineno = location.start_line - @column = location.start_column + @lineno, @column = line_and_column_cache.line_and_column(location.start_offset) end # :startdoc: diff --git a/shape.h b/shape.h index 1e27c15fd6d574..e41efde797e348 100644 --- a/shape.h +++ b/shape.h @@ -39,9 +39,9 @@ enum shape_id_fl_type { SHAPE_ID_HEAP_INDEX_MASK = ((1 << SHAPE_ID_HEAP_INDEX_BITS) - 1) << SHAPE_ID_HEAP_INDEX_OFFSET, - SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(0), - SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(1), - SHAPE_ID_FL_TOO_COMPLEX = RBIMPL_SHAPE_ID_FL(2), + SHAPE_ID_FL_TOO_COMPLEX = RBIMPL_SHAPE_ID_FL(0), + SHAPE_ID_FL_FROZEN = RBIMPL_SHAPE_ID_FL(1), + SHAPE_ID_FL_HAS_OBJECT_ID = RBIMPL_SHAPE_ID_FL(2), SHAPE_ID_FL_NON_CANONICAL_MASK = SHAPE_ID_FL_FROZEN | SHAPE_ID_FL_HAS_OBJECT_ID, SHAPE_ID_FLAGS_MASK = SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_NON_CANONICAL_MASK | SHAPE_ID_FL_TOO_COMPLEX, @@ -55,10 +55,12 @@ enum shape_id_mask { SHAPE_ID_HAS_IVAR_MASK = SHAPE_ID_FL_TOO_COMPLEX | (SHAPE_ID_OFFSET_MASK - 1), }; -// The interpreter doesn't care about frozen status or slot size when reading ivars. +// The interpreter doesn't care about frozen status, slot size or object id when reading ivars. // So we normalize shape_id by clearing these bits to improve cache hits. // JITs however might care about some of it. #define SHAPE_ID_READ_ONLY_MASK (~(SHAPE_ID_FL_FROZEN | SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID)) +// For write it's the same idea, but here we do care about frozen status. +#define SHAPE_ID_WRITE_MASK (~(SHAPE_ID_HEAP_INDEX_MASK | SHAPE_ID_FL_HAS_OBJECT_ID)) typedef uint32_t redblack_id_t; @@ -207,6 +209,12 @@ shape_id_t rb_shape_rebuild(shape_id_t initial_shape_id, shape_id_t dest_shape_i void rb_shape_copy_fields(VALUE dest, VALUE *dest_buf, shape_id_t dest_shape_id, VALUE *src_buf, shape_id_t src_shape_id); void rb_shape_copy_complex_ivars(VALUE dest, VALUE obj, shape_id_t src_shape_id, st_table *fields_table); +static inline bool +rb_shape_frozen_p(shape_id_t shape_id) +{ + return shape_id & SHAPE_ID_FL_FROZEN; +} + static inline bool rb_shape_too_complex_p(shape_id_t shape_id) { @@ -467,6 +475,14 @@ rb_shape_transition_complex(shape_id_t shape_id) return next_shape_id; } +static inline shape_id_t +rb_shape_transition_offset(shape_id_t shape_id, shape_id_t offset) +{ + offset = RSHAPE_OFFSET(offset); + RUBY_ASSERT(RSHAPE_OFFSET(shape_id) == offset || RSHAPE_DIRECT_CHILD_P(shape_id, offset)); + return RSHAPE_FLAGS(shape_id) | offset; +} + static inline shape_id_t rb_shape_transition_heap(shape_id_t shape_id, size_t heap_index) { diff --git a/vm_insnhelper.c b/vm_insnhelper.c index eeb8888f18c04a..6b51f88aa61d16 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1233,10 +1233,17 @@ vm_get_cvar_base(const rb_cref_t *cref, const rb_control_frame_t *cfp, int top_l return klass; } -ALWAYS_INLINE(static void fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, attr_index_t index, shape_id_t shape_id)); +ALWAYS_INLINE(static void fill_ivar_cache(attr_index_t index, shape_id_t shape_id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, bool is_attr)); static inline void -fill_ivar_cache(const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr, attr_index_t index, shape_id_t shape_id) +fill_ivar_cache(attr_index_t index, shape_id_t shape_id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, bool is_attr) { + RUBY_ASSERT(!rb_shape_too_complex_p(shape_id)); + RUBY_ASSERT(shape_id != INVALID_SHAPE_ID); + + // We only care about the shape offset. + shape_id = RSHAPE_OFFSET(shape_id); + + // Cache population code if (is_attr) { vm_cc_attr_index_set(cc, index, shape_id); } @@ -1367,7 +1374,7 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call // This fills in the cache with the shared cache object. // "ent" is the shared cache object if (cached_id != previous_cached_id) { - fill_ivar_cache(iseq, ic, cc, is_attr, index, cached_id); + fill_ivar_cache(index, cached_id, iseq, ic, cc, is_attr); } if (index == ATTR_INDEX_NOT_SET) { @@ -1410,18 +1417,46 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call } } -static void -populate_cache(attr_index_t index, shape_id_t next_shape_id, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, bool is_attr) +ALWAYS_INLINE(static shape_id_t revalidate_setivar_cache(shape_id_t shape_id, shape_id_t dest_shape_offset, ID id, attr_index_t index)); +static shape_id_t +revalidate_setivar_cache(shape_id_t shape_id, shape_id_t dest_shape_offset, ID id, attr_index_t index) { - RUBY_ASSERT(!rb_shape_too_complex_p(next_shape_id)); + RUBY_ASSERT(shape_id != INVALID_SHAPE_ID); + RUBY_ASSERT(dest_shape_offset == INVALID_SHAPE_ID || dest_shape_offset == RSHAPE_OFFSET(dest_shape_offset)); - // Cache population code - if (is_attr) { - vm_cc_attr_index_set(cc, index, next_shape_id); + shape_id_t dest_shape_id = shape_id; + shape_id_t normalized_shape_id = shape_id & SHAPE_ID_WRITE_MASK; + + if (normalized_shape_id == dest_shape_offset) { + // Perfect hit case, we're reassigning an existing ivar, the shape doesn't change. + // Also since `SHAPE_ID_WRITE_MASK` contains COMPLEX and FROZEN flags, by matching + // `dest_shape_offset` we also checked that the object is neither complex nor frozen. } else { - vm_ic_attr_index_set(iseq, ic, index, next_shape_id); + if (dest_shape_offset == INVALID_SHAPE_ID) { + // The cache is cold. + return INVALID_SHAPE_ID; + } + + // Child hit case, the cache offset is a direct child of the current shape + // and the ivar name matches. + // We additionally need to ensure that the object has sufficient capacity. + if (!(RSHAPE_DIRECT_CHILD_P(shape_id, dest_shape_id) && + RSHAPE_EDGE_NAME(dest_shape_id) == id && + index < RSHAPE_CAPACITY(shape_id))) { + return INVALID_SHAPE_ID; + } + + // We use the cached offset, but combined with the current shape flags. + dest_shape_id = rb_shape_transition_offset(shape_id, dest_shape_offset); } + + // Cache hit case + RUBY_ASSERT(!rb_shape_frozen_p(shape_id)); + RUBY_ASSERT(!rb_shape_too_complex_p(shape_id)); + RUBY_ASSERT(RSHAPE_CAPACITY(shape_id) >= RSHAPE_LEN(dest_shape_offset)); + + return dest_shape_id; } ALWAYS_INLINE(static VALUE vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, const struct rb_callcache *cc, int is_attr)); @@ -1440,7 +1475,7 @@ vm_setivar_slowpath(VALUE obj, ID id, VALUE val, const rb_iseq_t *iseq, IVC ic, shape_id_t next_shape_id = RBASIC_SHAPE_ID(obj); if (!rb_shape_too_complex_p(next_shape_id)) { - populate_cache(index, next_shape_id, id, iseq, ic, cc, is_attr); + fill_ivar_cache(index, next_shape_id, iseq, ic, cc, is_attr); } RB_DEBUG_COUNTER_INC(ivar_set_obj_miss); @@ -1476,20 +1511,8 @@ vm_setivar_class(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_ind } shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj); - - // Cache hit case - if (shape_id == dest_shape_id) { - RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); - } - else if (dest_shape_id != INVALID_SHAPE_ID) { - if (RSHAPE_DIRECT_CHILD_P(shape_id, dest_shape_id) && RSHAPE_EDGE_NAME(dest_shape_id) == id && RSHAPE_CAPACITY(shape_id) == RSHAPE_CAPACITY(dest_shape_id)) { - RUBY_ASSERT(index < RSHAPE_CAPACITY(dest_shape_id)); - } - else { - return Qundef; - } - } - else { + dest_shape_id = revalidate_setivar_cache(shape_id, dest_shape_id, id, index); + if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) { return Qundef; } @@ -1510,20 +1533,8 @@ static VALUE vm_setivar_default(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t index) { shape_id_t shape_id = RBASIC_SHAPE_ID(obj); - - // Cache hit case - if (shape_id == dest_shape_id) { - RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); - } - else if (dest_shape_id != INVALID_SHAPE_ID) { - if (RSHAPE_DIRECT_CHILD_P(shape_id, dest_shape_id) && RSHAPE_EDGE_NAME(dest_shape_id) == id && RSHAPE_CAPACITY(shape_id) == RSHAPE_CAPACITY(dest_shape_id)) { - RUBY_ASSERT(index < RSHAPE_CAPACITY(dest_shape_id)); - } - else { - return Qundef; - } - } - else { + dest_shape_id = revalidate_setivar_cache(shape_id, dest_shape_id, id, index); + if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) { return Qundef; } @@ -1551,32 +1562,15 @@ vm_setivar(VALUE obj, ID id, VALUE val, shape_id_t dest_shape_id, attr_index_t i VM_ASSERT(!rb_ractor_shareable_p(obj) || rb_obj_frozen_p(obj)); shape_id_t shape_id = RBASIC_SHAPE_ID(obj); - RUBY_ASSERT(dest_shape_id == INVALID_SHAPE_ID || !rb_shape_too_complex_p(dest_shape_id)); - - if (LIKELY(shape_id == dest_shape_id)) { - RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); - VM_ASSERT(!rb_ractor_shareable_p(obj)); - } - else if (dest_shape_id != INVALID_SHAPE_ID) { - if (RSHAPE_DIRECT_CHILD_P(shape_id, dest_shape_id) && RSHAPE_EDGE_NAME(dest_shape_id) == id && RSHAPE_CAPACITY(shape_id) == RSHAPE_CAPACITY(dest_shape_id)) { - RUBY_ASSERT(dest_shape_id != INVALID_SHAPE_ID && shape_id != INVALID_SHAPE_ID); - - RBASIC_SET_SHAPE_ID(obj, dest_shape_id); - - RUBY_ASSERT(index < RSHAPE_CAPACITY(dest_shape_id)); - } - else { - break; - } - } - else { + dest_shape_id = revalidate_setivar_cache(shape_id, dest_shape_id, id, index); + if (UNLIKELY(dest_shape_id == INVALID_SHAPE_ID)) { break; } - VALUE *ptr = ROBJECT_FIELDS(obj); - - RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); - RB_OBJ_WRITE(obj, &ptr[index], val); + RB_OBJ_WRITE(obj, &ROBJECT_FIELDS(obj)[index], val); + if (shape_id != dest_shape_id) { + RBASIC_SET_SHAPE_ID(obj, dest_shape_id); + } RB_DEBUG_COUNTER_INC(ivar_set_ic_hit); RB_DEBUG_COUNTER_INC(ivar_set_obj_hit); diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index eccee5852b03f6..52a05155149c51 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -636,7 +636,7 @@ pub const VM_ENV_FLAG_ISOLATED: vm_frame_env_flags = 16; pub type vm_frame_env_flags = u32; pub type attr_index_t = u16; pub type shape_id_t = u32; -pub const SHAPE_ID_HAS_IVAR_MASK: shape_id_mask = 34078718; +pub const SHAPE_ID_HAS_IVAR_MASK: shape_id_mask = 8912894; pub type shape_id_mask = u32; #[repr(C)] pub struct rb_cvar_class_tbl_entry { diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index 0bb4e275128e5b..bd6a4afa25aa6f 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -1485,10 +1485,10 @@ pub type vm_frame_env_flags = u32; pub type attr_index_t = u16; pub type shape_id_t = u32; pub const SHAPE_ID_HEAP_INDEX_MASK: shape_id_fl_type = 7864320; -pub const SHAPE_ID_FL_FROZEN: shape_id_fl_type = 8388608; -pub const SHAPE_ID_FL_HAS_OBJECT_ID: shape_id_fl_type = 16777216; -pub const SHAPE_ID_FL_TOO_COMPLEX: shape_id_fl_type = 33554432; -pub const SHAPE_ID_FL_NON_CANONICAL_MASK: shape_id_fl_type = 25165824; +pub const SHAPE_ID_FL_TOO_COMPLEX: shape_id_fl_type = 8388608; +pub const SHAPE_ID_FL_FROZEN: shape_id_fl_type = 16777216; +pub const SHAPE_ID_FL_HAS_OBJECT_ID: shape_id_fl_type = 33554432; +pub const SHAPE_ID_FL_NON_CANONICAL_MASK: shape_id_fl_type = 50331648; pub const SHAPE_ID_FLAGS_MASK: shape_id_fl_type = 66584576; pub type shape_id_fl_type = u32; pub const CONST_DEPRECATED: rb_const_flag_t = 256;