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;