summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/windows.yml2
-rw-r--r--NEWS.md20
-rw-r--r--common.mk15
-rw-r--r--defs/gmake.mk2
-rw-r--r--file.c2
-rw-r--r--gc.c43
-rw-r--r--gc/default/default.c66
-rw-r--r--gc/gc.h19
-rw-r--r--gc/mmtk/mmtk.c18
-rw-r--r--object.c56
-rw-r--r--prism/templates/lib/prism/visitor.rb.erb2
-rw-r--r--ractor.c7
-rw-r--r--set.c1
-rw-r--r--spec/ruby/core/kernel/inspect_spec.rb30
-rw-r--r--test/ruby/test_object.rb13
-rw-r--r--test/ruby/test_set.rb6
-rw-r--r--test/ruby/test_zjit.rb42
-rwxr-xr-xtool/fetch-bundled_gems.rb14
-rw-r--r--variable.c33
-rw-r--r--variable.h1
-rw-r--r--zjit/src/hir.rs88
21 files changed, 350 insertions, 130 deletions
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 6c8f09660d..fa3d2f659e 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -71,7 +71,7 @@ jobs:
bundler: none
windows-toolchain: none
- - name: Install libraries with scoop
+ - name: Install tools with scoop
run: |
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
iwr -useb get.scoop.sh | iex
diff --git a/NEWS.md b/NEWS.md
index 7fdc195653..6c901003ba 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -14,6 +14,26 @@ Note that each entry is kept to a minimum, see links for details.
Note: We're only listing outstanding class updates.
+* Kernel
+
+ * `Kernel#inspect` now check for the existence of a `#instance_variables_to_inspect` method
+ allowing to control which instance variables are displayed in the `#inspect` string:
+
+ ```ruby
+ class DatabaseConfig
+ def initialize(host, user, password)
+ @host = host
+ @user = user
+ @password = password
+ end
+
+ private def instance_variables_to_inspect = [:@host, :@user]
+ end
+
+ conf = DatabaseConfig.new("localhost", "root", "hunter2")
+ conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root">
+ ```
+
* Binding
* `Binding#local_variables` does no longer include numbered parameters.
diff --git a/common.mk b/common.mk
index d76223e072..34287c5782 100644
--- a/common.mk
+++ b/common.mk
@@ -1562,18 +1562,6 @@ extract-gems$(sequential): PHONY
extract-gems$(sequential): $(HAVE_GIT:yes=clone-bundled-gems-src)
-clone-bundled-gems-src: PHONY
- $(Q) $(BASERUBY) -C "$(srcdir)" \
- -Itool/lib -rbundled_gem -answ \
- -e 'BEGIN {git = $$git}' \
- -e 'gem, _, repo, rev = *$$F' \
- -e 'next if !rev or /^#/=~gem' \
- -e 'gemdir = "gems/src/#{gem}"' \
- -e 'BundledGem.checkout(gemdir, repo, rev, git: git)' \
- -e 'BundledGem.dummy_gemspec("#{gemdir}/#{gem}.gemspec")' \
- -- -git="$(GIT)" \
- gems/bundled_gems
-
outdate-bundled-gems: PHONY
$(Q) $(BASERUBY) $(tooldir)/[email protected] --make="$(MAKE)" --mflags="$(MFLAGS)" \
--ruby-platform=$(arch) --ruby-version=$(ruby_version) \
@@ -1623,7 +1611,8 @@ yes-install-for-test-bundled-gems: yes-update-default-gemspecs
"sinatra" "rack" "tilt" "mustermann" "base64" "compact_index" "rack-test" "logger" "kpeg" "tracer"
test-bundled-gems-fetch: yes-test-bundled-gems-fetch
-yes-test-bundled-gems-fetch:
+yes-test-bundled-gems-fetch: clone-bundled-gems-src
+clone-bundled-gems-src: PHONY
$(Q) $(BASERUBY) -C $(srcdir)/gems ../tool/fetch-bundled_gems.rb BUNDLED_GEMS="$(BUNDLED_GEMS)" src bundled_gems
no-test-bundled-gems-fetch:
diff --git a/defs/gmake.mk b/defs/gmake.mk
index 87fc8021b2..a81d82eadd 100644
--- a/defs/gmake.mk
+++ b/defs/gmake.mk
@@ -365,7 +365,7 @@ $(srcdir)/.bundle/.timestamp:
define build-gem
$(srcdir)/gems/src/$(1)/.git: | $(srcdir)/gems/src
$(ECHO) Cloning $(4)
- $(Q) $(GIT) clone $(4) $$(@D)
+ $(Q) $(GIT) clone --depth=1 --no-tags $(4) $$(@D)
$(bundled-gem-revision): \
$(if $(if $(wildcard $$(@)),$(filter $(3),$(shell cat $$(@)))),,PHONY) \
diff --git a/file.c b/file.c
index b38cd67199..322df6dbec 100644
--- a/file.c
+++ b/file.c
@@ -543,7 +543,7 @@ rb_stat_new(const struct stat *st)
if (st) {
#if RUBY_USE_STATX
# define CP(m) .stx_ ## m = st->st_ ## m
-# define CP_32(m) .stx_ ## m = (__u32)st->st_ ## m
+# define CP_32(m) .stx_ ## m = (uint32_t)st->st_ ## m
# define CP_TS(m) .stx_ ## m = stat_ ## m ## spec(st)
rb_st->stat = (struct statx){
.stx_mask = STATX_BASIC_STATS,
diff --git a/gc.c b/gc.c
index 5281e7fb49..05cefc739b 100644
--- a/gc.c
+++ b/gc.c
@@ -131,45 +131,45 @@
#include "shape.h"
unsigned int
-rb_gc_vm_lock(void)
+rb_gc_vm_lock(const char *file, int line)
{
unsigned int lev = 0;
- RB_VM_LOCK_ENTER_LEV(&lev);
+ rb_vm_lock_enter(&lev, file, line);
return lev;
}
void
-rb_gc_vm_unlock(unsigned int lev)
+rb_gc_vm_unlock(unsigned int lev, const char *file, int line)
{
- RB_VM_LOCK_LEAVE_LEV(&lev);
+ rb_vm_lock_leave(&lev, file, line);
}
unsigned int
-rb_gc_cr_lock(void)
+rb_gc_cr_lock(const char *file, int line)
{
unsigned int lev;
- RB_VM_LOCK_ENTER_CR_LEV(GET_RACTOR(), &lev);
+ rb_vm_lock_enter_cr(GET_RACTOR(), &lev, file, line);
return lev;
}
void
-rb_gc_cr_unlock(unsigned int lev)
+rb_gc_cr_unlock(unsigned int lev, const char *file, int line)
{
- RB_VM_LOCK_LEAVE_CR_LEV(GET_RACTOR(), &lev);
+ rb_vm_lock_leave_cr(GET_RACTOR(), &lev, file, line);
}
unsigned int
-rb_gc_vm_lock_no_barrier(void)
+rb_gc_vm_lock_no_barrier(const char *file, int line)
{
unsigned int lev = 0;
- RB_VM_LOCK_ENTER_LEV_NB(&lev);
+ rb_vm_lock_enter_nb(&lev, file, line);
return lev;
}
void
-rb_gc_vm_unlock_no_barrier(unsigned int lev)
+rb_gc_vm_unlock_no_barrier(unsigned int lev, const char *file, int line)
{
- RB_VM_LOCK_LEAVE_LEV_NB(&lev);
+ rb_vm_lock_leave_nb(&lev, file, line);
}
void
@@ -1783,9 +1783,9 @@ generate_next_object_id(void)
// 64bit atomics are available
return SIZET2NUM(RUBY_ATOMIC_SIZE_FETCH_ADD(object_id_counter, 1) * OBJ_ID_INCREMENT);
#else
- unsigned int lock_lev = rb_gc_vm_lock();
+ unsigned int lock_lev = RB_GC_VM_LOCK();
VALUE id = ULL2NUM(++object_id_counter * OBJ_ID_INCREMENT);
- rb_gc_vm_unlock(lock_lev);
+ RB_GC_VM_UNLOCK(lock_lev);
return id;
#endif
}
@@ -1867,7 +1867,7 @@ class_object_id(VALUE klass)
{
VALUE id = RUBY_ATOMIC_VALUE_LOAD(RCLASS(klass)->object_id);
if (!id) {
- unsigned int lock_lev = rb_gc_vm_lock();
+ unsigned int lock_lev = RB_GC_VM_LOCK();
id = generate_next_object_id();
VALUE existing_id = RUBY_ATOMIC_VALUE_CAS(RCLASS(klass)->object_id, 0, id);
if (existing_id) {
@@ -1876,7 +1876,7 @@ class_object_id(VALUE klass)
else if (RB_UNLIKELY(id2ref_tbl)) {
st_insert(id2ref_tbl, id, klass);
}
- rb_gc_vm_unlock(lock_lev);
+ RB_GC_VM_UNLOCK(lock_lev);
}
return id;
}
@@ -1946,9 +1946,9 @@ object_id(VALUE obj)
}
if (UNLIKELY(rb_gc_multi_ractor_p() && rb_ractor_shareable_p(obj))) {
- unsigned int lock_lev = rb_gc_vm_lock();
+ unsigned int lock_lev = RB_GC_VM_LOCK();
VALUE id = object_id0(obj);
- rb_gc_vm_unlock(lock_lev);
+ RB_GC_VM_UNLOCK(lock_lev);
return id;
}
@@ -1983,7 +1983,7 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id)
{
rb_objspace_t *objspace = objspace_ptr;
- unsigned int lev = rb_gc_vm_lock();
+ unsigned int lev = RB_GC_VM_LOCK();
if (!id2ref_tbl) {
rb_gc_vm_barrier(); // stop other ractors
@@ -2007,7 +2007,7 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id)
VALUE obj;
bool found = st_lookup(id2ref_tbl, object_id, &obj) && !rb_gc_impl_garbage_object_p(objspace, obj);
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
if (found) {
return obj;
@@ -4093,7 +4093,8 @@ vm_weak_table_gen_fields_foreach(st_data_t key, st_data_t value, st_data_t data)
);
}
else {
- for (uint32_t i = 0; i < fields_tbl->as.shape.fields_count; i++) {
+ uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID((VALUE)key));
+ for (uint32_t i = 0; i < fields_count; i++) {
if (SPECIAL_CONST_P(fields_tbl->as.shape.fields[i])) continue;
int ivar_ret = iter_data->callback(fields_tbl->as.shape.fields[i], iter_data->data);
diff --git a/gc/default/default.c b/gc/default/default.c
index 5664b3dd90..40d39d6f17 100644
--- a/gc/default/default.c
+++ b/gc/default/default.c
@@ -1229,7 +1229,7 @@ check_rvalue_consistency_force(rb_objspace_t *objspace, const VALUE obj, int ter
{
int err = 0;
- int lev = rb_gc_vm_lock_no_barrier();
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
if (SPECIAL_CONST_P(obj)) {
fprintf(stderr, "check_rvalue_consistency: %p is a special const.\n", (void *)obj);
@@ -1319,7 +1319,7 @@ check_rvalue_consistency_force(rb_objspace_t *objspace, const VALUE obj, int ter
}
}
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
if (err > 0 && terminate) {
rb_bug("check_rvalue_consistency_force: there is %d errors.", err);
@@ -2140,7 +2140,7 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
#if RGENGC_CHECK_MODE
newobj_fill(obj, 0, 0, 0);
- int lev = rb_gc_vm_lock_no_barrier();
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
check_rvalue_consistency(objspace, obj);
@@ -2151,7 +2151,7 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace,
if (RVALUE_REMEMBERED(objspace, obj)) rb_bug("newobj: %s is remembered.", rb_obj_info(obj));
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
#endif
if (RB_UNLIKELY(wb_protected == FALSE)) {
@@ -2363,7 +2363,7 @@ newobj_cache_miss(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size
bool unlock_vm = false;
if (!vm_locked) {
- lev = rb_gc_cr_lock();
+ lev = RB_GC_CR_LOCK();
unlock_vm = true;
}
@@ -2387,7 +2387,7 @@ newobj_cache_miss(rb_objspace_t *objspace, rb_ractor_newobj_cache_t *cache, size
}
if (unlock_vm) {
- rb_gc_cr_unlock(lev);
+ RB_GC_CR_UNLOCK(lev);
}
if (RB_UNLIKELY(obj == Qfalse)) {
@@ -2416,7 +2416,7 @@ newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_new
VALUE obj;
unsigned int lev;
- lev = rb_gc_cr_lock();
+ lev = RB_GC_CR_LOCK();
{
if (RB_UNLIKELY(during_gc || ruby_gc_stressful)) {
if (during_gc) {
@@ -2438,7 +2438,7 @@ newobj_slowpath(VALUE klass, VALUE flags, rb_objspace_t *objspace, rb_ractor_new
obj = newobj_alloc(objspace, cache, heap_idx, true);
newobj_init(klass, flags, wb_protected, objspace, obj);
}
- rb_gc_cr_unlock(lev);
+ RB_GC_CR_UNLOCK(lev);
return obj;
}
@@ -2753,7 +2753,7 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
RBASIC(obj)->flags |= FL_FINALIZE;
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
if (st_lookup(finalizer_table, obj, &data)) {
table = (VALUE)data;
@@ -2766,7 +2766,7 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
for (i = 0; i < len; i++) {
VALUE recv = RARRAY_AREF(table, i);
if (rb_equal(recv, block)) {
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
return recv;
}
}
@@ -2780,7 +2780,7 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
st_add_direct(finalizer_table, obj, table);
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
return block;
}
@@ -2794,9 +2794,9 @@ rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj)
st_data_t data = obj;
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
st_delete(finalizer_table, &data, 0);
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
FL_UNSET(obj, FL_FINALIZE);
}
@@ -2810,7 +2810,7 @@ rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
if (!FL_TEST(obj, FL_FINALIZE)) return;
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
if (RB_LIKELY(st_lookup(finalizer_table, obj, &data))) {
table = rb_ary_dup((VALUE)data);
RARRAY_ASET(table, 0, rb_obj_id(dest));
@@ -2820,7 +2820,7 @@ rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
else {
rb_bug("rb_gc_copy_finalizer: FL_FINALIZE set but not found in finalizer_table: %s", rb_obj_info(obj));
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
}
static VALUE
@@ -2864,7 +2864,7 @@ finalize_list(rb_objspace_t *objspace, VALUE zombie)
next_zombie = RZOMBIE(zombie)->next;
page = GET_HEAP_PAGE(zombie);
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
run_final(objspace, zombie);
{
@@ -2878,7 +2878,7 @@ finalize_list(rb_objspace_t *objspace, VALUE zombie)
heap_page_add_freeobj(objspace, page, zombie);
page->heap->total_freed_objects++;
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
zombie = next_zombie;
}
@@ -3247,7 +3247,7 @@ read_barrier_handler(uintptr_t address)
rb_bug("read_barrier_handler: segmentation fault at %p", (void *)address);
}
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
{
unlock_page_body(objspace, page_body);
@@ -3255,7 +3255,7 @@ read_barrier_handler(uintptr_t address)
invalidate_moved_page(objspace, GET_HEAP_PAGE(address));
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
}
#endif
@@ -5180,7 +5180,7 @@ gc_verify_internal_consistency(void *objspace_ptr)
{
rb_objspace_t *objspace = objspace_ptr;
- unsigned int lev = rb_gc_vm_lock();
+ unsigned int lev = RB_GC_VM_LOCK();
{
rb_gc_vm_barrier(); // stop other ractors
@@ -5191,7 +5191,7 @@ gc_verify_internal_consistency(void *objspace_ptr)
}
during_gc = prev_during_gc;
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
}
static void
@@ -5952,11 +5952,11 @@ gc_writebarrier_generational(VALUE a, VALUE b, rb_objspace_t *objspace)
/* mark `a' and remember (default behavior) */
if (!RVALUE_REMEMBERED(objspace, a)) {
- int lev = rb_gc_vm_lock_no_barrier();
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
rgengc_remember(objspace, a);
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
gc_report(1, objspace, "gc_writebarrier_generational: %s (remembered) -> %s\n", rb_obj_info(a), rb_obj_info(b));
}
@@ -6029,7 +6029,7 @@ rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
else {
bool retry = false;
/* slow path */
- int lev = rb_gc_vm_lock_no_barrier();
+ int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
if (is_incremental_marking(objspace)) {
gc_writebarrier_incremental(a, b, objspace);
@@ -6038,7 +6038,7 @@ rb_gc_impl_writebarrier(void *objspace_ptr, VALUE a, VALUE b)
retry = true;
}
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
if (retry) goto retry;
}
@@ -6057,7 +6057,7 @@ rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj)
gc_report(2, objspace, "rb_gc_writebarrier_unprotect: %s %s\n", rb_obj_info(obj),
RVALUE_REMEMBERED(objspace, obj) ? " (already remembered)" : "");
- unsigned int lev = rb_gc_vm_lock_no_barrier();
+ unsigned int lev = RB_GC_VM_LOCK_NO_BARRIER();
{
if (RVALUE_OLD_P(objspace, obj)) {
gc_report(1, objspace, "rb_gc_writebarrier_unprotect: %s\n", rb_obj_info(obj));
@@ -6079,7 +6079,7 @@ rb_gc_impl_writebarrier_unprotect(void *objspace_ptr, VALUE obj)
RB_DEBUG_COUNTER_INC(obj_wb_unprotect);
MARK_IN_BITMAP(GET_HEAP_WB_UNPROTECTED_BITS(obj), obj);
}
- rb_gc_vm_unlock_no_barrier(lev);
+ RB_GC_VM_UNLOCK_NO_BARRIER(lev);
}
}
@@ -6292,7 +6292,7 @@ garbage_collect(rb_objspace_t *objspace, unsigned int reason)
{
int ret;
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
{
#if GC_PROFILE_MORE_DETAIL
objspace->profile.prepare_time = getrusage_time();
@@ -6306,7 +6306,7 @@ garbage_collect(rb_objspace_t *objspace, unsigned int reason)
ret = gc_start(objspace, reason);
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
return ret;
}
@@ -6590,7 +6590,7 @@ gc_clock_end(struct timespec *ts)
static inline void
gc_enter(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_lev)
{
- *lock_lev = rb_gc_vm_lock();
+ *lock_lev = RB_GC_VM_LOCK();
switch (event) {
case gc_enter_event_rest:
@@ -6629,7 +6629,7 @@ gc_exit(rb_objspace_t *objspace, enum gc_enter_event event, unsigned int *lock_l
gc_report(1, objspace, "gc_exit: %s [%s]\n", gc_enter_event_cstr(event), gc_current_status(objspace));
during_gc = FALSE;
- rb_gc_vm_unlock(*lock_lev);
+ RB_GC_VM_UNLOCK(*lock_lev);
}
#ifndef MEASURE_GC
@@ -9106,7 +9106,7 @@ gc_verify_compaction_references(int argc, VALUE* argv, VALUE self)
/* Clear the heap. */
rb_gc_impl_start(objspace, true, true, true, false);
- unsigned int lev = rb_gc_vm_lock();
+ unsigned int lev = RB_GC_VM_LOCK();
{
gc_rest(objspace);
@@ -9162,7 +9162,7 @@ gc_verify_compaction_references(int argc, VALUE* argv, VALUE self)
objspace->rcompactor.compare_func = compare_free_slots;
}
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
rb_gc_impl_start(rb_gc_get_objspace(), true, true, true, true);
diff --git a/gc/gc.h b/gc/gc.h
index df709426de..c12498f033 100644
--- a/gc/gc.h
+++ b/gc/gc.h
@@ -35,6 +35,13 @@ enum rb_gc_vm_weak_tables {
RB_GC_VM_WEAK_TABLE_COUNT
};
+#define RB_GC_VM_LOCK() rb_gc_vm_lock(__FILE__, __LINE__)
+#define RB_GC_VM_UNLOCK(lev) rb_gc_vm_unlock(lev, __FILE__, __LINE__)
+#define RB_GC_CR_LOCK() rb_gc_cr_lock(__FILE__, __LINE__)
+#define RB_GC_CR_UNLOCK(lev) rb_gc_cr_unlock(lev, __FILE__, __LINE__)
+#define RB_GC_VM_LOCK_NO_BARRIER() rb_gc_vm_lock_no_barrier(__FILE__, __LINE__)
+#define RB_GC_VM_UNLOCK_NO_BARRIER(lev) rb_gc_vm_unlock_no_barrier(lev, __FILE__, __LINE__)
+
#if USE_MODULAR_GC
# define MODULAR_GC_FN
#else
@@ -57,12 +64,12 @@ size_t rb_obj_memsize_of(VALUE obj);
bool ruby_free_at_exit_p(void);
void rb_objspace_reachable_objects_from_root(void (func)(const char *category, VALUE, void *), void *passing_data);
-MODULAR_GC_FN unsigned int rb_gc_vm_lock(void);
-MODULAR_GC_FN void rb_gc_vm_unlock(unsigned int lev);
-MODULAR_GC_FN unsigned int rb_gc_cr_lock(void);
-MODULAR_GC_FN void rb_gc_cr_unlock(unsigned int lev);
-MODULAR_GC_FN unsigned int rb_gc_vm_lock_no_barrier(void);
-MODULAR_GC_FN void rb_gc_vm_unlock_no_barrier(unsigned int lev);
+MODULAR_GC_FN unsigned int rb_gc_vm_lock(const char *file, int line);
+MODULAR_GC_FN void rb_gc_vm_unlock(unsigned int lev, const char *file, int line);
+MODULAR_GC_FN unsigned int rb_gc_cr_lock(const char *file, int line);
+MODULAR_GC_FN void rb_gc_cr_unlock(unsigned int lev, const char *file, int line);
+MODULAR_GC_FN unsigned int rb_gc_vm_lock_no_barrier(const char *file, int line);
+MODULAR_GC_FN void rb_gc_vm_unlock_no_barrier(unsigned int lev, const char *file, int line);
MODULAR_GC_FN void rb_gc_vm_barrier(void);
MODULAR_GC_FN size_t rb_gc_obj_optimal_size(VALUE obj);
MODULAR_GC_FN void rb_gc_mark_children(void *objspace, VALUE obj);
diff --git a/gc/mmtk/mmtk.c b/gc/mmtk/mmtk.c
index 9e4ee9f3de..c318c6fe48 100644
--- a/gc/mmtk/mmtk.c
+++ b/gc/mmtk/mmtk.c
@@ -129,7 +129,7 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
struct objspace *objspace = rb_gc_get_objspace();
size_t starting_gc_count = objspace->gc_count;
- int lock_lev = rb_gc_vm_lock();
+ int lock_lev = RB_GC_VM_LOCK();
int err;
if ((err = pthread_mutex_lock(&objspace->mutex)) != 0) {
rb_bug("ERROR: cannot lock objspace->mutex: %s", strerror(err));
@@ -173,7 +173,7 @@ rb_mmtk_block_for_gc(MMTk_VMMutatorThread mutator)
if ((err = pthread_mutex_unlock(&objspace->mutex)) != 0) {
rb_bug("ERROR: cannot release objspace->mutex: %s", strerror(err));
}
- rb_gc_vm_unlock(lock_lev);
+ RB_GC_VM_UNLOCK(lock_lev);
}
static size_t
@@ -927,7 +927,7 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
RBASIC(obj)->flags |= FL_FINALIZE;
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
if (st_lookup(objspace->finalizer_table, obj, &data)) {
table = (VALUE)data;
@@ -940,7 +940,7 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
for (i = 0; i < len; i++) {
VALUE recv = RARRAY_AREF(table, i);
if (rb_equal(recv, block)) {
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
return recv;
}
}
@@ -954,7 +954,7 @@ rb_gc_impl_define_finalizer(void *objspace_ptr, VALUE obj, VALUE block)
st_add_direct(objspace->finalizer_table, obj, table);
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
return block;
}
@@ -966,9 +966,9 @@ rb_gc_impl_undefine_finalizer(void *objspace_ptr, VALUE obj)
st_data_t data = obj;
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
st_delete(objspace->finalizer_table, &data, 0);
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
FL_UNSET(obj, FL_FINALIZE);
}
@@ -982,7 +982,7 @@ rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
if (!FL_TEST(obj, FL_FINALIZE)) return;
- int lev = rb_gc_vm_lock();
+ int lev = RB_GC_VM_LOCK();
if (RB_LIKELY(st_lookup(objspace->finalizer_table, obj, &data))) {
table = rb_ary_dup((VALUE)data);
RARRAY_ASET(table, 0, rb_obj_id(dest));
@@ -992,7 +992,7 @@ rb_gc_impl_copy_finalizer(void *objspace_ptr, VALUE dest, VALUE obj)
else {
rb_bug("rb_gc_copy_finalizer: FL_FINALIZE set but not found in finalizer_table: %s", rb_obj_info(obj));
}
- rb_gc_vm_unlock(lev);
+ RB_GC_VM_UNLOCK(lev);
}
static int
diff --git a/object.c b/object.c
index fbd2f5d557..8e924b4e6a 100644
--- a/object.c
+++ b/object.c
@@ -83,6 +83,7 @@ static VALUE rb_cFalseClass_to_s;
#define id_init_dup idInitialize_dup
#define id_const_missing idConst_missing
#define id_to_f idTo_f
+static ID id_instance_variables_to_inspect;
#define CLASS_OR_MODULE_P(obj) \
(!SPECIAL_CONST_P(obj) && \
@@ -733,11 +734,17 @@ rb_inspect(VALUE obj)
static int
inspect_i(ID id, VALUE value, st_data_t a)
{
- VALUE str = (VALUE)a;
+ VALUE *args = (VALUE *)a, str = args[0], ivars = args[1];
/* need not to show internal data */
if (CLASS_OF(value) == 0) return ST_CONTINUE;
if (!rb_is_instance_id(id)) return ST_CONTINUE;
+ if (!NIL_P(ivars)) {
+ VALUE name = ID2SYM(id);
+ for (long i = 0; RARRAY_AREF(ivars, i) != name; ) {
+ if (++i >= RARRAY_LEN(ivars)) return ST_CONTINUE;
+ }
+ }
if (RSTRING_PTR(str)[0] == '-') { /* first element */
RSTRING_PTR(str)[0] = '#';
rb_str_cat2(str, " ");
@@ -752,13 +759,15 @@ inspect_i(ID id, VALUE value, st_data_t a)
}
static VALUE
-inspect_obj(VALUE obj, VALUE str, int recur)
+inspect_obj(VALUE obj, VALUE a, int recur)
{
+ VALUE *args = (VALUE *)a, str = args[0];
+
if (recur) {
rb_str_cat2(str, " ...");
}
else {
- rb_ivar_foreach(obj, inspect_i, str);
+ rb_ivar_foreach(obj, inspect_i, a);
}
rb_str_cat2(str, ">");
RSTRING_PTR(str)[0] = '#';
@@ -791,17 +800,47 @@ inspect_obj(VALUE obj, VALUE str, int recur)
* end
* end
* Bar.new.inspect #=> "#<Bar:0x0300c868 @bar=1>"
+ *
+ * If _obj_ responds to +instance_variables_to_inspect+, then only
+ * the instance variables listed in the returned array will be included
+ * in the inspect string.
+ *
+ *
+ * class DatabaseConfig
+ * def initialize(host, user, password)
+ * @host = host
+ * @user = user
+ * @password = password
+ * end
+ *
+ * private
+ * def instance_variables_to_inspect = [:@host, :@user]
+ * end
+ *
+ * conf = DatabaseConfig.new("localhost", "root", "hunter2")
+ * conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root">
*/
static VALUE
rb_obj_inspect(VALUE obj)
{
- if (rb_ivar_count(obj) > 0) {
- VALUE str;
+ VALUE ivars = rb_check_funcall(obj, id_instance_variables_to_inspect, 0, 0);
+ st_index_t n = 0;
+ if (UNDEF_P(ivars)) {
+ n = rb_ivar_count(obj);
+ ivars = Qnil;
+ }
+ else if (!NIL_P(ivars)) {
+ Check_Type(ivars, T_ARRAY);
+ n = RARRAY_LEN(ivars);
+ }
+ if (n > 0) {
VALUE c = rb_class_name(CLASS_OF(obj));
-
- str = rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj);
- return rb_exec_recursive(inspect_obj, obj, str);
+ VALUE args[2] = {
+ rb_sprintf("-<%"PRIsVALUE":%p", c, (void*)obj),
+ ivars
+ };
+ return rb_exec_recursive(inspect_obj, obj, (VALUE)args);
}
else {
return rb_any_to_s(obj);
@@ -4600,6 +4639,7 @@ void
Init_Object(void)
{
id_dig = rb_intern_const("dig");
+ id_instance_variables_to_inspect = rb_intern_const("instance_variables_to_inspect");
InitVM(Object);
}
diff --git a/prism/templates/lib/prism/visitor.rb.erb b/prism/templates/lib/prism/visitor.rb.erb
index a1eac38dc4..b1a03c3f1a 100644
--- a/prism/templates/lib/prism/visitor.rb.erb
+++ b/prism/templates/lib/prism/visitor.rb.erb
@@ -34,7 +34,7 @@ module Prism
#
# class FooCalls < Prism::Visitor
# def visit_call_node(node)
- # if node.name == "foo"
+ # if node.name == :foo
# # Do something with the node
# end
#
diff --git a/ractor.c b/ractor.c
index 56345d5670..177906ea1c 100644
--- a/ractor.c
+++ b/ractor.c
@@ -1658,10 +1658,9 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
if (d.stop) return 1;
}
else {
- for (uint32_t i = 0; i < fields_tbl->as.shape.fields_count; i++) {
- if (!UNDEF_P(fields_tbl->as.shape.fields[i])) {
- CHECK_AND_REPLACE(fields_tbl->as.shape.fields[i]);
- }
+ uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
+ for (uint32_t i = 0; i < fields_count; i++) {
+ CHECK_AND_REPLACE(fields_tbl->as.shape.fields[i]);
}
}
}
diff --git a/set.c b/set.c
index ed0ace4224..6dbfd535cf 100644
--- a/set.c
+++ b/set.c
@@ -528,6 +528,7 @@ set_i_initialize_copy(VALUE set, VALUE other)
set_free_embedded(sobj);
set_copy(&sobj->table, RSET_TABLE(other));
+ rb_gc_writebarrier_remember(set);
return set;
}
diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb
index 1f9ce834ab..e60f7576c5 100644
--- a/spec/ruby/core/kernel/inspect_spec.rb
+++ b/spec/ruby/core/kernel/inspect_spec.rb
@@ -28,4 +28,34 @@ describe "Kernel#inspect" do
end
obj.inspect.should be_kind_of(String)
end
+
+ ruby_version_is "3.5" do
+ it "calls #instance_variables_to_inspect private method to know which variables to display" do
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = %i[@host @user @does_not_exist]
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == '#<Object:0x00 @host="localhost", @user="root">'
+
+ obj = Object.new
+ obj.instance_eval do
+ @host = "localhost"
+ @user = "root"
+ @password = "hunter2"
+ end
+ obj.singleton_class.class_eval do
+ private def instance_variables_to_inspect = []
+ end
+
+ inspected = obj.inspect.sub(/^#<Object:0x[0-9a-f]+/, '#<Object:0x00')
+ inspected.should == "#<Object:0x00>"
+ end
+ end
end
diff --git a/test/ruby/test_object.rb b/test/ruby/test_object.rb
index 7d00422629..9074e54df5 100644
--- a/test/ruby/test_object.rb
+++ b/test/ruby/test_object.rb
@@ -950,6 +950,19 @@ class TestObject < Test::Unit::TestCase
assert_match(/\bInspect\u{3042}:.* @\u{3044}=42\b/, x.inspect)
x.instance_variable_set("@\u{3046}".encode(Encoding::EUC_JP), 6)
assert_match(/@\u{3046}=6\b/, x.inspect)
+
+ x = Object.new
+ x.singleton_class.class_eval do
+ private def instance_variables_to_inspect = [:@host, :@user]
+ end
+
+ x.instance_variable_set(:@host, "localhost")
+ x.instance_variable_set(:@user, "root")
+ x.instance_variable_set(:@password, "hunter2")
+ s = x.inspect
+ assert_include(s, "@host=\"localhost\"")
+ assert_include(s, "@user=\"root\"")
+ assert_not_include(s, "@password=")
end
def test_singleton_methods
diff --git a/test/ruby/test_set.rb b/test/ruby/test_set.rb
index 2bb7858eb2..3a8568762a 100644
--- a/test/ruby/test_set.rb
+++ b/test/ruby/test_set.rb
@@ -130,6 +130,12 @@ class TC_Set < Test::Unit::TestCase
assert_equal(Set['a','b','c'], set)
set = Set[1,2]
+ ret = set.replace(Set.new('a'..'c'))
+
+ assert_same(set, ret)
+ assert_equal(Set['a','b','c'], set)
+
+ set = Set[1,2]
assert_raise(ArgumentError) {
set.replace(3)
}
diff --git a/test/ruby/test_zjit.rb b/test/ruby/test_zjit.rb
index 3b64887f92..47a9f6f7dc 100644
--- a/test/ruby/test_zjit.rb
+++ b/test/ruby/test_zjit.rb
@@ -205,6 +205,48 @@ class TestZJIT < Test::Unit::TestCase
}, insns: [:opt_gt], call_threshold: 2
end
+ def test_opt_empty_p
+ assert_compiles('[false, false, true]', <<~RUBY, insns: [:opt_empty_p])
+ def test(x) = x.empty?
+ return test([1]), test("1"), test({})
+ RUBY
+ end
+
+ def test_opt_succ
+ assert_compiles('[0, "B"]', <<~RUBY, insns: [:opt_succ])
+ def test(obj) = obj.succ
+ return test(-1), test("A")
+ RUBY
+ end
+
+ def test_opt_and
+ assert_compiles('[1, [3, 2, 1]]', <<~RUBY, insns: [:opt_and])
+ def test(x, y) = x & y
+ return test(0b1101, 3), test([3, 2, 1, 4], [8, 1, 2, 3])
+ RUBY
+ end
+
+ def test_opt_or
+ assert_compiles('[11, [3, 2, 1]]', <<~RUBY, insns: [:opt_or])
+ def test(x, y) = x | y
+ return test(0b1000, 3), test([3, 2, 1], [1, 2, 3])
+ RUBY
+ end
+
+ def test_opt_not
+ assert_compiles('[true, true, false]', <<~RUBY, insns: [:opt_not])
+ def test(obj) = !obj
+ return test(nil), test(false), test(0)
+ RUBY
+ end
+
+ def test_opt_regexpmatch2
+ assert_compiles('[1, nil]', <<~RUBY, insns: [:opt_regexpmatch2])
+ def test(haystack) = /needle/ =~ haystack
+ return test("kneedle"), test("")
+ RUBY
+ end
+
def test_opt_ge
assert_compiles '[false, true, true]', %q{
def test(a, b) = a >= b
diff --git a/tool/fetch-bundled_gems.rb b/tool/fetch-bundled_gems.rb
index f50bda360a..b76feefd94 100755
--- a/tool/fetch-bundled_gems.rb
+++ b/tool/fetch-bundled_gems.rb
@@ -24,20 +24,22 @@ next unless n
next if n =~ /^#/
next if bundled_gems&.all? {|pat| !File.fnmatch?(pat, n)}
-if File.directory?(n)
- puts "updating #{color.notice(n)} ..."
- system("git", "fetch", "--all", chdir: n) or abort
-else
+unless File.exist?("#{n}/.git")
puts "retrieving #{color.notice(n)} ..."
- system(*%W"git clone #{u} #{n}") or abort
+ system(*%W"git clone --depth=1 --no-tags #{u} #{n}") or abort
end
if r
puts "fetching #{color.notice(r)} ..."
system("git", "fetch", "origin", r, chdir: n) or abort
+ c = r
+else
+ c = ["v#{v}", v].find do |c|
+ puts "fetching #{color.notice(c)} ..."
+ system("git", "fetch", "origin", "refs/tags/#{c}:refs/tags/#{c}", chdir: n)
+ end or abort
end
-c = r || "v#{v}"
checkout = %w"git -c advice.detachedHead=false checkout"
print %[checking out #{color.notice(c)} (v=#{color.info(v)}]
print %[, r=#{color.info(r)}] if r
diff --git a/variable.c b/variable.c
index 6d0e9832e7..a54bebcec0 100644
--- a/variable.c
+++ b/variable.c
@@ -1228,19 +1228,10 @@ gen_fields_tbl_bytes(size_t n)
}
static struct gen_fields_tbl *
-gen_fields_tbl_resize(struct gen_fields_tbl *old, uint32_t n)
+gen_fields_tbl_resize(struct gen_fields_tbl *old, uint32_t new_capa)
{
- RUBY_ASSERT(n > 0);
-
- uint32_t len = old ? old->as.shape.fields_count : 0;
- struct gen_fields_tbl *fields_tbl = xrealloc(old, gen_fields_tbl_bytes(n));
-
- fields_tbl->as.shape.fields_count = n;
- for (; len < n; len++) {
- fields_tbl->as.shape.fields[len] = Qundef;
- }
-
- return fields_tbl;
+ RUBY_ASSERT(new_capa > 0);
+ return xrealloc(old, gen_fields_tbl_bytes(new_capa));
}
void
@@ -1253,7 +1244,8 @@ rb_mark_generic_ivar(VALUE obj)
rb_mark_tbl_no_pin(fields_tbl->as.complex.table);
}
else {
- for (uint32_t i = 0; i < fields_tbl->as.shape.fields_count; i++) {
+ uint32_t fields_count = RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
+ for (uint32_t i = 0; i < fields_count; i++) {
rb_gc_mark_movable(fields_tbl->as.shape.fields[i]);
}
}
@@ -1290,7 +1282,7 @@ rb_generic_ivar_memsize(VALUE obj)
return sizeof(struct gen_fields_tbl) + st_memsize(fields_tbl->as.complex.table);
}
else {
- return gen_fields_tbl_bytes(fields_tbl->as.shape.fields_count);
+ return gen_fields_tbl_bytes(RSHAPE_CAPACITY(RBASIC_SHAPE_ID(obj)));
}
}
return 0;
@@ -1299,21 +1291,12 @@ rb_generic_ivar_memsize(VALUE obj)
static size_t
gen_fields_tbl_count(VALUE obj, const struct gen_fields_tbl *fields_tbl)
{
- uint32_t i;
- size_t n = 0;
-
if (rb_shape_obj_too_complex_p(obj)) {
- n = st_table_size(fields_tbl->as.complex.table);
+ return st_table_size(fields_tbl->as.complex.table);
}
else {
- for (i = 0; i < fields_tbl->as.shape.fields_count; i++) {
- if (!UNDEF_P(fields_tbl->as.shape.fields[i])) {
- n++;
- }
- }
+ return RSHAPE_LEN(RBASIC_SHAPE_ID(obj));
}
-
- return n;
}
VALUE
diff --git a/variable.h b/variable.h
index a95fcc563d..54b7fc5461 100644
--- a/variable.h
+++ b/variable.h
@@ -15,7 +15,6 @@
struct gen_fields_tbl {
union {
struct {
- uint32_t fields_count;
VALUE fields[1];
} shape;
struct {
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index 86e87d72ac..c93b603f53 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -2355,6 +2355,10 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
break; // Don't enqueue the next block as a successor
}
+ // These are opt_send_without_block and all the opt_* instructions
+ // specialized to a certain method that could also be serviced
+ // using the general send implementation. The optimizer start from
+ // a general send for all of these later in the pipeline.
YARVINSN_opt_nil_p |
YARVINSN_opt_plus |
YARVINSN_opt_minus |
@@ -2371,6 +2375,12 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
YARVINSN_opt_length |
YARVINSN_opt_size |
YARVINSN_opt_aref |
+ YARVINSN_opt_empty_p |
+ YARVINSN_opt_succ |
+ YARVINSN_opt_and |
+ YARVINSN_opt_or |
+ YARVINSN_opt_not |
+ YARVINSN_opt_regexpmatch2 |
YARVINSN_opt_send_without_block => {
let cd: *const rb_call_data = get_arg(pc, 0).as_ptr();
let call_info = unsafe { rb_get_call_data_ci(cd) };
@@ -3807,6 +3817,84 @@ mod tests {
}
#[test]
+ fn opt_empty_p() {
+ eval("
+ def test(x) = x.empty?
+ ");
+ assert_method_hir_with_opcode("test", YARVINSN_opt_empty_p, expect![[r#"
+ fn test:
+ bb0(v0:BasicObject, v1:BasicObject):
+ v4:BasicObject = SendWithoutBlock v1, :empty?
+ Return v4
+ "#]]);
+ }
+
+ #[test]
+ fn opt_succ() {
+ eval("
+ def test(x) = x.succ
+ ");
+ assert_method_hir_with_opcode("test", YARVINSN_opt_succ, expect![[r#"
+ fn test:
+ bb0(v0:BasicObject, v1:BasicObject):
+ v4:BasicObject = SendWithoutBlock v1, :succ
+ Return v4
+ "#]]);
+ }
+
+ #[test]
+ fn opt_and() {
+ eval("
+ def test(x, y) = x & y
+ ");
+ assert_method_hir_with_opcode("test", YARVINSN_opt_and, expect![[r#"
+ fn test:
+ bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
+ v5:BasicObject = SendWithoutBlock v1, :&, v2
+ Return v5
+ "#]]);
+ }
+
+ #[test]
+ fn opt_or() {
+ eval("
+ def test(x, y) = x | y
+ ");
+ assert_method_hir_with_opcode("test", YARVINSN_opt_or, expect![[r#"
+ fn test:
+ bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
+ v5:BasicObject = SendWithoutBlock v1, :|, v2
+ Return v5
+ "#]]);
+ }
+
+ #[test]
+ fn opt_not() {
+ eval("
+ def test(x) = !x
+ ");
+ assert_method_hir_with_opcode("test", YARVINSN_opt_not, expect![[r#"
+ fn test:
+ bb0(v0:BasicObject, v1:BasicObject):
+ v4:BasicObject = SendWithoutBlock v1, :!
+ Return v4
+ "#]]);
+ }
+
+ #[test]
+ fn opt_regexpmatch2() {
+ eval("
+ def test(regexp, matchee) = regexp =~ matchee
+ ");
+ assert_method_hir_with_opcode("test", YARVINSN_opt_regexpmatch2, expect![[r#"
+ fn test:
+ bb0(v0:BasicObject, v1:BasicObject, v2:BasicObject):
+ v5:BasicObject = SendWithoutBlock v1, :=~, v2
+ Return v5
+ "#]]);
+ }
+
+ #[test]
fn test_branchnil() {
eval("
def test(x) = x&.itself