diff --git a/NEWS.md b/NEWS.md index 9e436dcae1f087..476d5ba88c5884 100644 --- a/NEWS.md +++ b/NEWS.md @@ -182,7 +182,7 @@ The following bundled gems are updated. * minitest 5.25.5 * rake 13.3.0 * test-unit 3.7.0 -* rexml 3.4.1 +* rexml 3.4.2 * net-imap 0.5.9 * net-smtp 0.5.1 * matrix 0.4.3 diff --git a/gems/bundled_gems b/gems/bundled_gems index 77ace93114a17c..01b56931bfe257 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -10,7 +10,7 @@ minitest 5.25.5 https://github.com/minitest/minitest power_assert 2.0.5 https://github.com/ruby/power_assert f88e406e7c9e0810cc149869582afbae1fb84c4a rake 13.3.0 https://github.com/ruby/rake test-unit 3.7.0 https://github.com/test-unit/test-unit -rexml 3.4.1 https://github.com/ruby/rexml +rexml 3.4.2 https://github.com/ruby/rexml rss 0.3.1 https://github.com/ruby/rss net-ftp 0.3.8 https://github.com/ruby/net-ftp net-imap 0.5.9 https://github.com/ruby/net-imap diff --git a/imemo.c b/imemo.c index 2fde22a3db865b..b4ca1fdcede0ac 100644 --- a/imemo.c +++ b/imemo.c @@ -116,11 +116,11 @@ imemo_fields_new(VALUE owner, size_t capa) if (rb_gc_size_allocatable_p(embedded_size)) { VALUE fields = rb_imemo_new(imemo_fields, owner, embedded_size); RUBY_ASSERT(IMEMO_TYPE_P(fields, imemo_fields)); + FL_SET_RAW(fields, OBJ_FIELD_EMBED); return fields; } else { VALUE fields = rb_imemo_new(imemo_fields, owner, sizeof(struct rb_fields)); - FL_SET_RAW(fields, OBJ_FIELD_EXTERNAL); IMEMO_OBJ_FIELDS(fields)->as.external.ptr = ALLOC_N(VALUE, capa); return fields; } @@ -135,8 +135,9 @@ rb_imemo_fields_new(VALUE owner, size_t capa) static VALUE imemo_fields_new_complex(VALUE owner, size_t capa) { - VALUE fields = imemo_fields_new(owner, sizeof(struct rb_fields)); + VALUE fields = imemo_fields_new(owner, 1); IMEMO_OBJ_FIELDS(fields)->as.complex.table = st_init_numtable_with_size(capa); + FL_UNSET_RAW(fields, OBJ_FIELD_EMBED); return fields; } @@ -165,6 +166,7 @@ VALUE rb_imemo_fields_new_complex_tbl(VALUE owner, st_table *tbl) { VALUE fields = imemo_fields_new(owner, sizeof(struct rb_fields)); + FL_UNSET_RAW(fields, OBJ_FIELD_EMBED); IMEMO_OBJ_FIELDS(fields)->as.complex.table = tbl; st_foreach(tbl, imemo_fields_trigger_wb_i, (st_data_t)fields); return fields; @@ -258,7 +260,7 @@ rb_imemo_memsize(VALUE obj) if (rb_shape_obj_too_complex_p(obj)) { size += st_memsize(IMEMO_OBJ_FIELDS(obj)->as.complex.table); } - else if (FL_TEST_RAW(obj, OBJ_FIELD_EXTERNAL)) { + else if (!FL_TEST_RAW(obj, OBJ_FIELD_EMBED)) { size += RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj)) * sizeof(VALUE); } break; @@ -536,7 +538,7 @@ imemo_fields_free(struct rb_fields *fields) if (rb_shape_obj_too_complex_p((VALUE)fields)) { st_free_table(fields->as.complex.table); } - else if (FL_TEST_RAW((VALUE)fields, OBJ_FIELD_EXTERNAL)) { + else if (!FL_TEST_RAW((VALUE)fields, OBJ_FIELD_EMBED)) { xfree(fields->as.external.ptr); } } diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h index d84e318a2cfe80..fc5b28fd67dc7c 100644 --- a/include/ruby/internal/core/robject.h +++ b/include/ruby/internal/core/robject.h @@ -71,7 +71,7 @@ enum ruby_robject_flags { * 3rd parties must not be aware that there even is more than one way to * store instance variables. Might better be hidden. */ - ROBJECT_EMBED = RUBY_FL_USER1 + ROBJECT_EMBED = RUBY_FL_USER4 }; struct st_table; diff --git a/internal/imemo.h b/internal/imemo.h index 8d1e42353d7b07..c5afcefc974bfb 100644 --- a/internal/imemo.h +++ b/internal/imemo.h @@ -270,7 +270,14 @@ struct rb_fields { } as; }; -#define OBJ_FIELD_EXTERNAL IMEMO_FL_USER0 +// IMEMO/fields and T_OBJECT have exactly the same layout. +// This is useful for JIT and common codepaths. +#define OBJ_FIELD_EMBED ROBJECT_EMBED +STATIC_ASSERT(imemo_fields_flags, OBJ_FIELD_EMBED == IMEMO_FL_USER0); +STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.ary) == offsetof(struct rb_fields, as.embed.fields)); +STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.external.ptr)); +STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.heap.fields) == offsetof(struct rb_fields, as.complex.table)); + #define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields) VALUE rb_imemo_fields_new(VALUE owner, size_t capa); @@ -282,36 +289,43 @@ void rb_imemo_fields_clear(VALUE fields_obj); static inline VALUE rb_imemo_fields_owner(VALUE fields_obj) { + RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields)); + return CLASS_OF(fields_obj); } static inline VALUE * -rb_imemo_fields_ptr(VALUE obj_fields) +rb_imemo_fields_ptr(VALUE fields_obj) { - if (!obj_fields) { + if (!fields_obj) { return NULL; } - RUBY_ASSERT(IMEMO_TYPE_P(obj_fields, imemo_fields)); + RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT)); - if (RB_UNLIKELY(FL_TEST_RAW(obj_fields, OBJ_FIELD_EXTERNAL))) { - return IMEMO_OBJ_FIELDS(obj_fields)->as.external.ptr; + if (RB_LIKELY(FL_TEST_RAW(fields_obj, OBJ_FIELD_EMBED))) { + return IMEMO_OBJ_FIELDS(fields_obj)->as.embed.fields; } else { - return IMEMO_OBJ_FIELDS(obj_fields)->as.embed.fields; + return IMEMO_OBJ_FIELDS(fields_obj)->as.external.ptr; } } static inline st_table * -rb_imemo_fields_complex_tbl(VALUE obj_fields) +rb_imemo_fields_complex_tbl(VALUE fields_obj) { - if (!obj_fields) { + if (!fields_obj) { return NULL; } - RUBY_ASSERT(IMEMO_TYPE_P(obj_fields, imemo_fields)); + RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields) || RB_TYPE_P(fields_obj, T_OBJECT)); + RUBY_ASSERT(!FL_TEST_RAW(fields_obj, OBJ_FIELD_EMBED)); + + // Some codepaths unconditionally access the fields_ptr, and assume it can be used as st_table if the + // shape is too_complex. + RUBY_ASSERT((st_table *)rb_imemo_fields_ptr(fields_obj) == IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table); - return IMEMO_OBJ_FIELDS(obj_fields)->as.complex.table; + return IMEMO_OBJ_FIELDS(fields_obj)->as.complex.table; } #endif /* INTERNAL_IMEMO_H */ diff --git a/object.c b/object.c index 1ae6b8a165416c..cbe3a5269d0ae9 100644 --- a/object.c +++ b/object.c @@ -46,7 +46,7 @@ /* Flags of RObject * - * 1: ROBJECT_EMBED + * 4: ROBJECT_EMBED * The object has its instance variables embedded (the array of * instance variables directly follow the object, rather than being * on a separately allocated buffer). diff --git a/pathname.c b/pathname.c index d1111335c5c4d4..71c78d89e764fc 100644 --- a/pathname.c +++ b/pathname.c @@ -3,7 +3,6 @@ static VALUE rb_cPathname; static ID id_at_path; static ID id_sub; -static ID id_realdirpath; static VALUE get_strpath(VALUE obj) @@ -84,22 +83,6 @@ path_sub(int argc, VALUE *argv, VALUE self) return rb_class_new_instance(1, &str, rb_obj_class(self)); } -/* - * Returns the real (absolute) pathname of +self+ in the actual filesystem. - * - * Does not contain symlinks or useless dots, +..+ and +.+. - * - * The last component of the real pathname can be nonexistent. - */ -static VALUE -path_realdirpath(int argc, VALUE *argv, VALUE self) -{ - VALUE basedir, str; - rb_scan_args(argc, argv, "01", &basedir); - str = rb_funcall(rb_cFile, id_realdirpath, 2, get_strpath(self), basedir); - return rb_class_new_instance(1, &str, rb_obj_class(self)); -} - #include "pathname_builtin.rbinc" static void init_ids(void); @@ -121,7 +104,6 @@ InitVM_pathname(void) rb_cPathname = rb_define_class("Pathname", rb_cObject); rb_define_method(rb_cPathname, "<=>", path_cmp, 1); rb_define_method(rb_cPathname, "sub", path_sub, -1); - rb_define_method(rb_cPathname, "realdirpath", path_realdirpath, -1); rb_provide("pathname.so"); } @@ -132,5 +114,4 @@ init_ids(void) #undef rb_intern id_at_path = rb_intern("@path"); id_sub = rb_intern("sub"); - id_realdirpath = rb_intern("realdirpath"); } diff --git a/pathname_builtin.rb b/pathname_builtin.rb index 81ca6b02615aac..081b82ba9a6a51 100644 --- a/pathname_builtin.rb +++ b/pathname_builtin.rb @@ -130,6 +130,7 @@ # - #read(*args) # - #binread(*args) # - #readlines(*args) +# - #sysopen(*args) # - #write(*args) # - #binwrite(*args) # - #atime @@ -170,11 +171,6 @@ # - #mkdir(*args) # - #opendir(*args) # -# === IO -# -# This method is a facade for IO: -# - #sysopen(*args) -# # === Utilities # # These methods are a mixture of Find, FileUtils, and others: @@ -219,9 +215,10 @@ class Pathname # If +path+ contains a NUL character (\0), an ArgumentError is raised. # def initialize(path) - path = path.to_path if path.respond_to? :to_path - - raise TypeError unless path.is_a?(String) # Compatibility for C version + unless String === path + path = path.to_path if path.respond_to? :to_path + raise TypeError unless String === path + end if path.include?("\0") raise ArgumentError, "pathname contains \\0: #{path.inspect}" @@ -864,11 +861,6 @@ def relative_path_from(base_directory) end end -class Pathname # * IO * - # See IO.sysopen. - def sysopen(...) IO.sysopen(@path, ...) end -end - class Pathname # * File * # # #each_line iterates over the line in the file. It yields a String object @@ -891,6 +883,9 @@ def binread(...) File.binread(@path, ...) end # See File.readlines. Returns all the lines from the file. def readlines(...) File.readlines(@path, ...) end + # See File.sysopen. + def sysopen(...) File.sysopen(@path, ...) end + # Writes +contents+ to the file. See File.write. def write(...) File.write(@path, ...) end @@ -966,6 +961,13 @@ def truncate(length) File.truncate(@path, length) end # See File.utime. Update the access and modification times. def utime(atime, mtime) File.utime(atime, mtime, @path) end + # Update the access and modification times of the file. + # + # Same as Pathname#utime, but does not follow symbolic links. + # + # See File.lutime. + def lutime(atime, mtime) File.lutime(atime, mtime, @path) end + # See File.basename. Returns the last component of the path. def basename(...) self.class.new(File.basename(@path, ...)) end @@ -992,6 +994,13 @@ def split() # # All components of the pathname must exist when this method is called. def realpath(...) self.class.new(File.realpath(@path, ...)) end + + # Returns the real (absolute) pathname of +self+ in the actual filesystem. + # + # Does not contain symlinks or useless dots, +..+ and +.+. + # + # The last component of the real pathname can be nonexistent. + def realdirpath(...) self.class.new(File.realdirpath(@path, ...)) end end @@ -1158,12 +1167,8 @@ module Kernel # # This method is available since 1.8.5. def Pathname(path) # :doc: - Kernel.Pathname(path) - end - private :Pathname - - def self.Pathname(path) # Compatibility for C version return path if Pathname === path Pathname.new(path) end + module_function :Pathname end diff --git a/shape.c b/shape.c index 4345654f840876..05aea7905ce021 100644 --- a/shape.c +++ b/shape.c @@ -1270,6 +1270,11 @@ rb_shape_verify_consistency(VALUE obj, shape_id_t shape_id) // Make sure SHAPE_ID_HAS_IVAR_MASK is valid. if (rb_shape_too_complex_p(shape_id)) { RUBY_ASSERT(shape_id & SHAPE_ID_HAS_IVAR_MASK); + + // Ensure complex object don't appear as embedded + if (RB_TYPE_P(obj, T_OBJECT) || IMEMO_TYPE_P(obj, imemo_fields)) { + RUBY_ASSERT(!FL_TEST_RAW(obj, ROBJECT_EMBED)); + } } else { attr_index_t ivar_count = RSHAPE_LEN(shape_id); diff --git a/shape.h b/shape.h index 065d3759074117..3541b7baf4e0f2 100644 --- a/shape.h +++ b/shape.h @@ -351,6 +351,8 @@ ROBJECT_FIELDS_HASH(VALUE obj) { RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); + RUBY_ASSERT(!FL_TEST_RAW(obj, ROBJECT_EMBED)); + return (st_table *)ROBJECT(obj)->as.heap.fields; } @@ -359,6 +361,8 @@ ROBJECT_SET_FIELDS_HASH(VALUE obj, const st_table *tbl) { RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); RUBY_ASSERT(rb_shape_obj_too_complex_p(obj)); + RUBY_ASSERT(!FL_TEST_RAW(obj, ROBJECT_EMBED)); + ROBJECT(obj)->as.heap.fields = (VALUE *)tbl; } diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb index 7e0011c664bf8a..e80473e5a3eea0 100644 --- a/test/pathname/test_pathname.rb +++ b/test/pathname/test_pathname.rb @@ -348,7 +348,7 @@ def has_symlink? rescue NotImplementedError return false rescue Errno::ENOENT - return false + return true rescue Errno::EACCES return false end @@ -370,10 +370,11 @@ def has_hardlink? end def realpath(path, basedir=nil) - Pathname.new(path).realpath(basedir).to_s + Pathname.new(path).realpath(*basedir).to_s end def test_realpath + omit "not working yet" if RUBY_ENGINE == "jruby" return if !has_symlink? with_tmpchdir('rubytest-pathname') {|dir| assert_raise(Errno::ENOENT) { realpath("#{dir}/not-exist") } @@ -434,6 +435,7 @@ def realdirpath(path) end def test_realdirpath + omit "not working yet" if RUBY_ENGINE == "jruby" return if !has_symlink? Dir.mktmpdir('rubytest-pathname') {|dir| rdir = realpath(dir) @@ -1054,7 +1056,11 @@ def test_lutime latime = Time.utc(2000) lmtime = Time.utc(1999) File.symlink("a", "l") - Pathname("l").utime(latime, lmtime) + begin + Pathname("l").lutime(latime, lmtime) + rescue NotImplementedError + next + end s = File.lstat("a") ls = File.lstat("l") assert_equal(atime, s.atime) diff --git a/variable.c b/variable.c index 6d172defdd5d06..e38af116ec679f 100644 --- a/variable.c +++ b/variable.c @@ -1362,47 +1362,35 @@ rb_obj_field_get(VALUE obj, shape_id_t target_shape_id) RUBY_ASSERT(!SPECIAL_CONST_P(obj)); RUBY_ASSERT(RSHAPE_TYPE_P(target_shape_id, SHAPE_IVAR) || RSHAPE_TYPE_P(target_shape_id, SHAPE_OBJ_ID)); - if (rb_shape_too_complex_p(target_shape_id)) { - st_table *fields_hash; - switch (BUILTIN_TYPE(obj)) { - case T_CLASS: - case T_MODULE: - fields_hash = rb_imemo_fields_complex_tbl(RCLASS_WRITABLE_FIELDS_OBJ(obj)); - break; - case T_OBJECT: - fields_hash = ROBJECT_FIELDS_HASH(obj); - break; - case T_IMEMO: - fields_hash = rb_imemo_fields_complex_tbl(obj); - break; - default: - fields_hash = rb_imemo_fields_complex_tbl(rb_obj_fields(obj, RSHAPE_EDGE_NAME(target_shape_id))); - break; - } - VALUE value = Qundef; - st_lookup(fields_hash, RSHAPE_EDGE_NAME(target_shape_id), &value); - RUBY_ASSERT(!UNDEF_P(value)); - return value; - } + VALUE fields_obj; - attr_index_t attr_index = RSHAPE_INDEX(target_shape_id); - VALUE *fields; switch (BUILTIN_TYPE(obj)) { case T_CLASS: case T_MODULE: - fields = rb_imemo_fields_ptr(RCLASS_WRITABLE_FIELDS_OBJ(obj)); + fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj); break; case T_OBJECT: - fields = ROBJECT_FIELDS(obj); + fields_obj = obj; break; case T_IMEMO: - fields = rb_imemo_fields_ptr(obj); + RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields)); + fields_obj = obj; break; default: - fields = rb_imemo_fields_ptr(rb_obj_fields(obj, RSHAPE_EDGE_NAME(target_shape_id))); + fields_obj = rb_obj_fields(obj, RSHAPE_EDGE_NAME(target_shape_id)); break; } - return fields[attr_index]; + + if (UNLIKELY(rb_shape_too_complex_p(target_shape_id))) { + st_table *fields_hash = rb_imemo_fields_complex_tbl(fields_obj); + VALUE value = Qundef; + st_lookup(fields_hash, RSHAPE_EDGE_NAME(target_shape_id), &value); + RUBY_ASSERT(!UNDEF_P(value)); + return value; + } + + attr_index_t index = RSHAPE_INDEX(target_shape_id); + return rb_imemo_fields_ptr(fields_obj)[index]; } VALUE @@ -1410,19 +1398,13 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef) { if (SPECIAL_CONST_P(obj)) return undef; - shape_id_t shape_id; - VALUE *ivar_list; + VALUE fields_obj; switch (BUILTIN_TYPE(obj)) { case T_CLASS: case T_MODULE: { - VALUE val = undef; - VALUE fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj); - if (fields_obj) { - val = rb_ivar_lookup(fields_obj, id, undef); - } - + VALUE val = rb_ivar_lookup(RCLASS_WRITABLE_FIELDS_OBJ(obj), id, undef); if (val != undef && rb_is_instance_id(id) && UNLIKELY(!rb_ractor_main_p()) && @@ -1434,69 +1416,35 @@ rb_ivar_lookup(VALUE obj, ID id, VALUE undef) } case T_IMEMO: // Handled like T_OBJECT - { - RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields)); - shape_id = RBASIC_SHAPE_ID(obj); + RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_fields)); + fields_obj = obj; + break; + case T_OBJECT: + fields_obj = obj; + break; + default: + fields_obj = rb_obj_fields(obj, id); + break; + } - if (rb_shape_too_complex_p(shape_id)) { - st_table *iv_table = rb_imemo_fields_complex_tbl(obj); - VALUE val; - if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) { - return val; - } - else { - return undef; - } - } + if (!fields_obj) { + return undef; + } - RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); - ivar_list = rb_imemo_fields_ptr(obj); - break; - } - case T_OBJECT: - { - shape_id = RBASIC_SHAPE_ID(obj); - if (rb_shape_too_complex_p(shape_id)) { - st_table *iv_table = ROBJECT_FIELDS_HASH(obj); - VALUE val; - if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) { - return val; - } - else { - return undef; - } - } + shape_id_t shape_id = RBASIC_SHAPE_ID(fields_obj); - RUBY_ASSERT(!rb_shape_obj_too_complex_p(obj)); - ivar_list = ROBJECT_FIELDS(obj); - break; - } - default: - { - shape_id = RBASIC_SHAPE_ID(obj); - VALUE fields_obj = rb_obj_fields(obj, id); - if (fields_obj) { - if (rb_shape_obj_too_complex_p(fields_obj)) { - VALUE val; - if (rb_st_lookup(rb_imemo_fields_complex_tbl(fields_obj), (st_data_t)id, (st_data_t *)&val)) { - return val; - } - else { - return undef; - } - } - ivar_list = rb_imemo_fields_ptr(fields_obj); - } - else { - return undef; - } - break; + if (UNLIKELY(rb_shape_too_complex_p(shape_id))) { + st_table *iv_table = rb_imemo_fields_complex_tbl(fields_obj); + VALUE val; + if (rb_st_lookup(iv_table, (st_data_t)id, (st_data_t *)&val)) { + return val; } + return undef; } attr_index_t index = 0; if (rb_shape_get_iv_index(shape_id, id, &index)) { - return ivar_list[index]; + return rb_imemo_fields_ptr(fields_obj)[index]; } return undef; @@ -1532,7 +1480,10 @@ obj_transition_too_complex(VALUE obj, st_table *table) case T_OBJECT: { VALUE *old_fields = NULL; - if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) { + if (FL_TEST_RAW(obj, ROBJECT_EMBED)) { + FL_UNSET_RAW(obj, ROBJECT_EMBED); + } + else { old_fields = ROBJECT_FIELDS(obj); } RBASIC_SET_SHAPE_ID(obj, shape_id); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index e186c57745df07..9196d16e02d77d 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1223,19 +1223,13 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call { VALUE fields_obj; #if OPT_IC_FOR_IVAR - VALUE val = Qundef; - VALUE *ivar_list; - if (SPECIAL_CONST_P(obj)) { return default_value; } - shape_id_t shape_id = RBASIC_SHAPE_ID_FOR_READ(obj); - switch (BUILTIN_TYPE(obj)) { case T_OBJECT: - ivar_list = ROBJECT_FIELDS(obj); - VM_ASSERT(rb_ractor_shareable_p(obj) ? rb_ractor_shareable_p(val) : true); + fields_obj = obj; break; case T_CLASS: case T_MODULE: @@ -1257,27 +1251,21 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call } fields_obj = RCLASS_WRITABLE_FIELDS_OBJ(obj); - if (!fields_obj) { - return default_value; - } - ivar_list = rb_imemo_fields_ptr(fields_obj); - shape_id = RBASIC_SHAPE_ID_FOR_READ(fields_obj); - break; } default: - if (rb_obj_exivar_p(obj)) { - VALUE fields_obj = rb_obj_fields(obj, id); - if (!fields_obj) { - return default_value; - } - ivar_list = rb_imemo_fields_ptr(fields_obj); - } - else { - return default_value; - } + fields_obj = rb_obj_fields(obj, id); + } + + if (!fields_obj) { + return default_value; } + VALUE val = Qundef; + + shape_id_t shape_id = RBASIC_SHAPE_ID_FOR_READ(fields_obj); + VALUE *ivar_list = rb_imemo_fields_ptr(fields_obj); + shape_id_t cached_id; attr_index_t index; @@ -1330,26 +1318,13 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call } #endif - if (rb_shape_too_complex_p(shape_id)) { - st_table *table = NULL; - switch (BUILTIN_TYPE(obj)) { - case T_CLASS: - case T_MODULE: - table = rb_imemo_fields_complex_tbl(fields_obj); - break; + if (UNLIKELY(rb_shape_too_complex_p(shape_id))) { + st_table *table = (st_table *)ivar_list; - case T_OBJECT: - table = ROBJECT_FIELDS_HASH(obj); - break; + RUBY_ASSERT(table); + RUBY_ASSERT(table == rb_imemo_fields_complex_tbl(fields_obj)); - default: { - VALUE fields_obj = rb_obj_fields(obj, id); - table = rb_imemo_fields_complex_tbl(fields_obj); - break; - } - } - - if (!table || !st_lookup(table, id, &val)) { + if (!st_lookup(table, id, &val)) { val = default_value; } } @@ -1382,14 +1357,12 @@ vm_getivar(VALUE obj, ID id, const rb_iseq_t *iseq, IVC ic, const struct rb_call val = default_value; } } - } if (!UNDEF_P(default_value)) { RUBY_ASSERT(!UNDEF_P(val)); } - RB_GC_GUARD(fields_obj); return val; general_path: diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index c8a58f424e385f..e3ec97416d186c 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -306,7 +306,7 @@ pub const RARRAY_EMBED_LEN_SHIFT: ruby_rarray_consts = 15; pub type ruby_rarray_consts = u32; pub const RMODULE_IS_REFINEMENT: ruby_rmodule_flags = 8192; pub type ruby_rmodule_flags = u32; -pub const ROBJECT_EMBED: ruby_robject_flags = 8192; +pub const ROBJECT_EMBED: ruby_robject_flags = 65536; pub type ruby_robject_flags = u32; pub type rb_block_call_func = ::std::option::Option< unsafe extern "C" fn( diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs index ee6d4d5e0e2938..406f22ece6d560 100644 --- a/zjit/src/cruby_bindings.inc.rs +++ b/zjit/src/cruby_bindings.inc.rs @@ -160,7 +160,7 @@ pub const RARRAY_EMBED_LEN_SHIFT: ruby_rarray_consts = 15; pub type ruby_rarray_consts = u32; pub const RMODULE_IS_REFINEMENT: ruby_rmodule_flags = 8192; pub type ruby_rmodule_flags = u32; -pub const ROBJECT_EMBED: ruby_robject_flags = 8192; +pub const ROBJECT_EMBED: ruby_robject_flags = 65536; pub type ruby_robject_flags = u32; pub const RUBY_ENCODING_INLINE_MAX: ruby_encoding_consts = 127; pub const RUBY_ENCODING_SHIFT: ruby_encoding_consts = 22;