diff --git a/.github/workflows/annocheck.yml b/.github/workflows/annocheck.yml index 211dfbdac4744e..76489f1885263b 100644 --- a/.github/workflows/annocheck.yml +++ b/.github/workflows/annocheck.yml @@ -40,7 +40,12 @@ jobs: image: ghcr.io/ruby/ruby-ci-image:gcc-11 options: --user root - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} env: CONFIGURE_TTY: never diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml index 7d461fa8094cda..b5455f5bc9a885 100644 --- a/.github/workflows/baseruby.yml +++ b/.github/workflows/baseruby.yml @@ -36,7 +36,12 @@ jobs: runs-on: ubuntu-20.04 - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} strategy: matrix: diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml index 29bd489efc9f73..65ba10b7a2ebd7 100644 --- a/.github/workflows/check_dependencies.yml +++ b/.github/workflows/check_dependencies.yml @@ -38,7 +38,12 @@ jobs: runs-on: ${{ matrix.os }} - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 768eb01d777a03..28142e8e0e8ef4 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -36,7 +36,12 @@ jobs: contents: read # for actions/checkout to fetch code security-events: write # for github/codeql-action/autobuild to send a status report # CodeQL fails to run pull requests from dependabot due to missing write access to upload results. - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') && github.event.head_commit.pusher.name != 'dependabot[bot]' }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} env: enable_install_doc: no diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml index cb87c6601db1e2..1aba46569f1eff 100644 --- a/.github/workflows/compilers.yml +++ b/.github/workflows/compilers.yml @@ -165,7 +165,6 @@ jobs: # - { name: SYMBOL_DEBUG, env: { cppflags: '-DSYMBOL_DEBUG' } } # - { name: RGENGC_CHECK_MODE, env: { cppflags: '-DRGENGC_CHECK_MODE' } } -# - { name: TRANSIENT_HEAP_CHECK_MODE, env: { cppflags: '-DTRANSIENT_HEAP_CHECK_MODE' } } # - { name: VM_CHECK_MODE, env: { cppflags: '-DVM_CHECK_MODE' } } # - { name: USE_EMBED_CI=0, env: { cppflags: '-DUSE_EMBED_CI=0' } } @@ -178,7 +177,6 @@ jobs: # - { name: USE_LAZY_LOAD, env: { cppflags: '-DUSE_LAZY_LOAD' } } # - { name: USE_SYMBOL_GC=0, env: { cppflags: '-DUSE_SYMBOL_GC=0' } } # - { name: USE_THREAD_CACHE=0, env: { cppflags: '-DUSE_THREAD_CACHE=0' } } -# - { name: USE_TRANSIENT_HEAP=0, env: { cppflags: '-DUSE_TRANSIENT_HEAP=0' } } - { name: USE_RUBY_DEBUG_LOG=1, env: { cppflags: '-DUSE_RUBY_DEBUG_LOG=1' } } # - { name: USE_DEBUG_COUNTER, env: { cppflags: '-DUSE_DEBUG_COUNTER=1', RUBY_DEBUG_COUNTER_DISABLE: '1' } } @@ -218,7 +216,12 @@ jobs: image: ghcr.io/ruby/ruby-ci-image:${{ matrix.entry.container || matrix.entry.env.default_cc || 'clang-16' }} options: --user root - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} env: ${{ matrix.entry.env || matrix.env }} diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml index f6d5c2cc6a5f55..16d4199ea214b3 100644 --- a/.github/workflows/macos.yml +++ b/.github/workflows/macos.yml @@ -47,7 +47,12 @@ jobs: runs-on: ${{ matrix.os }} - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml index 2017c478fd08c5..b7387d0fcf23ce 100644 --- a/.github/workflows/mingw.yml +++ b/.github/workflows/mingw.yml @@ -58,7 +58,12 @@ jobs: test-all-opts: '--name=!/TestObjSpace#test_reachable_objects_during_iteration/' fail-fast: false - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} steps: - name: Set up Ruby & MSYS2 diff --git a/.github/workflows/rjit-bindgen.yml b/.github/workflows/rjit-bindgen.yml index 3c8043b9b46597..cb777c069755ea 100644 --- a/.github/workflows/rjit-bindgen.yml +++ b/.github/workflows/rjit-bindgen.yml @@ -39,7 +39,12 @@ jobs: runs-on: ubuntu-20.04 - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} steps: - name: Set up Ruby diff --git a/.github/workflows/rjit.yml b/.github/workflows/rjit.yml index 22aa69570952bc..4d9062f1bd79ad 100644 --- a/.github/workflows/rjit.yml +++ b/.github/workflows/rjit.yml @@ -49,7 +49,12 @@ jobs: runs-on: ubuntu-22.04 - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml index 79d375c703e029..4a5ff9a90fb087 100644 --- a/.github/workflows/spec_guards.yml +++ b/.github/workflows/spec_guards.yml @@ -27,7 +27,12 @@ jobs: runs-on: ubuntu-20.04 - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} strategy: matrix: diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index 7f50e25dfafd6a..2e3f228aec6805 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -55,7 +55,12 @@ jobs: runs-on: ubuntu-20.04 - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 diff --git a/.github/workflows/wasm.yml b/.github/workflows/wasm.yml index f40543a5389d75..496d5fc8925c4f 100644 --- a/.github/workflows/wasm.yml +++ b/.github/workflows/wasm.yml @@ -54,7 +54,12 @@ jobs: runs-on: ubuntu-20.04 - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 2f706c09f264f4..0c02de78580494 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -40,7 +40,12 @@ jobs: runs-on: windows-${{ matrix.vs < 2022 && '2019' || matrix.vs }} - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} name: VisualStudio ${{ matrix.vs }} diff --git a/.github/workflows/yjit-ubuntu.yml b/.github/workflows/yjit-ubuntu.yml index b273fd6ac3faed..b9660f6aca9b2f 100644 --- a/.github/workflows/yjit-ubuntu.yml +++ b/.github/workflows/yjit-ubuntu.yml @@ -109,7 +109,12 @@ jobs: runs-on: ubuntu-20.04 - if: ${{ !contains(github.event.head_commit.message, '[DOC]') && !contains(github.event.pull_request.labels.*.name, 'Documentation') }} + if: >- + ${{!(false + || contains(github.event.head_commit.message, '[DOC]') + || contains(github.event.pull_request.title, '[DOC]') + || contains(github.event.pull_request.labels.*.name, 'Documentation') + )}} steps: - uses: actions/checkout@c85c95e3d7251135ab7dc9ce3241c5835cc595a9 # v3.5.3 diff --git a/NEWS.md b/NEWS.md index 2ed7e56d7d5079..70ebbe1958bbd1 100644 --- a/NEWS.md +++ b/NEWS.md @@ -59,7 +59,7 @@ The following default gems are updated. * csv 3.2.8 * fiddle 1.1.2 * fileutils 1.7.1 -* irb 1.7.2 +* irb 1.7.3 * nkf 0.1.3 * optparse 0.4.0.pre.1 * psych 5.1.0 @@ -137,6 +137,6 @@ changelog for details of the default gems or bundled gems. [Bug #19150]: https://bugs.ruby-lang.org/issues/19150 [Feature #19314]: https://bugs.ruby-lang.org/issues/19314 [Feature #19347]: https://bugs.ruby-lang.org/issues/19347 +[Feature #19521]: https://bugs.ruby-lang.org/issues/19521 [Feature #19538]: https://bugs.ruby-lang.org/issues/19538 [Feature #19591]: https://bugs.ruby-lang.org/issues/19591 -[Feature #19521]: https://bugs.ruby-lang.org/issues/19521 diff --git a/array.c b/array.c index a99fd9c73d9a01..d5e9d62c3760a6 100644 --- a/array.c +++ b/array.c @@ -28,7 +28,6 @@ #include "ruby/encoding.h" #include "ruby/st.h" #include "ruby/util.h" -#include "transient_heap.h" #include "builtin.h" #if !ARRAY_DEBUG @@ -58,8 +57,6 @@ VALUE rb_cArray; * they cannot be modified. Not updating the reference count * improves copy-on-write performance. Their reference count is * assumed to be infinity. - * 13: RARRAY_TRANSIENT_FLAG - * The buffer of the array is allocated on the transient heap. * 14: RARRAY_PTR_IN_USE_FLAG * The buffer of the array is in use. This is only used during * debugging. @@ -97,7 +94,6 @@ should_be_T_ARRAY(VALUE ary) #define FL_SET_EMBED(a) do { \ assert(!ARY_SHARED_P(a)); \ FL_SET((a), RARRAY_EMBED_FLAG); \ - RARY_TRANSIENT_UNSET(a); \ ary_verify(a); \ } while (0) @@ -166,7 +162,6 @@ should_be_T_ARRAY(VALUE ary) #define FL_SET_SHARED_ROOT(ary) do { \ assert(!OBJ_FROZEN(ary)); \ assert(!ARY_EMBED_P(ary)); \ - assert(!RARRAY_TRANSIENT_P(ary)); \ FL_SET((ary), RARRAY_SHARED_ROOT_FLAG); \ } while (0) @@ -243,20 +238,19 @@ ary_verify_(VALUE ary, const char *file, int line) if (ARY_SHARED_P(ary)) { VALUE root = ARY_SHARED_ROOT(ary); const VALUE *ptr = ARY_HEAP_PTR(ary); - const VALUE *root_ptr = RARRAY_CONST_PTR_TRANSIENT(root); + const VALUE *root_ptr = RARRAY_CONST_PTR(root); long len = ARY_HEAP_LEN(ary), root_len = RARRAY_LEN(root); assert(ARY_SHARED_ROOT_P(root) || OBJ_FROZEN(root)); assert(root_ptr <= ptr && ptr + len <= root_ptr + root_len); ary_verify(root); } else if (ARY_EMBED_P(ary)) { - assert(!RARRAY_TRANSIENT_P(ary)); assert(!ARY_SHARED_P(ary)); assert(RARRAY_LEN(ary) <= ary_embed_capa(ary)); } else { #if 1 - const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary); + const VALUE *ptr = RARRAY_CONST_PTR(ary); long i, len = RARRAY_LEN(ary); volatile VALUE v; if (len > 1) len = 1; /* check only HEAD */ @@ -267,14 +261,6 @@ ary_verify_(VALUE ary, const char *file, int line) #endif } -#if USE_TRANSIENT_HEAP - if (RARRAY_TRANSIENT_P(ary)) { - assert(rb_transient_heap_managed_ptr_p(RARRAY_CONST_PTR_TRANSIENT(ary))); - } -#endif - - rb_transient_heap_verify(); - return ary; } @@ -293,7 +279,7 @@ rb_ary_ptr_use_start(VALUE ary) #if ARRAY_DEBUG FL_SET_RAW(ary, RARRAY_PTR_IN_USE_FLAG); #endif - return (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary); + return (VALUE *)RARRAY_CONST_PTR(ary); } void @@ -315,7 +301,7 @@ rb_mem_clear(VALUE *mem, long size) static void ary_mem_clear(VALUE ary, long beg, long size) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { rb_mem_clear(ptr + beg, size); }); } @@ -331,7 +317,7 @@ memfill(register VALUE *mem, register long size, register VALUE val) static void ary_memfill(VALUE ary, long beg, long size, VALUE val) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { memfill(ptr + beg, size, val); RB_OBJ_WRITTEN(ary, Qundef, val); }); @@ -344,13 +330,13 @@ ary_memcpy0(VALUE ary, long beg, long argc, const VALUE *argv, VALUE buff_owner_ if (argc > (int)(128/sizeof(VALUE)) /* is magic number (cache line size) */) { rb_gc_writebarrier_remember(buff_owner_ary); - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMCPY(ptr+beg, argv, VALUE, argc); }); } else { int i; - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { for (i=0; ias.heap.ptr, VALUE, new_capa, old_capa); - } + SIZED_REALLOC_N(RARRAY(ary)->as.heap.ptr, VALUE, new_capa, ARY_HEAP_CAPA(ary)); ary_verify(ary); - return alloc_capa; + return new_capa; } -#if USE_TRANSIENT_HEAP -static inline void -rb_ary_transient_heap_evacuate_(VALUE ary, int transient, int promote) -{ - if (transient) { - assert(!ARY_SHARED_ROOT_P(ary)); - - VALUE *new_ptr; - const VALUE *old_ptr = ARY_HEAP_PTR(ary); - long capa = ARY_HEAP_CAPA(ary); - - assert(ARY_OWNS_HEAP_P(ary)); - assert(RARRAY_TRANSIENT_P(ary)); - assert(!ARY_PTR_USING_P(ary)); - - if (promote) { - new_ptr = ALLOC_N(VALUE, capa); - RARY_TRANSIENT_UNSET(ary); - } - else { - new_ptr = ary_heap_alloc(ary, capa); - } - - MEMCPY(new_ptr, old_ptr, VALUE, capa); - /* do not use ARY_SET_PTR() because they assert !frozen */ - RARRAY(ary)->as.heap.ptr = new_ptr; - } - - ary_verify(ary); -} - -void -rb_ary_transient_heap_evacuate(VALUE ary, int promote) -{ - rb_ary_transient_heap_evacuate_(ary, RARRAY_TRANSIENT_P(ary), promote); -} - -void -rb_ary_detransient(VALUE ary) -{ - assert(RARRAY_TRANSIENT_P(ary)); - rb_ary_transient_heap_evacuate_(ary, TRUE, TRUE); -} -#else -void -rb_ary_detransient(VALUE ary) -{ - /* do nothing */ -} -#endif - void rb_ary_make_embedded(VALUE ary) { @@ -491,17 +384,13 @@ rb_ary_make_embedded(VALUE ary) if (!ARY_EMBED_P(ary)) { const VALUE *buf = ARY_HEAP_PTR(ary); long len = ARY_HEAP_LEN(ary); - bool was_transient = RARRAY_TRANSIENT_P(ary); - // FL_SET_EMBED also unsets the transient flag FL_SET_EMBED(ary); ARY_SET_EMBED_LEN(ary, len); MEMCPY((void *)ARY_EMBED_PTR(ary), (void *)buf, VALUE, len); - if (!was_transient) { - ary_heap_free_ptr(ary, buf, len * sizeof(VALUE)); - } + ary_heap_free_ptr(ary, buf, len * sizeof(VALUE)); } } @@ -516,7 +405,7 @@ ary_resize_capa(VALUE ary, long capacity) size_t new_capa = capacity; if (ARY_EMBED_P(ary)) { long len = ARY_EMBED_LEN(ary); - VALUE *ptr = ary_heap_alloc(ary, capacity); + VALUE *ptr = ary_heap_alloc(capacity); MEMCPY(ptr, ARY_EMBED_PTR(ary), VALUE, len); FL_UNSET_EMBED(ary); @@ -656,18 +545,18 @@ rb_ary_cancel_sharing(VALUE ary) ARY_SET_EMBED_LEN(ary, len); } else if (ARY_SHARED_ROOT_OCCUPIED(shared_root) && len > ((shared_len = RARRAY_LEN(shared_root))>>1)) { - long shift = RARRAY_CONST_PTR_TRANSIENT(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root); + long shift = RARRAY_CONST_PTR(ary) - RARRAY_CONST_PTR(shared_root); FL_UNSET_SHARED(ary); - ARY_SET_PTR(ary, RARRAY_CONST_PTR_TRANSIENT(shared_root)); + ARY_SET_PTR(ary, RARRAY_CONST_PTR(shared_root)); ARY_SET_CAPA(ary, shared_len); - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr, ptr+shift, VALUE, len); }); FL_SET_EMBED(shared_root); rb_ary_decrement_share(shared_root); } else { - VALUE *ptr = ary_heap_alloc(ary, len); + VALUE *ptr = ary_heap_alloc(len); MEMCPY(ptr, ARY_HEAP_PTR(ary), VALUE, len); rb_ary_unshare(ary); ARY_SET_CAPA(ary, len); @@ -700,7 +589,7 @@ ary_ensure_room_for_push(VALUE ary, long add_len) if (new_len > ary_embed_capa(ary)) { VALUE shared_root = ARY_SHARED_ROOT(ary); if (ARY_SHARED_ROOT_OCCUPIED(shared_root)) { - if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR_TRANSIENT(shared_root) + new_len <= RARRAY_LEN(shared_root)) { + if (ARY_HEAP_PTR(ary) - RARRAY_CONST_PTR(shared_root) + new_len <= RARRAY_LEN(shared_root)) { rb_ary_modify_check(ary); ary_verify(ary); @@ -807,7 +696,7 @@ empty_ary_alloc(VALUE klass) static VALUE ary_new(VALUE klass, long capa) { - VALUE ary,*ptr; + VALUE ary; if (capa < 0) { rb_raise(rb_eArgError, "negative array size (or size too big)"); @@ -826,8 +715,7 @@ ary_new(VALUE klass, long capa) ARY_SET_CAPA(ary, capa); assert(!ARY_EMBED_P(ary)); - ptr = ary_heap_alloc(ary, capa); - ARY_SET_PTR(ary, ptr); + ARY_SET_PTR(ary, ary_heap_alloc(capa)); ARY_SET_HEAP_LEN(ary, 0); } @@ -912,7 +800,7 @@ ec_ary_alloc_heap(rb_execution_context_t *ec, VALUE klass) static VALUE ec_ary_new(rb_execution_context_t *ec, VALUE klass, long capa) { - VALUE ary,*ptr; + VALUE ary; if (capa < 0) { rb_raise(rb_eArgError, "negative array size (or size too big)"); @@ -931,8 +819,7 @@ ec_ary_new(rb_execution_context_t *ec, VALUE klass, long capa) ARY_SET_CAPA(ary, capa); assert(!ARY_EMBED_P(ary)); - ptr = ary_heap_alloc(ary, capa); - ARY_SET_PTR(ary, ptr); + ARY_SET_PTR(ary, ary_heap_alloc(capa)); ARY_SET_HEAP_LEN(ary, 0); } @@ -957,7 +844,6 @@ VALUE rb_ary_hidden_new(long capa) { VALUE ary = ary_new(0, capa); - rb_ary_transient_heap_evacuate(ary, TRUE); return ary; } @@ -980,13 +866,8 @@ rb_ary_free(VALUE ary) RB_DEBUG_COUNTER_INC(obj_ary_extracapa); } - if (RARRAY_TRANSIENT_P(ary)) { - RB_DEBUG_COUNTER_INC(obj_ary_transient); - } - else { - RB_DEBUG_COUNTER_INC(obj_ary_ptr); - ary_heap_free(ary); - } + RB_DEBUG_COUNTER_INC(obj_ary_ptr); + ary_heap_free(ary); } else { RB_DEBUG_COUNTER_INC(obj_ary_embed); @@ -1024,14 +905,11 @@ ary_make_shared(VALUE ary) } else if (OBJ_FROZEN(ary)) { if (!ARY_EMBED_P(ary)) { - rb_ary_transient_heap_evacuate(ary, TRUE); ary_shrink_capa(ary); } return ary; } else { - rb_ary_transient_heap_evacuate(ary, TRUE); - long capa = ARY_CAPA(ary); long len = RARRAY_LEN(ary); @@ -1041,9 +919,7 @@ ary_make_shared(VALUE ary) FL_SET_SHARED_ROOT(shared); if (ARY_EMBED_P(ary)) { - /* Cannot use ary_heap_alloc because we don't want to allocate - * on the transient heap. */ - VALUE *ptr = ALLOC_N(VALUE, capa); + VALUE *ptr = ary_heap_alloc(capa); ARY_SET_PTR(shared, ptr); ary_memcpy(shared, 0, len, RARRAY_CONST_PTR(ary)); @@ -1075,7 +951,7 @@ ary_make_substitution(VALUE ary) VALUE subst = rb_ary_new_capa(len); assert(ARY_EMBED_P(subst)); - ary_memcpy(subst, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary)); + ary_memcpy(subst, 0, len, RARRAY_CONST_PTR(ary)); ARY_SET_EMBED_LEN(subst, len); return subst; } @@ -1322,7 +1198,7 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len) if ((size_t)len <= rarray_embed_capa_max && ary_embeddable_p(len)) { VALUE result = ary_alloc_embed(klass, len); - ary_memcpy(result, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary) + offset); + ary_memcpy(result, 0, len, RARRAY_CONST_PTR(ary) + offset); ARY_SET_EMBED_LEN(result, len); return result; } @@ -1332,7 +1208,7 @@ ary_make_partial(VALUE ary, VALUE klass, long offset, long len) VALUE result = ary_alloc_heap(klass); assert(!ARY_EMBED_P(result)); - ARY_SET_PTR(result, RARRAY_CONST_PTR_TRANSIENT(ary)); + ARY_SET_PTR(result, RARRAY_CONST_PTR(ary)); ARY_SET_LEN(result, RARRAY_LEN(ary)); rb_ary_set_shared(result, shared); @@ -1353,7 +1229,7 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step) assert(offset+len <= RARRAY_LEN(ary)); assert(step != 0); - const VALUE *values = RARRAY_CONST_PTR_TRANSIENT(ary); + const VALUE *values = RARRAY_CONST_PTR(ary); const long orig_len = len; if (step > 0 && step >= len) { @@ -1383,7 +1259,7 @@ ary_make_partial_step(VALUE ary, VALUE klass, long offset, long len, long step) ARY_SET_EMBED_LEN(result, len); } else { - RARRAY_PTR_USE_TRANSIENT(result, ptr, { + RARRAY_PTR_USE(result, ptr, { for (i = 0; i < len; ++i) { RB_OBJ_WRITE(result, ptr+i, values[j]); j += step; @@ -1458,7 +1334,7 @@ rb_ary_push(VALUE ary, VALUE item) { long idx = RARRAY_LEN((ary_verify(ary), ary)); VALUE target_ary = ary_ensure_room_for_push(ary, 1); - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { RB_OBJ_WRITE(target_ary, &ptr[idx], item); }); ARY_SET_LEN(ary, idx + 1); @@ -1648,7 +1524,7 @@ rb_ary_behead(VALUE ary, long n) if (!ARY_SHARED_P(ary)) { if (ARY_EMBED_P(ary) || RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr, ptr + n, VALUE, RARRAY_LEN(ary) - n); }); /* WB: no new reference */ ARY_INCREASE_LEN(ary, -n); @@ -1709,12 +1585,12 @@ ary_modify_for_unshift(VALUE ary, int argc) capa = ARY_CAPA(ary); ary_make_shared(ary); - head = sharedp = RARRAY_CONST_PTR_TRANSIENT(ary); + head = sharedp = RARRAY_CONST_PTR(ary); return make_room_for_unshift(ary, head, (void *)sharedp, argc, capa, len); } else { /* sliding items */ - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr + argc, ptr, VALUE, len); }); @@ -1746,8 +1622,8 @@ ary_ensure_room_for_unshift(VALUE ary, int argc) return ary_modify_for_unshift(ary, argc); } else { - const VALUE * head = RARRAY_CONST_PTR_TRANSIENT(ary); - void *sharedp = (void *)RARRAY_CONST_PTR_TRANSIENT(shared_root); + const VALUE * head = RARRAY_CONST_PTR(ary); + void *sharedp = (void *)RARRAY_CONST_PTR(shared_root); rb_ary_modify_check(ary); return make_room_for_unshift(ary, head, sharedp, argc, capa, len); @@ -2264,7 +2140,7 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen) } { - const VALUE *optr = RARRAY_CONST_PTR_TRANSIENT(ary); + const VALUE *optr = RARRAY_CONST_PTR(ary); rofs = (rptr >= optr && rptr < optr + olen) ? rptr - optr : -1; } @@ -2277,7 +2153,7 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen) len = beg + rlen; ary_mem_clear(ary, olen, beg - olen); if (rlen > 0) { - if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs; + if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs; ary_memcpy0(ary, beg, rlen, rptr, target_ary); } ARY_SET_LEN(ary, len); @@ -2295,20 +2171,20 @@ rb_ary_splice(VALUE ary, long beg, long len, const VALUE *rptr, long rlen) } if (len != rlen) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, + RARRAY_PTR_USE(ary, ptr, MEMMOVE(ptr + beg + rlen, ptr + beg + len, VALUE, olen - (beg + len))); ARY_SET_LEN(ary, alen); } if (rlen > 0) { - if (rofs != -1) rptr = RARRAY_CONST_PTR_TRANSIENT(ary) + rofs; + if (rofs != -1) rptr = RARRAY_CONST_PTR(ary) + rofs; /* give up wb-protected ary */ RB_OBJ_WB_UNPROTECT_FOR(ARRAY, ary); /* do not use RARRAY_PTR() because it can causes GC. * ary can contain T_NONE object because it is not cleared. */ - RARRAY_PTR_USE_TRANSIENT(ary, ptr, + RARRAY_PTR_USE(ary, ptr, MEMMOVE(ptr + beg, rptr, VALUE, rlen)); } } @@ -2353,9 +2229,8 @@ rb_ary_resize(VALUE ary, long len) else if (len <= ary_embed_capa(ary)) { const VALUE *ptr = ARY_HEAP_PTR(ary); long ptr_capa = ARY_HEAP_SIZE(ary); - bool is_malloc_ptr = !ARY_SHARED_P(ary) && !RARRAY_TRANSIENT_P(ary); + bool is_malloc_ptr = !ARY_SHARED_P(ary); - FL_UNSET(ary, RARRAY_TRANSIENT_FLAG); FL_SET_EMBED(ary); MEMCPY((VALUE *)ARY_EMBED_PTR(ary), ptr, VALUE, len); /* WB: no new reference */ @@ -2385,7 +2260,7 @@ static VALUE ary_aset_by_rb_ary_splice(VALUE ary, long beg, long len, VALUE val) { VALUE rpl = rb_ary_to_ary(val); - rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR_TRANSIENT(rpl), RARRAY_LEN(rpl)); + rb_ary_splice(ary, beg, len, RARRAY_CONST_PTR(rpl), RARRAY_LEN(rpl)); RB_GC_GUARD(rpl); return val; } @@ -2808,7 +2683,7 @@ rb_ary_dup(VALUE ary) { long len = RARRAY_LEN(ary); VALUE dup = rb_ary_new2(len); - ary_memcpy(dup, 0, len, RARRAY_CONST_PTR_TRANSIENT(ary)); + ary_memcpy(dup, 0, len, RARRAY_CONST_PTR(ary)); ARY_SET_LEN(dup, len); ary_verify(ary); @@ -3154,7 +3029,7 @@ rb_ary_reverse(VALUE ary) rb_ary_modify(ary); if (len > 1) { - RARRAY_PTR_USE_TRANSIENT(ary, p1, { + RARRAY_PTR_USE(ary, p1, { p2 = p1 + len - 1; /* points last item */ ary_reverse(p1, p2); }); /* WB: no new reference */ @@ -3198,8 +3073,8 @@ rb_ary_reverse_m(VALUE ary) VALUE dup = rb_ary_new2(len); if (len > 0) { - const VALUE *p1 = RARRAY_CONST_PTR_TRANSIENT(ary); - VALUE *p2 = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(dup) + len - 1; + const VALUE *p1 = RARRAY_CONST_PTR(ary); + VALUE *p2 = (VALUE *)RARRAY_CONST_PTR(dup) + len - 1; do *p2-- = *p1++; while (--len > 0); } ARY_SET_LEN(dup, RARRAY_LEN(ary)); @@ -3241,7 +3116,7 @@ rb_ary_rotate(VALUE ary, long cnt) if (cnt != 0) { long len = RARRAY_LEN(ary); if (len > 1 && (cnt = rotate_count(cnt, len)) > 0) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, ary_rotate_ptr(ptr, len, cnt)); + RARRAY_PTR_USE(ary, ptr, ary_rotate_ptr(ptr, len, cnt)); return ary; } } @@ -3363,7 +3238,7 @@ rb_ary_rotate_m(int argc, VALUE *argv, VALUE ary) rotated = rb_ary_new2(len); if (len > 0) { cnt = rotate_count(cnt, len); - ptr = RARRAY_CONST_PTR_TRANSIENT(ary); + ptr = RARRAY_CONST_PTR(ary); len -= cnt; ary_memcpy(rotated, 0, len, ptr + cnt); ary_memcpy(rotated, len, cnt, ptr); @@ -3816,7 +3691,7 @@ append_values_at_single(VALUE result, VALUE ary, long olen, VALUE idx) /* check if idx is Range */ else if (rb_range_beg_len(idx, &beg, &len, olen, 1)) { if (len > 0) { - const VALUE *const src = RARRAY_CONST_PTR_TRANSIENT(ary); + const VALUE *const src = RARRAY_CONST_PTR(ary); const long end = beg + len; const long prevlen = RARRAY_LEN(result); if (beg < olen) { @@ -3962,7 +3837,7 @@ select_bang_ensure(VALUE a) rb_ary_modify(ary); if (i1 < len) { tail = len - i1; - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr + i2, ptr + i1, VALUE, tail); }); } @@ -4149,7 +4024,7 @@ rb_ary_delete_at(VALUE ary, long pos) rb_ary_modify(ary); del = RARRAY_AREF(ary, pos); - RARRAY_PTR_USE_TRANSIENT(ary, ptr, { + RARRAY_PTR_USE(ary, ptr, { MEMMOVE(ptr+pos, ptr+pos+1, VALUE, len-pos-1); }); ARY_INCREASE_LEN(ary, -1); @@ -4210,7 +4085,7 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len) return rb_ary_new2(0); } else { - VALUE arg2 = rb_ary_new4(len, RARRAY_CONST_PTR_TRANSIENT(ary)+pos); + VALUE arg2 = rb_ary_new4(len, RARRAY_CONST_PTR(ary)+pos); rb_ary_splice(ary, pos, len, 0, 0); return arg2; } @@ -4651,14 +4526,14 @@ rb_ary_replace(VALUE copy, VALUE orig) /* orig has enough space to embed the contents of orig. */ if (RARRAY_LEN(orig) <= ary_embed_capa(copy)) { assert(ARY_EMBED_P(copy)); - ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR_TRANSIENT(orig)); + ary_memcpy(copy, 0, RARRAY_LEN(orig), RARRAY_CONST_PTR(orig)); ARY_SET_EMBED_LEN(copy, RARRAY_LEN(orig)); } /* orig is embedded but copy does not have enough space to embed the * contents of orig. */ else if (ARY_EMBED_P(orig)) { long len = ARY_EMBED_LEN(orig); - VALUE *ptr = ary_heap_alloc(copy, len); + VALUE *ptr = ary_heap_alloc(len); FL_UNSET_EMBED(copy); ARY_SET_PTR(copy, ptr); @@ -4667,7 +4542,7 @@ rb_ary_replace(VALUE copy, VALUE orig) // No allocation and exception expected that could leave `copy` in a // bad state from the edits above. - ary_memcpy(copy, 0, len, RARRAY_CONST_PTR_TRANSIENT(orig)); + ary_memcpy(copy, 0, len, RARRAY_CONST_PTR(orig)); } /* Otherwise, orig is on heap and copy does not have enough space to embed * the contents of orig. */ @@ -4999,8 +4874,8 @@ rb_ary_plus(VALUE x, VALUE y) len = xlen + ylen; z = rb_ary_new2(len); - ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR_TRANSIENT(x)); - ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR_TRANSIENT(y)); + ary_memcpy(z, 0, xlen, RARRAY_CONST_PTR(x)); + ary_memcpy(z, xlen, ylen, RARRAY_CONST_PTR(y)); ARY_SET_LEN(z, len); return z; } @@ -5010,7 +4885,7 @@ ary_append(VALUE x, VALUE y) { long n = RARRAY_LEN(y); if (n > 0) { - rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR_TRANSIENT(y), n); + rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR(y), n); } RB_GC_GUARD(y); return x; @@ -5099,16 +4974,16 @@ rb_ary_times(VALUE ary, VALUE times) ary2 = ary_new(rb_cArray, len); ARY_SET_LEN(ary2, len); - ptr = RARRAY_CONST_PTR_TRANSIENT(ary); + ptr = RARRAY_CONST_PTR(ary); t = RARRAY_LEN(ary); if (0 < t) { ary_memcpy(ary2, 0, t, ptr); while (t <= len/2) { - ary_memcpy(ary2, t, t, RARRAY_CONST_PTR_TRANSIENT(ary2)); + ary_memcpy(ary2, t, t, RARRAY_CONST_PTR(ary2)); t *= 2; } if (t < len) { - ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR_TRANSIENT(ary2)); + ary_memcpy(ary2, t, len-t, RARRAY_CONST_PTR(ary2)); } } out: @@ -5239,7 +5114,7 @@ rb_ary_equal(VALUE ary1, VALUE ary2) return rb_equal(ary2, ary1); } if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; - if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue; + if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue; return rb_exec_recursive_paired(recursive_equal, ary1, ary2, ary2); } @@ -5279,7 +5154,7 @@ rb_ary_eql(VALUE ary1, VALUE ary2) if (ary1 == ary2) return Qtrue; if (!RB_TYPE_P(ary2, T_ARRAY)) return Qfalse; if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return Qfalse; - if (RARRAY_CONST_PTR_TRANSIENT(ary1) == RARRAY_CONST_PTR_TRANSIENT(ary2)) return Qtrue; + if (RARRAY_CONST_PTR(ary1) == RARRAY_CONST_PTR(ary2)) return Qtrue; return rb_exec_recursive_paired(recursive_eql, ary1, ary2, ary2); } @@ -6322,14 +6197,14 @@ rb_ary_compact_bang(VALUE ary) long n; rb_ary_modify(ary); - p = t = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(ary); /* WB: no new reference */ + p = t = (VALUE *)RARRAY_CONST_PTR(ary); /* WB: no new reference */ end = p + RARRAY_LEN(ary); while (t < end) { if (NIL_P(*t)) t++; else *p++ = *t++; } - n = p - RARRAY_CONST_PTR_TRANSIENT(ary); + n = p - RARRAY_CONST_PTR(ary); if (RARRAY_LEN(ary) == n) { return Qnil; } @@ -6439,7 +6314,7 @@ flatten(VALUE ary, int level) } result = ary_new(0, RARRAY_LEN(ary)); - ary_memcpy(result, 0, i, RARRAY_CONST_PTR_TRANSIENT(ary)); + ary_memcpy(result, 0, i, RARRAY_CONST_PTR(ary)); ARY_SET_LEN(result, i); stack = ary_new(0, ARY_DEFAULT_SIZE); @@ -6627,7 +6502,7 @@ rb_ary_shuffle_bang(rb_execution_context_t *ec, VALUE ary, VALUE randgen) while (i) { long j = RAND_UPTO(i); VALUE tmp; - if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR_TRANSIENT(ary)) { + if (len != RARRAY_LEN(ary) || ptr != RARRAY_CONST_PTR(ary)) { rb_raise(rb_eRuntimeError, "modified during shuffle"); } tmp = ptr[--i]; @@ -6719,7 +6594,7 @@ ary_sample(rb_execution_context_t *ec, VALUE ary, VALUE randgen, VALUE nv, VALUE sorted[j] = idx[i] = k; } result = rb_ary_new_capa(n); - RARRAY_PTR_USE_TRANSIENT(result, ptr_result, { + RARRAY_PTR_USE(result, ptr_result, { for (i=0; i len) n = len; - RARRAY_PTR_USE_TRANSIENT(ary, ptr_ary, { + RARRAY_PTR_USE(ary, ptr_ary, { for (i=0; icatch_table_ary; if (NIL_P(catch_table_ary)) return; unsigned int i, tlen = (unsigned int)RARRAY_LEN(catch_table_ary); - const VALUE *tptr = RARRAY_CONST_PTR_TRANSIENT(catch_table_ary); + const VALUE *tptr = RARRAY_CONST_PTR(catch_table_ary); for (i = 0; i < tlen; i++) { - const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]); + const VALUE *ptr = RARRAY_CONST_PTR(tptr[i]); LINK_ELEMENT *end = (LINK_ELEMENT *)(ptr[2] & ~1); LINK_ELEMENT *cont = (LINK_ELEMENT *)(ptr[4] & ~1); LINK_ELEMENT *e; @@ -1874,7 +1874,7 @@ iseq_set_arguments(rb_iseq_t *iseq, LINK_ANCHOR *const optargs, const NODE *cons opt_table = ALLOC_N(VALUE, i+1); - MEMCPY(opt_table, RARRAY_CONST_PTR_TRANSIENT(labels), VALUE, i+1); + MEMCPY(opt_table, RARRAY_CONST_PTR(labels), VALUE, i+1); for (j = 0; j < i+1; j++) { opt_table[j] &= ~1; } @@ -2640,14 +2640,14 @@ iseq_set_exception_table(rb_iseq_t *iseq) ISEQ_BODY(iseq)->catch_table = NULL; if (NIL_P(ISEQ_COMPILE_DATA(iseq)->catch_table_ary)) return COMPILE_OK; tlen = (int)RARRAY_LEN(ISEQ_COMPILE_DATA(iseq)->catch_table_ary); - tptr = RARRAY_CONST_PTR_TRANSIENT(ISEQ_COMPILE_DATA(iseq)->catch_table_ary); + tptr = RARRAY_CONST_PTR(ISEQ_COMPILE_DATA(iseq)->catch_table_ary); if (tlen > 0) { struct iseq_catch_table *table = xmalloc(iseq_catch_table_bytes(tlen)); table->size = tlen; for (i = 0; i < table->size; i++) { - ptr = RARRAY_CONST_PTR_TRANSIENT(tptr[i]); + ptr = RARRAY_CONST_PTR(tptr[i]); entry = UNALIGNED_MEMBER_PTR(table, entries[i]); entry->type = (enum rb_catch_type)(ptr[0] & 0xffff); entry->start = label_get_position((LABEL *)(ptr[1] & ~1)); @@ -4735,7 +4735,7 @@ compile_hash(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int meth rb_ary_cat(ary, elem, 2); } VALUE hash = rb_hash_new_with_size(RARRAY_LEN(ary) / 2); - rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR_TRANSIENT(ary), hash); + rb_hash_bulk_insert(RARRAY_LEN(ary), RARRAY_CONST_PTR(ary), hash); hash = rb_obj_hide(hash); OBJ_FREEZE(hash); diff --git a/debug_counter.h b/debug_counter.h index f1208d83a89c47..01b1a63f86312d 100644 --- a/debug_counter.h +++ b/debug_counter.h @@ -207,7 +207,6 @@ RB_DEBUG_COUNTER(gc_isptr_maybe) * * [attr] * * _ptr: R?? is not embed. * * _embed: R?? is embed. - * * _transient: R?? uses transient heap. * * type specific attr. * * str_shared: str is shared. * * str_nofree: nofree @@ -233,7 +232,6 @@ RB_DEBUG_COUNTER(obj_promote) RB_DEBUG_COUNTER(obj_wb_unprotect) RB_DEBUG_COUNTER(obj_obj_embed) -RB_DEBUG_COUNTER(obj_obj_transient) RB_DEBUG_COUNTER(obj_obj_ptr) RB_DEBUG_COUNTER(obj_obj_too_complex) @@ -244,7 +242,6 @@ RB_DEBUG_COUNTER(obj_str_nofree) RB_DEBUG_COUNTER(obj_str_fstr) RB_DEBUG_COUNTER(obj_ary_embed) -RB_DEBUG_COUNTER(obj_ary_transient) RB_DEBUG_COUNTER(obj_ary_ptr) RB_DEBUG_COUNTER(obj_ary_extracapa) /* @@ -268,11 +265,9 @@ RB_DEBUG_COUNTER(obj_hash_g8) RB_DEBUG_COUNTER(obj_hash_null) RB_DEBUG_COUNTER(obj_hash_ar) RB_DEBUG_COUNTER(obj_hash_st) -RB_DEBUG_COUNTER(obj_hash_transient) RB_DEBUG_COUNTER(obj_hash_force_convert) RB_DEBUG_COUNTER(obj_struct_embed) -RB_DEBUG_COUNTER(obj_struct_transient) RB_DEBUG_COUNTER(obj_struct_ptr) RB_DEBUG_COUNTER(obj_data_empty) @@ -327,11 +322,6 @@ RB_DEBUG_COUNTER(heap_xmalloc) RB_DEBUG_COUNTER(heap_xrealloc) RB_DEBUG_COUNTER(heap_xfree) -/* transient_heap */ -RB_DEBUG_COUNTER(theap_alloc) -RB_DEBUG_COUNTER(theap_alloc_fail) -RB_DEBUG_COUNTER(theap_evacuate) - // VM sync RB_DEBUG_COUNTER(vm_sync_lock) RB_DEBUG_COUNTER(vm_sync_lock_enter) diff --git a/ext/-test-/struct/data.c b/ext/-test-/struct/data.c new file mode 100644 index 00000000000000..5841c342e7b0a3 --- /dev/null +++ b/ext/-test-/struct/data.c @@ -0,0 +1,13 @@ +#include "ruby.h" + +static VALUE +bug_data_new(VALUE self, VALUE super) +{ + return rb_data_define(super, "mem1", "mem2", NULL); +} + +void +Init_data(VALUE klass) +{ + rb_define_singleton_method(klass, "data_new", bug_data_new, 1); +} diff --git a/ext/-test-/struct/depend b/ext/-test-/struct/depend index 191408cc90d76e..5db943e28637f1 100644 --- a/ext/-test-/struct/depend +++ b/ext/-test-/struct/depend @@ -1,4 +1,163 @@ # AUTOGENERATED DEPENDENCIES START +data.o: $(RUBY_EXTCONF_H) +data.o: $(arch_hdrdir)/ruby/config.h +data.o: $(hdrdir)/ruby.h +data.o: $(hdrdir)/ruby/assert.h +data.o: $(hdrdir)/ruby/backward.h +data.o: $(hdrdir)/ruby/backward/2/assume.h +data.o: $(hdrdir)/ruby/backward/2/attributes.h +data.o: $(hdrdir)/ruby/backward/2/bool.h +data.o: $(hdrdir)/ruby/backward/2/inttypes.h +data.o: $(hdrdir)/ruby/backward/2/limits.h +data.o: $(hdrdir)/ruby/backward/2/long_long.h +data.o: $(hdrdir)/ruby/backward/2/stdalign.h +data.o: $(hdrdir)/ruby/backward/2/stdarg.h +data.o: $(hdrdir)/ruby/defines.h +data.o: $(hdrdir)/ruby/intern.h +data.o: $(hdrdir)/ruby/internal/abi.h +data.o: $(hdrdir)/ruby/internal/anyargs.h +data.o: $(hdrdir)/ruby/internal/arithmetic.h +data.o: $(hdrdir)/ruby/internal/arithmetic/char.h +data.o: $(hdrdir)/ruby/internal/arithmetic/double.h +data.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +data.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +data.o: $(hdrdir)/ruby/internal/arithmetic/int.h +data.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +data.o: $(hdrdir)/ruby/internal/arithmetic/long.h +data.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +data.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +data.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +data.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +data.o: $(hdrdir)/ruby/internal/arithmetic/short.h +data.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +data.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +data.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +data.o: $(hdrdir)/ruby/internal/assume.h +data.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +data.o: $(hdrdir)/ruby/internal/attr/artificial.h +data.o: $(hdrdir)/ruby/internal/attr/cold.h +data.o: $(hdrdir)/ruby/internal/attr/const.h +data.o: $(hdrdir)/ruby/internal/attr/constexpr.h +data.o: $(hdrdir)/ruby/internal/attr/deprecated.h +data.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +data.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +data.o: $(hdrdir)/ruby/internal/attr/error.h +data.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +data.o: $(hdrdir)/ruby/internal/attr/forceinline.h +data.o: $(hdrdir)/ruby/internal/attr/format.h +data.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +data.o: $(hdrdir)/ruby/internal/attr/noalias.h +data.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +data.o: $(hdrdir)/ruby/internal/attr/noexcept.h +data.o: $(hdrdir)/ruby/internal/attr/noinline.h +data.o: $(hdrdir)/ruby/internal/attr/nonnull.h +data.o: $(hdrdir)/ruby/internal/attr/noreturn.h +data.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +data.o: $(hdrdir)/ruby/internal/attr/pure.h +data.o: $(hdrdir)/ruby/internal/attr/restrict.h +data.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +data.o: $(hdrdir)/ruby/internal/attr/warning.h +data.o: $(hdrdir)/ruby/internal/attr/weakref.h +data.o: $(hdrdir)/ruby/internal/cast.h +data.o: $(hdrdir)/ruby/internal/compiler_is.h +data.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +data.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +data.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +data.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +data.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +data.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +data.o: $(hdrdir)/ruby/internal/compiler_since.h +data.o: $(hdrdir)/ruby/internal/config.h +data.o: $(hdrdir)/ruby/internal/constant_p.h +data.o: $(hdrdir)/ruby/internal/core.h +data.o: $(hdrdir)/ruby/internal/core/rarray.h +data.o: $(hdrdir)/ruby/internal/core/rbasic.h +data.o: $(hdrdir)/ruby/internal/core/rbignum.h +data.o: $(hdrdir)/ruby/internal/core/rclass.h +data.o: $(hdrdir)/ruby/internal/core/rdata.h +data.o: $(hdrdir)/ruby/internal/core/rfile.h +data.o: $(hdrdir)/ruby/internal/core/rhash.h +data.o: $(hdrdir)/ruby/internal/core/robject.h +data.o: $(hdrdir)/ruby/internal/core/rregexp.h +data.o: $(hdrdir)/ruby/internal/core/rstring.h +data.o: $(hdrdir)/ruby/internal/core/rstruct.h +data.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +data.o: $(hdrdir)/ruby/internal/ctype.h +data.o: $(hdrdir)/ruby/internal/dllexport.h +data.o: $(hdrdir)/ruby/internal/dosish.h +data.o: $(hdrdir)/ruby/internal/error.h +data.o: $(hdrdir)/ruby/internal/eval.h +data.o: $(hdrdir)/ruby/internal/event.h +data.o: $(hdrdir)/ruby/internal/fl_type.h +data.o: $(hdrdir)/ruby/internal/gc.h +data.o: $(hdrdir)/ruby/internal/glob.h +data.o: $(hdrdir)/ruby/internal/globals.h +data.o: $(hdrdir)/ruby/internal/has/attribute.h +data.o: $(hdrdir)/ruby/internal/has/builtin.h +data.o: $(hdrdir)/ruby/internal/has/c_attribute.h +data.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +data.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +data.o: $(hdrdir)/ruby/internal/has/extension.h +data.o: $(hdrdir)/ruby/internal/has/feature.h +data.o: $(hdrdir)/ruby/internal/has/warning.h +data.o: $(hdrdir)/ruby/internal/intern/array.h +data.o: $(hdrdir)/ruby/internal/intern/bignum.h +data.o: $(hdrdir)/ruby/internal/intern/class.h +data.o: $(hdrdir)/ruby/internal/intern/compar.h +data.o: $(hdrdir)/ruby/internal/intern/complex.h +data.o: $(hdrdir)/ruby/internal/intern/cont.h +data.o: $(hdrdir)/ruby/internal/intern/dir.h +data.o: $(hdrdir)/ruby/internal/intern/enum.h +data.o: $(hdrdir)/ruby/internal/intern/enumerator.h +data.o: $(hdrdir)/ruby/internal/intern/error.h +data.o: $(hdrdir)/ruby/internal/intern/eval.h +data.o: $(hdrdir)/ruby/internal/intern/file.h +data.o: $(hdrdir)/ruby/internal/intern/hash.h +data.o: $(hdrdir)/ruby/internal/intern/io.h +data.o: $(hdrdir)/ruby/internal/intern/load.h +data.o: $(hdrdir)/ruby/internal/intern/marshal.h +data.o: $(hdrdir)/ruby/internal/intern/numeric.h +data.o: $(hdrdir)/ruby/internal/intern/object.h +data.o: $(hdrdir)/ruby/internal/intern/parse.h +data.o: $(hdrdir)/ruby/internal/intern/proc.h +data.o: $(hdrdir)/ruby/internal/intern/process.h +data.o: $(hdrdir)/ruby/internal/intern/random.h +data.o: $(hdrdir)/ruby/internal/intern/range.h +data.o: $(hdrdir)/ruby/internal/intern/rational.h +data.o: $(hdrdir)/ruby/internal/intern/re.h +data.o: $(hdrdir)/ruby/internal/intern/ruby.h +data.o: $(hdrdir)/ruby/internal/intern/select.h +data.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +data.o: $(hdrdir)/ruby/internal/intern/signal.h +data.o: $(hdrdir)/ruby/internal/intern/sprintf.h +data.o: $(hdrdir)/ruby/internal/intern/string.h +data.o: $(hdrdir)/ruby/internal/intern/struct.h +data.o: $(hdrdir)/ruby/internal/intern/thread.h +data.o: $(hdrdir)/ruby/internal/intern/time.h +data.o: $(hdrdir)/ruby/internal/intern/variable.h +data.o: $(hdrdir)/ruby/internal/intern/vm.h +data.o: $(hdrdir)/ruby/internal/interpreter.h +data.o: $(hdrdir)/ruby/internal/iterator.h +data.o: $(hdrdir)/ruby/internal/memory.h +data.o: $(hdrdir)/ruby/internal/method.h +data.o: $(hdrdir)/ruby/internal/module.h +data.o: $(hdrdir)/ruby/internal/newobj.h +data.o: $(hdrdir)/ruby/internal/scan_args.h +data.o: $(hdrdir)/ruby/internal/special_consts.h +data.o: $(hdrdir)/ruby/internal/static_assert.h +data.o: $(hdrdir)/ruby/internal/stdalign.h +data.o: $(hdrdir)/ruby/internal/stdbool.h +data.o: $(hdrdir)/ruby/internal/symbol.h +data.o: $(hdrdir)/ruby/internal/value.h +data.o: $(hdrdir)/ruby/internal/value_type.h +data.o: $(hdrdir)/ruby/internal/variable.h +data.o: $(hdrdir)/ruby/internal/warning_push.h +data.o: $(hdrdir)/ruby/internal/xmalloc.h +data.o: $(hdrdir)/ruby/missing.h +data.o: $(hdrdir)/ruby/ruby.h +data.o: $(hdrdir)/ruby/st.h +data.o: $(hdrdir)/ruby/subst.h +data.o: data.c duplicate.o: $(RUBY_EXTCONF_H) duplicate.o: $(arch_hdrdir)/ruby/config.h duplicate.o: $(hdrdir)/ruby.h diff --git a/ext/etc/etc.c b/ext/etc/etc.c index 0b3e5ffd5edea1..78657b43d0f77d 100644 --- a/ext/etc/etc.c +++ b/ext/etc/etc.c @@ -54,7 +54,7 @@ static VALUE sGroup; # include # endif #endif -char *getlogin(); +char *getlogin(void); #define RUBY_ETC_VERSION "1.4.2" @@ -68,7 +68,8 @@ void rb_deprecate_constant(VALUE mod, const char *name); #ifndef HAVE_RB_IO_DESCRIPTOR static int -io_descriptor_fallback(VALUE io) { +io_descriptor_fallback(VALUE io) +{ rb_io_t *fptr; GetOpenFile(io, fptr); return fptr->fd; diff --git a/ext/etc/extconf.rb b/ext/etc/extconf.rb index 7c30b38bfd139b..2e28d5803775b5 100644 --- a/ext/etc/extconf.rb +++ b/ext/etc/extconf.rb @@ -43,8 +43,16 @@ # for https://github.com/ruby/etc srcdir = File.expand_path("..", __FILE__) -if !File.exist?("#{srcdir}/depend") - %x[#{RbConfig.ruby} #{srcdir}/mkconstants.rb -o #{srcdir}/constdefs.h] +constdefs = "#{srcdir}/constdefs.h" +if !File.exist?(constdefs) + ruby = RbConfig.ruby + if File.file?(ruby) + ruby = [ruby] + else + require "shellwords" + ruby = Shellwords.split(ruby) + end + system(*ruby, "#{srcdir}/mkconstants.rb", "-o", constdefs) end # TODO: remove when dropping 2.7 support, as exported since 3.0 diff --git a/ext/openssl/ossl.c b/ext/openssl/ossl.c index 0ffb817fb55ac8..e67832d466eb9b 100644 --- a/ext/openssl/ossl.c +++ b/ext/openssl/ossl.c @@ -827,45 +827,6 @@ ossl_crypto_fixed_length_secure_compare(VALUE dummy, VALUE str1, VALUE str2) * decrypted = cipher.update encrypted * decrypted << cipher.final * - * == PKCS #5 Password-based Encryption - * - * PKCS #5 is a password-based encryption standard documented at - * RFC2898[http://www.ietf.org/rfc/rfc2898.txt]. It allows a short password or - * passphrase to be used to create a secure encryption key. If possible, PBKDF2 - * as described above should be used if the circumstances allow it. - * - * PKCS #5 uses a Cipher, a pass phrase and a salt to generate an encryption - * key. - * - * pass_phrase = 'my secure pass phrase goes here' - * salt = '8 octets' - * - * === Encryption - * - * First set up the cipher for encryption - * - * encryptor = OpenSSL::Cipher.new 'aes-256-cbc' - * encryptor.encrypt - * encryptor.pkcs5_keyivgen pass_phrase, salt - * - * Then pass the data you want to encrypt through - * - * encrypted = encryptor.update 'top secret document' - * encrypted << encryptor.final - * - * === Decryption - * - * Use a new Cipher instance set up for decryption - * - * decryptor = OpenSSL::Cipher.new 'aes-256-cbc' - * decryptor.decrypt - * decryptor.pkcs5_keyivgen pass_phrase, salt - * - * Then pass the data you want to decrypt through - * - * plain = decryptor.update encrypted - * plain << decryptor.final - * * == X509 Certificates * * === Creating a Certificate diff --git a/ext/openssl/ossl_pkey.c b/ext/openssl/ossl_pkey.c index 9caeb5622a1ee4..952a6851e6febb 100644 --- a/ext/openssl/ossl_pkey.c +++ b/ext/openssl/ossl_pkey.c @@ -628,6 +628,72 @@ ossl_pkey_initialize_copy(VALUE self, VALUE other) } #endif +#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY +/* + * call-seq: + * OpenSSL::PKey.new_raw_private_key(algo, string) -> PKey + * + * See the OpenSSL documentation for EVP_PKEY_new_raw_private_key() + */ + +static VALUE +ossl_pkey_new_raw_private_key(VALUE self, VALUE type, VALUE key) +{ + EVP_PKEY *pkey; + const EVP_PKEY_ASN1_METHOD *ameth; + int pkey_id; + size_t keylen; + + StringValue(type); + StringValue(key); + ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type)); + if (!ameth) + ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type); + EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); + + keylen = RSTRING_LEN(key); + + pkey = EVP_PKEY_new_raw_private_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen); + if (!pkey) + ossl_raise(ePKeyError, "EVP_PKEY_new_raw_private_key"); + + return ossl_pkey_new(pkey); +} +#endif + +#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY +/* + * call-seq: + * OpenSSL::PKey.new_raw_public_key(algo, string) -> PKey + * + * See the OpenSSL documentation for EVP_PKEY_new_raw_public_key() + */ + +static VALUE +ossl_pkey_new_raw_public_key(VALUE self, VALUE type, VALUE key) +{ + EVP_PKEY *pkey; + const EVP_PKEY_ASN1_METHOD *ameth; + int pkey_id; + size_t keylen; + + StringValue(type); + StringValue(key); + ameth = EVP_PKEY_asn1_find_str(NULL, RSTRING_PTR(type), RSTRING_LENINT(type)); + if (!ameth) + ossl_raise(ePKeyError, "algorithm %"PRIsVALUE" not found", type); + EVP_PKEY_asn1_get0_info(&pkey_id, NULL, NULL, NULL, NULL, ameth); + + keylen = RSTRING_LEN(key); + + pkey = EVP_PKEY_new_raw_public_key(pkey_id, NULL, (unsigned char *)RSTRING_PTR(key), keylen); + if (!pkey) + ossl_raise(ePKeyError, "EVP_PKEY_new_raw_public_key"); + + return ossl_pkey_new(pkey); +} +#endif + /* * call-seq: * pkey.oid -> string @@ -816,6 +882,35 @@ ossl_pkey_private_to_pem(int argc, VALUE *argv, VALUE self) return do_pkcs8_export(argc, argv, self, 0); } +#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY +/* + * call-seq: + * pkey.raw_private_key => string + * + * See the OpenSSL documentation for EVP_PKEY_get_raw_private_key() + */ + +static VALUE +ossl_pkey_raw_private_key(VALUE self) +{ + EVP_PKEY *pkey; + VALUE str; + size_t len; + + GetPKey(self, pkey); + if (EVP_PKEY_get_raw_private_key(pkey, NULL, &len) != 1) + ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key"); + str = rb_str_new(NULL, len); + + if (EVP_PKEY_get_raw_private_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1) + ossl_raise(ePKeyError, "EVP_PKEY_get_raw_private_key"); + + rb_str_set_len(str, len); + + return str; +} +#endif + VALUE ossl_pkey_export_spki(VALUE self, int to_der) { @@ -865,6 +960,35 @@ ossl_pkey_public_to_pem(VALUE self) return ossl_pkey_export_spki(self, 0); } +#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY +/* + * call-seq: + * pkey.raw_public_key => string + * + * See the OpenSSL documentation for EVP_PKEY_get_raw_public_key() + */ + +static VALUE +ossl_pkey_raw_public_key(VALUE self) +{ + EVP_PKEY *pkey; + VALUE str; + size_t len; + + GetPKey(self, pkey); + if (EVP_PKEY_get_raw_public_key(pkey, NULL, &len) != 1) + ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key"); + str = rb_str_new(NULL, len); + + if (EVP_PKEY_get_raw_public_key(pkey, (unsigned char *)RSTRING_PTR(str), &len) != 1) + ossl_raise(ePKeyError, "EVP_PKEY_get_raw_public_key"); + + rb_str_set_len(str, len); + + return str; +} +#endif + /* * call-seq: * pkey.compare?(another_pkey) -> true | false @@ -1602,6 +1726,10 @@ Init_ossl_pkey(void) rb_define_module_function(mPKey, "read", ossl_pkey_new_from_data, -1); rb_define_module_function(mPKey, "generate_parameters", ossl_pkey_s_generate_parameters, -1); rb_define_module_function(mPKey, "generate_key", ossl_pkey_s_generate_key, -1); +#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY + rb_define_module_function(mPKey, "new_raw_private_key", ossl_pkey_new_raw_private_key, 2); + rb_define_module_function(mPKey, "new_raw_public_key", ossl_pkey_new_raw_public_key, 2); +#endif rb_define_alloc_func(cPKey, ossl_pkey_alloc); rb_define_method(cPKey, "initialize", ossl_pkey_initialize, 0); @@ -1617,6 +1745,10 @@ Init_ossl_pkey(void) rb_define_method(cPKey, "private_to_pem", ossl_pkey_private_to_pem, -1); rb_define_method(cPKey, "public_to_der", ossl_pkey_public_to_der, 0); rb_define_method(cPKey, "public_to_pem", ossl_pkey_public_to_pem, 0); +#ifdef HAVE_EVP_PKEY_NEW_RAW_PRIVATE_KEY + rb_define_method(cPKey, "raw_private_key", ossl_pkey_raw_private_key, 0); + rb_define_method(cPKey, "raw_public_key", ossl_pkey_raw_public_key, 0); +#endif rb_define_method(cPKey, "compare?", ossl_pkey_compare, 1); rb_define_method(cPKey, "sign", ossl_pkey_sign, -1); diff --git a/gc.c b/gc.c index 2e887f715f2bc5..18b36fcf5b6112 100644 --- a/gc.c +++ b/gc.c @@ -131,7 +131,6 @@ #include "ruby_assert.h" #include "ruby_atomic.h" #include "symbol.h" -#include "transient_heap.h" #include "vm_core.h" #include "vm_sync.h" #include "vm_callinfo.h" @@ -1026,6 +1025,9 @@ static const bool HEAP_PAGE_ALLOC_USE_MMAP = false; static bool heap_page_alloc_use_mmap; #endif +#define RVALUE_AGE_BIT_COUNT 2 +#define RVALUE_AGE_BIT_MASK (((bits_t)1 << RVALUE_AGE_BIT_COUNT) - 1) + struct heap_page { short slot_size; short total_slots; @@ -1058,6 +1060,7 @@ struct heap_page { /* If set, the object is not movable */ bits_t pinned_bits[HEAP_PAGE_BITMAP_LIMIT]; + bits_t age_bits[HEAP_PAGE_BITMAP_LIMIT * RVALUE_AGE_BIT_COUNT]; }; /* @@ -1115,6 +1118,35 @@ get_updated_objspace_link(rb_objspace_link_t *os_link) #define GC_SWEEP_PAGES_FREEABLE_PER_STEP 3 +#define RVALUE_AGE_BITMAP_INDEX(n) (NUM_IN_PAGE(n) / (BITS_BITLENGTH / RVALUE_AGE_BIT_COUNT)) +#define RVALUE_AGE_BITMAP_OFFSET(n) ((NUM_IN_PAGE(n) % (BITS_BITLENGTH / RVALUE_AGE_BIT_COUNT)) * RVALUE_AGE_BIT_COUNT) + +#define RVALUE_OLD_AGE 3 + +static int +RVALUE_AGE_GET(VALUE obj) +{ + bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits; + return (int)(age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] >> RVALUE_AGE_BITMAP_OFFSET(obj)) & RVALUE_AGE_BIT_MASK; +} + +static void +RVALUE_AGE_SET(VALUE obj, int age) +{ + RUBY_ASSERT(age <= RVALUE_OLD_AGE); + bits_t *age_bits = GET_HEAP_PAGE(obj)->age_bits; + // clear the bits + age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] &= ~(RVALUE_AGE_BIT_MASK << (RVALUE_AGE_BITMAP_OFFSET(obj))); + // shift the correct value in + age_bits[RVALUE_AGE_BITMAP_INDEX(obj)] |= ((bits_t)age << RVALUE_AGE_BITMAP_OFFSET(obj)); + if (age == RVALUE_OLD_AGE) { + RB_FL_SET_RAW(obj, RUBY_FL_PROMOTED); + } + else { + RB_FL_UNSET_RAW(obj, RUBY_FL_PROMOTED); + } +} + /* Aliases */ #define rb_objspace (*rb_objspace_of(GET_VM())) #define rb_objspace_of(vm) (current_ractor_objspace(vm)) @@ -1337,9 +1369,6 @@ NORETURN(static void gc_raise(VALUE exc, const char *fmt, ...)); NORETURN(static void negative_size_allocation_error(const char *)); static void init_mark_stack(mark_stack_t *stack); - -static int ready_to_gc(rb_objspace_t *objspace); - static int garbage_collect(rb_objspace_t *, unsigned int reason); static int gc_start(rb_objspace_t *objspace, unsigned int reason); @@ -1405,42 +1434,22 @@ static void gc_marking_enter(rb_objspace_t *objspace); static void gc_marking_exit(rb_objspace_t *objspace); static void gc_sweeping_enter(rb_objspace_t *objspace); static void gc_sweeping_exit(rb_objspace_t *objspace); - -static void gc_marks_start(rb_objspace_t *objspace, int full); -static void gc_marks_finish(rb_objspace_t *objspace); static bool gc_marks_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap); static void gc_sweep(rb_objspace_t *objspace); -static void gc_sweep_start(rb_objspace_t *objspace); static void gc_sweep_finish_size_pool(rb_objspace_t *objspace, rb_size_pool_t *size_pool); -static void gc_sweep_finish(rb_objspace_t *objspace); -static int gc_sweep_step(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap); -static void gc_sweep_rest(rb_objspace_t *objspace); static void gc_sweep_continue(rb_objspace_t *objspace, rb_size_pool_t *size_pool, rb_heap_t *heap); static inline void gc_mark(rb_objspace_t *objspace, VALUE ptr); static inline void gc_pin(rb_objspace_t *objspace, VALUE ptr); static inline void gc_mark_and_pin(rb_objspace_t *objspace, VALUE ptr); -static void gc_mark_ptr(rb_objspace_t *objspace, VALUE ptr); NO_SANITIZE("memory", static void gc_mark_maybe(rb_objspace_t *objspace, VALUE ptr)); -static void gc_mark_children(rb_objspace_t *objspace, VALUE ptr); static int gc_mark_stacked_objects_incremental(rb_objspace_t *, size_t count); -static int gc_mark_stacked_objects_all(rb_objspace_t *); -static void gc_grey(rb_objspace_t *objspace, VALUE ptr); - -static inline int gc_mark_set(rb_objspace_t *objspace, VALUE obj); NO_SANITIZE("memory", static inline int is_pointer_to_heap(rb_objspace_t *objspace, void *ptr)); -static void push_mark_stack(mark_stack_t *, VALUE); -static int pop_mark_stack(mark_stack_t *, VALUE *); -static size_t mark_stack_size(mark_stack_t *stack); -static void shrink_stack_chunk_cache(mark_stack_t *stack); - static size_t obj_memsize_of(VALUE obj, int use_all_types); static void gc_verify_internal_consistency(rb_objspace_t *objspace); -static int gc_verify_heap_page(rb_objspace_t *objspace, struct heap_page *page, VALUE obj); -static int gc_verify_heap_pages(rb_objspace_t *objspace); static void gc_stress_set(rb_objspace_t *objspace, VALUE flag); static VALUE gc_disable_no_rest(rb_objspace_t *); @@ -1652,8 +1661,6 @@ asan_poison_object_restore(VALUE obj, void *ptr) #define RVALUE_PAGE_UNCOLLECTIBLE(page, obj) MARKED_IN_BITMAP((page)->uncollectible_bits, (obj)) #define RVALUE_PAGE_MARKING(page, obj) MARKED_IN_BITMAP((page)->marking_bits, (obj)) -#define RVALUE_OLD_AGE 3 -#define RVALUE_AGE_SHIFT 5 /* FL_PROMOTED0 bit */ static int rgengc_remembered(rb_objspace_t *objspace, VALUE obj); static int rgengc_remembered_sweep(rb_objspace_t *objspace, VALUE obj); @@ -1661,12 +1668,6 @@ static int rgengc_remember(rb_objspace_t *objspace, VALUE obj); static void rgengc_mark_and_rememberset_clear(rb_objspace_t *objspace, rb_heap_t *heap); static void rgengc_rememberset_mark(rb_objspace_t *objspace, rb_heap_t *heap); -static inline int -RVALUE_FLAGS_AGE(VALUE flags) -{ - return (int)((flags & (FL_PROMOTED0 | FL_PROMOTED1)) >> RVALUE_AGE_SHIFT); -} - static int check_rvalue_consistency_force(const VALUE obj, int terminate) { @@ -1706,7 +1707,7 @@ check_rvalue_consistency_force(const VALUE obj, int terminate) const int mark_bit = RVALUE_MARK_BITMAP(obj) != 0; const int marking_bit = RVALUE_MARKING_BITMAP(obj) != 0; const int remembered_bit = MARKED_IN_BITMAP(GET_HEAP_PAGE(obj)->remembered_bits, obj) != 0; - const int age = RVALUE_FLAGS_AGE(RBASIC(obj)->flags); + const int age = RVALUE_AGE_GET((VALUE)obj); if (GET_HEAP_PAGE(obj)->flags.in_tomb) { fprintf(stderr, "check_rvalue_consistency: %s is in tomb page.\n", obj_info(obj)); @@ -1849,35 +1850,21 @@ RVALUE_UNCOLLECTIBLE(VALUE obj) return RVALUE_UNCOLLECTIBLE_BITMAP(obj) != 0; } -static inline int -RVALUE_OLD_P_RAW(VALUE obj) -{ - const VALUE promoted = FL_PROMOTED0 | FL_PROMOTED1; - return (RBASIC(obj)->flags & promoted) == promoted; -} - static inline int RVALUE_OLD_P(VALUE obj) { + GC_ASSERT(!RB_SPECIAL_CONST_P(obj)); check_rvalue_consistency(obj); - return RVALUE_OLD_P_RAW(obj); -} - -#if RGENGC_CHECK_MODE || GC_DEBUG -static inline int -RVALUE_AGE(VALUE obj) -{ - check_rvalue_consistency(obj); - return RVALUE_FLAGS_AGE(RBASIC(obj)->flags); + // Because this will only ever be called on GC controlled objects, + // we can use the faster _RAW function here + return RB_OBJ_PROMOTED_RAW(obj); } -#endif static inline void RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(rb_objspace_t *objspace, struct heap_page *page, VALUE obj) { MARK_IN_BITMAP(&page->uncollectible_bits[0], obj); objspace->rgengc.old_objects++; - rb_transient_heap_promote(obj); #if RGENGC_PROFILE >= 2 objspace->profile.total_promoted_count++; @@ -1892,39 +1879,39 @@ RVALUE_OLD_UNCOLLECTIBLE_SET(rb_objspace_t *objspace, VALUE obj) RVALUE_PAGE_OLD_UNCOLLECTIBLE_SET(objspace, GET_HEAP_PAGE(obj), obj); } -static inline VALUE -RVALUE_FLAGS_AGE_SET(VALUE flags, int age) -{ - flags &= ~(FL_PROMOTED0 | FL_PROMOTED1); - flags |= (age << RVALUE_AGE_SHIFT); - return flags; -} - /* set age to age+1 */ static inline void RVALUE_AGE_INC(rb_objspace_t *objspace, VALUE obj) { - VALUE flags = RBASIC(obj)->flags; - int age = RVALUE_FLAGS_AGE(flags); + int age = RVALUE_AGE_GET((VALUE)obj); if (RGENGC_CHECK_MODE && age == RVALUE_OLD_AGE) { rb_bug("RVALUE_AGE_INC: can not increment age of OLD object %s.", obj_info(obj)); } age++; - RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(flags, age); + RVALUE_AGE_SET(obj, age); if (age == RVALUE_OLD_AGE) { RVALUE_OLD_UNCOLLECTIBLE_SET(objspace, obj); } + check_rvalue_consistency(obj); } static inline void -RVALUE_DEMOTE_RAW(rb_objspace_t *objspace, VALUE obj) +RVALUE_AGE_SET_CANDIDATE(rb_objspace_t *objspace, VALUE obj) { - RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, 0); - CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(obj), obj); + check_rvalue_consistency(obj); + GC_ASSERT(!RVALUE_OLD_P(obj)); + RVALUE_AGE_SET(obj, RVALUE_OLD_AGE - 1); + check_rvalue_consistency(obj); +} + +static inline void +RVALUE_AGE_RESET(VALUE obj) +{ + RVALUE_AGE_SET(obj, 0); } static inline void @@ -1937,7 +1924,8 @@ RVALUE_DEMOTE(rb_objspace_t *objspace, VALUE obj) CLEAR_IN_BITMAP(GET_HEAP_PAGE(obj)->remembered_bits, obj); } - RVALUE_DEMOTE_RAW(objspace, obj); + CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS(obj), obj); + RVALUE_AGE_RESET(obj); if (RVALUE_MARKED(obj)) { objspace->rgengc.old_objects--; @@ -1946,22 +1934,6 @@ RVALUE_DEMOTE(rb_objspace_t *objspace, VALUE obj) check_rvalue_consistency(obj); } -static inline void -RVALUE_AGE_RESET_RAW(VALUE obj) -{ - RBASIC(obj)->flags = RVALUE_FLAGS_AGE_SET(RBASIC(obj)->flags, 0); -} - -static inline void -RVALUE_AGE_RESET(VALUE obj) -{ - check_rvalue_consistency(obj); - GC_ASSERT(!RVALUE_OLD_P(obj)); - - RVALUE_AGE_RESET_RAW(obj); - check_rvalue_consistency(obj); -} - static inline int RVALUE_BLACK_P(VALUE obj) { @@ -2153,6 +2125,8 @@ heap_page_add_freeobj(rb_objspace_t *objspace, struct heap_page *page, VALUE obj page->freelist = p; asan_lock_freelist(page); + RVALUE_AGE_RESET(obj); + if (RGENGC_CHECK_MODE && /* obj should belong to page */ !(page->start <= (uintptr_t)obj && @@ -2903,6 +2877,11 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace, p->as.basic.flags = flags; *((VALUE *)&p->as.basic.klass) = klass; + int t = flags & RUBY_T_MASK; + if (t == T_CLASS || t == T_MODULE || t == T_ICLASS) { + RVALUE_AGE_SET_CANDIDATE(objspace, obj); + } + #if RACTOR_CHECK_MODE rb_ractor_setup_belonging(obj); #endif @@ -2919,12 +2898,6 @@ newobj_init(VALUE klass, VALUE flags, int wb_protected, rb_objspace_t *objspace, GC_ASSERT(RVALUE_OLD_P(obj) == FALSE); GC_ASSERT(RVALUE_WB_UNPROTECTED(obj) == FALSE); - if (flags & FL_PROMOTED1) { - if (RVALUE_AGE(obj) != 2) rb_bug("newobj: %s of age (%d) != 2.", obj_info(obj), RVALUE_AGE(obj)); - } - else { - if (RVALUE_AGE(obj) > 0) rb_bug("newobj: %s of age (%d) > 0.", obj_info(obj), RVALUE_AGE(obj)); - } if (rgengc_remembered(objspace, (VALUE)obj)) rb_bug("newobj: %s is remembered.", obj_info(obj)); } RB_VM_LOCK_LEAVE_NO_BARRIER(); @@ -4043,9 +4016,6 @@ obj_free(rb_objspace_t *objspace, VALUE obj) else if (RANY(obj)->as.basic.flags & ROBJECT_EMBED) { RB_DEBUG_COUNTER_INC(obj_obj_embed); } - else if (ROBJ_TRANSIENT_P(obj)) { - RB_DEBUG_COUNTER_INC(obj_obj_transient); - } else { xfree(RANY(obj)->as.object.as.heap.ivptr); RB_DEBUG_COUNTER_INC(obj_obj_ptr); @@ -4216,9 +4186,6 @@ obj_free(rb_objspace_t *objspace, VALUE obj) RANY(obj)->as.rstruct.as.heap.ptr == NULL) { RB_DEBUG_COUNTER_INC(obj_struct_embed); } - else if (RSTRUCT_TRANSIENT_P(obj)) { - RB_DEBUG_COUNTER_INC(obj_struct_transient); - } else { xfree((void *)RANY(obj)->as.rstruct.as.heap.ptr); RB_DEBUG_COUNTER_INC(obj_struct_ptr); @@ -8112,16 +8079,10 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj) } else { long i, len = RARRAY_LEN(obj); - const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(obj); + const VALUE *ptr = RARRAY_CONST_PTR(obj); for (i=0; i < len; i++) { gc_mark(objspace, ptr[i]); } - - if (LIKELY(during_gc)) { - if (!ARY_EMBED_P(obj) && RARRAY_TRANSIENT_P(obj)) { - rb_transient_heap_mark(obj, ptr); - } - } } break; @@ -8165,11 +8126,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj) for (i = 0; i < len; i++) { gc_mark(objspace, ptr[i]); } - - if (LIKELY(during_gc) && - ROBJ_TRANSIENT_P(obj)) { - rb_transient_heap_mark(obj, ptr); - } } if (shape) { VALUE klass = RBASIC_CLASS(obj); @@ -8226,11 +8182,6 @@ gc_mark_children(rb_objspace_t *objspace, VALUE obj) for (i=0; iprofile.heap_used_at_gc_start = heap_allocated_pages; gc_prof_setup_new_record(objspace, reason); gc_reset_malloc_info(objspace, *do_full_mark); - rb_transient_heap_start_marking(*do_full_mark); gc_event_hook(objspace, RUBY_INTERNAL_EVENT_GC_START, 0 /* TODO: pass minor/immediate flag? */); GC_ASSERT(during_gc); @@ -11049,6 +10991,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s int marked; int wb_unprotected; int uncollectible; + int age; RVALUE *dest = (RVALUE *)free; RVALUE *src = (RVALUE *)scan; @@ -11064,6 +11007,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s wb_unprotected = RVALUE_WB_UNPROTECTED((VALUE)src); uncollectible = RVALUE_UNCOLLECTIBLE((VALUE)src); bool remembered = RVALUE_REMEMBERED((VALUE)src); + age = RVALUE_AGE_GET((VALUE)src); /* Clear bits for eventual T_MOVED */ CLEAR_IN_BITMAP(GET_HEAP_MARK_BITS((VALUE)src), (VALUE)src); @@ -11097,6 +11041,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s } memset(src, 0, src_slot_size); + RVALUE_AGE_RESET((VALUE)src); /* Set bits for object in new location */ if (remembered) { @@ -11127,6 +11072,7 @@ gc_move(rb_objspace_t *objspace, VALUE scan, VALUE free, size_t src_slot_size, s CLEAR_IN_BITMAP(GET_HEAP_UNCOLLECTIBLE_BITS((VALUE)dest), (VALUE)dest); } + RVALUE_AGE_SET((VALUE)dest, age); /* Assign forwarding address */ src->as.moved.flags = T_MOVED; src->as.moved.dummy = Qundef; @@ -11207,7 +11153,7 @@ gc_ref_update_array(rb_objspace_t * objspace, VALUE v) long len = RARRAY_LEN(v); if (len > 0) { - VALUE *ptr = (VALUE *)RARRAY_CONST_PTR_TRANSIENT(v); + VALUE *ptr = (VALUE *)RARRAY_CONST_PTR(v); for (long i = 0; i < len; i++) { UPDATE_IF_MOVED(objspace, ptr[i]); } @@ -11237,12 +11183,7 @@ gc_ref_update_object(rb_objspace_t *objspace, VALUE v) // Object can be re-embedded memcpy(ROBJECT(v)->as.ary, ptr, sizeof(VALUE) * ROBJECT_IV_COUNT(v)); RB_FL_SET_RAW(v, ROBJECT_EMBED); - if (ROBJ_TRANSIENT_P(v)) { - ROBJ_TRANSIENT_UNSET(v); - } - else { - xfree(ptr); - } + xfree(ptr); ptr = ROBJECT(v)->as.ary; } @@ -11924,7 +11865,6 @@ gc_update_references(rb_objspace_t *objspace) } } rb_vm_update_references(vm); - rb_transient_heap_update_references(); rb_gc_update_global_tbl(); global_symbols.ids = rb_gc_location(global_symbols.ids); global_symbols.dsymbol_fstr_hash = rb_gc_location(global_symbols.dsymbol_fstr_hash); @@ -14766,7 +14706,7 @@ rb_raw_obj_info_common(char *const buff, const size_t buff_size, const VALUE obj } } else { - const int age = RVALUE_FLAGS_AGE(RBASIC(obj)->flags); + const int age = RVALUE_AGE_GET(obj); if (is_pointer_to_heap(&rb_objspace, (void *)obj)) { APPEND_F("%p [%d%s%s%s%s%s%s] %s ", @@ -14830,13 +14770,12 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU RARRAY_LEN(obj)); } else { - APPEND_F("[%s%s%s] len: %ld, capa:%ld ptr:%p", + APPEND_F("[%s%s] len: %ld, capa:%ld ptr:%p", C(ARY_EMBED_P(obj), "E"), C(ARY_SHARED_P(obj), "S"), - C(RARRAY_TRANSIENT_P(obj), "T"), RARRAY_LEN(obj), ARY_EMBED_P(obj) ? -1L : RARRAY(obj)->as.heap.aux.capa, - (void *)RARRAY_CONST_PTR_TRANSIENT(obj)); + (void *)RARRAY_CONST_PTR(obj)); } break; case T_STRING: { @@ -15103,7 +15042,7 @@ rb_gcdebug_print_obj_condition(VALUE obj) fprintf(stderr, "marked? : %s\n", MARKED_IN_BITMAP(GET_HEAP_MARK_BITS(obj), obj) ? "true" : "false"); fprintf(stderr, "pinned? : %s\n", MARKED_IN_BITMAP(GET_HEAP_PINNED_BITS(obj), obj) ? "true" : "false"); - fprintf(stderr, "age? : %d\n", RVALUE_AGE(obj)); + fprintf(stderr, "age? : %d\n", RVALUE_AGE_GET(obj)); fprintf(stderr, "old? : %s\n", RVALUE_OLD_P(obj) ? "true" : "false"); fprintf(stderr, "WB-protected?: %s\n", RVALUE_WB_UNPROTECTED(obj) ? "false" : "true"); fprintf(stderr, "remembered? : %s\n", RVALUE_REMEMBERED(obj) ? "true" : "false"); @@ -15279,7 +15218,6 @@ Init_GC(void) /* internal methods */ rb_define_singleton_method(rb_mGC, "verify_internal_consistency", gc_verify_internal_consistency_m, 0); - rb_define_singleton_method(rb_mGC, "verify_transient_heap_internal_consistency", gc_verify_transient_heap_internal_consistency, 0); #if MALLOC_ALLOCATED_SIZE rb_define_singleton_method(rb_mGC, "malloc_allocated_size", gc_malloc_allocated_size, 0); rb_define_singleton_method(rb_mGC, "malloc_allocations", gc_malloc_allocations, 0); diff --git a/gems/bundled_gems b/gems/bundled_gems index 499b2a74deb676..7b28da98f5fe88 100644 --- a/gems/bundled_gems +++ b/gems/bundled_gems @@ -17,7 +17,7 @@ net-pop 0.1.2 https://github.com/ruby/net-pop net-smtp 0.3.3 https://github.com/ruby/net-smtp matrix 0.4.2 https://github.com/ruby/matrix prime 0.1.2 https://github.com/ruby/prime -rbs 3.1.0 https://github.com/ruby/rbs +rbs 3.1.0 https://github.com/ruby/rbs b943e7e60493ba312a7c9f5f5e0069a40da90320 typeprof 0.21.7 https://github.com/ruby/typeprof aabc019684d8b4a1ed66c2a1ca48da7bbb18dcc0 debug 1.8.0 https://github.com/ruby/debug racc 1.7.1 https://github.com/ruby/racc diff --git a/hash.c b/hash.c index 978b4626fa4a3c..4bf5fdef61dc62 100644 --- a/hash.c +++ b/hash.c @@ -3501,7 +3501,7 @@ rb_hash_keys(VALUE hash) if (size == 0) return keys; if (ST_DATA_COMPATIBLE_P(VALUE)) { - RARRAY_PTR_USE_TRANSIENT(keys, ptr, { + RARRAY_PTR_USE(keys, ptr, { if (RHASH_AR_TABLE_P(hash)) { size = ar_keys(hash, ptr, size); } @@ -3548,14 +3548,14 @@ rb_hash_values(VALUE hash) if (ST_DATA_COMPATIBLE_P(VALUE)) { if (RHASH_AR_TABLE_P(hash)) { rb_gc_writebarrier_remember(values); - RARRAY_PTR_USE_TRANSIENT(values, ptr, { + RARRAY_PTR_USE(values, ptr, { size = ar_values(hash, ptr, size); }); } else if (RHASH_ST_TABLE_P(hash)) { st_table *table = RHASH_ST_TABLE(hash); rb_gc_writebarrier_remember(values); - RARRAY_PTR_USE_TRANSIENT(values, ptr, { + RARRAY_PTR_USE(values, ptr, { size = st_values(table, ptr, size); }); } diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h index 9670f93d0c54c0..90690fe7945495 100644 --- a/include/ruby/internal/core/rarray.h +++ b/include/ruby/internal/core/rarray.h @@ -35,18 +35,6 @@ #include "ruby/internal/value_type.h" #include "ruby/assert.h" -/** - * @private - * @warning Do not touch this macro. - * @warning It is an implementation detail. - * @warning The value of this macro must match for ruby itself and all - * extension libraries, otherwise serious memory corruption shall - * occur. - */ -#ifndef USE_TRANSIENT_HEAP -# define USE_TRANSIENT_HEAP 1 -#endif - /** * Convenient casting macro. * @@ -59,15 +47,9 @@ #define RARRAY_EMBED_LEN_MASK RARRAY_EMBED_LEN_MASK #define RARRAY_EMBED_LEN_MAX RARRAY_EMBED_LEN_MAX #define RARRAY_EMBED_LEN_SHIFT RARRAY_EMBED_LEN_SHIFT -#if USE_TRANSIENT_HEAP -# define RARRAY_TRANSIENT_FLAG RARRAY_TRANSIENT_FLAG -#else -# define RARRAY_TRANSIENT_FLAG 0 -#endif /** @endcond */ #define RARRAY_LEN rb_array_len /**< @alias{rb_array_len} */ #define RARRAY_CONST_PTR rb_array_const_ptr /**< @alias{rb_array_const_ptr} */ -#define RARRAY_CONST_PTR_TRANSIENT rb_array_const_ptr_transient /**< @alias{rb_array_const_ptr_transient} */ /** @cond INTERNAL_MACRO */ #if defined(__fcc__) || defined(__fcc_version) || \ @@ -80,7 +62,6 @@ #define RARRAY_EMBED_LEN RARRAY_EMBED_LEN #define RARRAY_LENINT RARRAY_LENINT -#define RARRAY_TRANSIENT_P RARRAY_TRANSIENT_P #define RARRAY_ASET RARRAY_ASET #define RARRAY_PTR RARRAY_PTR /** @endcond */ @@ -132,24 +113,6 @@ enum ruby_rarray_flags { */ RARRAY_EMBED_LEN_MASK = RUBY_FL_USER9 | RUBY_FL_USER8 | RUBY_FL_USER7 | RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3 - -#if USE_TRANSIENT_HEAP - , - - /** - * This flag has something to do with an array's "transiency". A transient - * array is an array of young generation (of generational GC), who stores - * its elements inside of dedicated memory pages called a transient heap. - * Not every young generation share that storage scheme, but elder - * generations must no join. - * - * @internal - * - * 3rd parties must not be aware that there even is more than one way to - * store array elements. It was a bad idea to expose this to them. - */ - RARRAY_TRANSIENT_FLAG = RUBY_FL_USER13 -#endif }; /** @@ -249,16 +212,6 @@ VALUE *rb_ary_ptr_use_start(VALUE ary); */ void rb_ary_ptr_use_end(VALUE a); -#if USE_TRANSIENT_HEAP -/** - * Destructively converts an array of transient backend into ordinal one. - * - * @param[out] a An object of ::RArray. - * @pre `a` must be a transient array. - * @post `a` gets out of transient heap, destructively. - */ -void rb_ary_detransient(VALUE a); -#endif RBIMPL_SYMBOL_EXPORT_END() RBIMPL_ATTR_PURE_UNLESS_DEBUG() @@ -330,33 +283,6 @@ RARRAY_LENINT(VALUE ary) return rb_long2int(RARRAY_LEN(ary)); } -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -RBIMPL_ATTR_ARTIFICIAL() -/** - * Queries if the array is a transient array. - * - * @param[in] ary Array in question. - * @retval true Yes it is. - * @retval false No it isn't. - * @pre `ary` must be an instance of ::RArray. - * - * @internal - * - * @shyouhei doesn't understand the benefit of this function called from - * extension libraries. - */ -static inline bool -RARRAY_TRANSIENT_P(VALUE ary) -{ - RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY); - -#if USE_TRANSIENT_HEAP - return RB_FL_ANY_RAW(ary, RARRAY_TRANSIENT_FLAG); -#else - return false; -#endif -} - RBIMPL_ATTR_PURE_UNLESS_DEBUG() /** * @private @@ -368,7 +294,7 @@ RBIMPL_ATTR_PURE_UNLESS_DEBUG() * @return Its backend storage. */ static inline const VALUE * -rb_array_const_ptr_transient(VALUE a) +rb_array_const_ptr(VALUE a) { RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY); @@ -380,101 +306,20 @@ rb_array_const_ptr_transient(VALUE a) } } -#if ! USE_TRANSIENT_HEAP -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -#endif -/** - * @private - * - * This is an implementation detail of RARRAY_PTR(). People do not use it - * directly. - * - * @param[in] a An object of ::RArray. - * @return Its backend storage. - * @post `a` is not a transient array. - */ -static inline const VALUE * -rb_array_const_ptr(VALUE a) -{ - RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY); - -#if USE_TRANSIENT_HEAP - if (RARRAY_TRANSIENT_P(a)) { - rb_ary_detransient(a); - } -#endif - return rb_array_const_ptr_transient(a); -} - -/** - * @private - * - * This is an implementation detail of #RARRAY_PTR_USE. People do not use it - * directly. - * - * @param[in] a An object of ::RArray. - * @param[in] allow_transient Whether `a` can be transient or not. - * @return Its backend storage. - * @post `a` is not a transient array unless `allow_transient`. - */ -static inline VALUE * -rb_array_ptr_use_start(VALUE a, - RBIMPL_ATTR_MAYBE_UNUSED() - int allow_transient) -{ - RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY); - -#if USE_TRANSIENT_HEAP - if (!allow_transient) { - if (RARRAY_TRANSIENT_P(a)) { - rb_ary_detransient(a); - } - } -#endif - - return rb_ary_ptr_use_start(a); -} - -/** - * @private - * - * This is an implementation detail of #RARRAY_PTR_USE. People do not use it - * directly. - * - * @param[in] a An object of ::RArray. - * @param[in] allow_transient Whether `a` can be transient or not. - */ -static inline void -rb_array_ptr_use_end(VALUE a, - RBIMPL_ATTR_MAYBE_UNUSED() - int allow_transient) -{ - RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY); - rb_ary_ptr_use_end(a); -} - /** * @private * * This is an implementation detail of #RARRAY_PTR_USE. People do not use it * directly. */ -#define RBIMPL_RARRAY_STMT(flag, ary, var, expr) do { \ +#define RBIMPL_RARRAY_STMT(ary, var, expr) do { \ RBIMPL_ASSERT_TYPE((ary), RUBY_T_ARRAY); \ const VALUE rbimpl_ary = (ary); \ - VALUE *var = rb_array_ptr_use_start(rbimpl_ary, (flag)); \ + VALUE *var = rb_ary_ptr_use_start(rbimpl_ary); \ expr; \ - rb_array_ptr_use_end(rbimpl_ary, (flag)); \ + rb_ary_ptr_use_end(rbimpl_ary); \ } while (0) -/** - * @private - * - * This is an implementation detail of #RARRAY_PTR_USE. People do not use it - * directly. - */ -#define RARRAY_PTR_USE_END(a) rb_array_ptr_use_end(a, 0) - /** * Declares a section of code where raw pointers are used. In case you need to * touch the raw C array instead of polite CAPIs, then that operation shall be @@ -501,21 +346,11 @@ rb_array_ptr_use_end(VALUE a, * them use it... Maybe some transition path can be implemented later. */ #define RARRAY_PTR_USE(ary, ptr_name, expr) \ - RBIMPL_RARRAY_STMT(0, ary, ptr_name, expr) - -/** - * Identical to #RARRAY_PTR_USE, except the pointer can be a transient one. - * - * @param ary An object of ::RArray. - * @param ptr_name A variable name which points the C array in `expr`. - * @param expr The expression that touches `ptr_name`. - */ -#define RARRAY_PTR_USE_TRANSIENT(ary, ptr_name, expr) \ - RBIMPL_RARRAY_STMT(1, ary, ptr_name, expr) + RBIMPL_RARRAY_STMT(ary, ptr_name, expr) /** * Wild use of a C pointer. This function accesses the backend storage - * directly. This is slower than #RARRAY_PTR_USE_TRANSIENT. It exercises + * directly. This is slower than #RARRAY_PTR_USE. It exercises * extra manoeuvres to protect our generational GC. Use of this function is * considered archaic. Use a modern way instead. * @@ -550,7 +385,7 @@ RARRAY_PTR(VALUE ary) static inline void RARRAY_ASET(VALUE ary, long i, VALUE v) { - RARRAY_PTR_USE_TRANSIENT(ary, ptr, + RARRAY_PTR_USE(ary, ptr, RB_OBJ_WRITE(ary, &ptr[i], v)); } @@ -565,6 +400,6 @@ RARRAY_ASET(VALUE ary, long i, VALUE v) * remains as it is due to that. If we could warn such usages we can set a * transition path, but currently no way is found to do so. */ -#define RARRAY_AREF(a, i) RARRAY_CONST_PTR_TRANSIENT(a)[i] +#define RARRAY_AREF(a, i) RARRAY_CONST_PTR(a)[i] #endif /* RBIMPL_RARRAY_H */ diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h index 1abf9653055fe9..c7904746fd0115 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -173,10 +173,9 @@ rbimpl_typeddata_flags { RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */ /** - * This flag is mysterious. It seems nobody is currently using it. The - * intention of this flag is also unclear. We need further investigations. + * This flag no longer in use */ - RUBY_TYPED_PROMOTED1 = RUBY_FL_PROMOTED1, /* THIS FLAG DEPENDS ON Ruby version */ + RUBY_TYPED_UNUSED = RUBY_FL_UNUSED6, /** * This flag determines whether marking and compaction should be carried out diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h index d59c258a3f877f..f7f5abdd9b1e35 100644 --- a/include/ruby/internal/fl_type.h +++ b/include/ruby/internal/fl_type.h @@ -57,8 +57,7 @@ #define FL_SINGLETON RBIMPL_CAST((VALUE)RUBY_FL_SINGLETON) /**< @old{RUBY_FL_SINGLETON} */ #define FL_WB_PROTECTED RBIMPL_CAST((VALUE)RUBY_FL_WB_PROTECTED) /**< @old{RUBY_FL_WB_PROTECTED} */ -#define FL_PROMOTED0 RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED0) /**< @old{RUBY_FL_PROMOTED0} */ -#define FL_PROMOTED1 RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED1) /**< @old{RUBY_FL_PROMOTED1} */ +#define FL_PROMOTED RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED) /**< @old{RUBY_FL_PROMOTED} */ #define FL_FINALIZE RBIMPL_CAST((VALUE)RUBY_FL_FINALIZE) /**< @old{RUBY_FL_FINALIZE} */ #define FL_TAINT RBIMPL_CAST((VALUE)RUBY_FL_TAINT) /**< @old{RUBY_FL_TAINT} */ #define FL_SHAREABLE RBIMPL_CAST((VALUE)RUBY_FL_SHAREABLE) /**< @old{RUBY_FL_SHAREABLE} */ @@ -200,12 +199,15 @@ ruby_fl_type { RUBY_FL_WB_PROTECTED = (1<<5), /** - * This flag has something to do with our garbage collector. These days - * ruby objects are "generational". There are those who are young and - * those who are old. Young objects are prone to die; monitored relatively - * extensively by the garbage collector. OTOH old objects tend to live - * longer. They are relatively rarely considered. This flag is set when a - * object experienced promotion i.e. survived a garbage collection. + * Ruby objects are "generational". There are young objects & old objects. + * Young objects are prone to die & monitored relatively extensively by the + * garbage collector. Old objects tend to live longer & are monitored less + * frequently. When an object survives a GC, its age is incremented. When + * age is equal to RVALUE_OLD_AGE, the object becomes Old. This flag is set + * when an object becomes old, and is used by the write barrier to check if + * an old object should be considered for marking more frequently - as old + * objects that have references added between major GCs need to be remarked + * to prevent the referred object being mistakenly swept. * * @internal * @@ -213,41 +215,14 @@ ruby_fl_type { * 3rd parties. It must be an implementation detail that they should never * know. Might better be hidden. */ - RUBY_FL_PROMOTED0 = (1<<5), + RUBY_FL_PROMOTED = (1<<5), /** - * This flag has something to do with our garbage collector. These days - * ruby objects are "generational". There are those who are young and - * those who are old. Young objects are prone to die; monitored relatively - * extensively by the garbage collector. OTOH old objects tend to live - * longer. They are relatively rarely considered. This flag is set when a - * object experienced two promotions i.e. survived garbage collections - * twice. + * This flag is no longer in use * * @internal - * - * But honestly, @shyouhei doesn't think this flag should be visible from - * 3rd parties. It must be an implementation detail that they should never - * know. Might better be hidden. - */ - RUBY_FL_PROMOTED1 = (1<<6), - - /** - * This flag has something to do with our garbage collector. These days - * ruby objects are "generational". There are those who are young and - * those who are old. Young objects are prone to die; monitored relatively - * extensively by the garbage collector. OTOH old objects tend to live - * longer. They are relatively rarely considered. This flag is set when a - * object experienced promotions i.e. survived more than one garbage - * collections. - * - * @internal - * - * But honestly, @shyouhei doesn't think this flag should be visible from - * 3rd parties. It must be an implementation detail that they should never - * know. Might better be hidden. */ - RUBY_FL_PROMOTED = RUBY_FL_PROMOTED0 | RUBY_FL_PROMOTED1, + RUBY_FL_UNUSED6 = (1<<6), /** * This flag has something to do with finalisers. A ruby object can have diff --git a/include/ruby/internal/intern/struct.h b/include/ruby/internal/intern/struct.h index 144aea8ecca5df..4510508d7750a0 100644 --- a/include/ruby/internal/intern/struct.h +++ b/include/ruby/internal/intern/struct.h @@ -198,6 +198,20 @@ RBIMPL_ATTR_NONNULL((2)) */ VALUE rb_struct_define_without_accessor_under(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc, ...); +/** + * Defines an anonymous data class. + * + * @endinternal + * + * @param[in] super Superclass of the defining class. Must be a + * descendant of ::rb_cData, or 0 as ::rb_cData. + * @param[in] ... Arbitrary number of `const char*`, terminated by + * NULL. Each of which are the name of fields. + * @exception rb_eArgError Duplicated field name. + * @return The defined class. + */ +VALUE rb_data_define(VALUE super, ...); + RBIMPL_SYMBOL_EXPORT_END() #endif /* RBIMPL_INTERN_STRUCT_H */ diff --git a/inits.c b/inits.c index 1e8047e81f07f4..701ed856b0dbe3 100644 --- a/inits.c +++ b/inits.c @@ -22,9 +22,6 @@ rb_call_inits(void) { CALL(default_shapes); CALL(Thread_Mutex); -#if USE_TRANSIENT_HEAP - CALL(TransientHeap); -#endif CALL(Method); CALL(RandomSeedCore); CALL(encodings); diff --git a/internal/array.h b/internal/array.h index 7e55b66a873ad3..66017129c8849b 100644 --- a/internal/array.h +++ b/internal/array.h @@ -40,8 +40,6 @@ VALUE rb_ary_diff(VALUE ary1, VALUE ary2); static inline VALUE rb_ary_entry_internal(VALUE ary, long offset); static inline bool ARY_PTR_USING_P(VALUE ary); -static inline void RARY_TRANSIENT_SET(VALUE ary); -static inline void RARY_TRANSIENT_UNSET(VALUE ary); VALUE rb_ary_tmp_new_from_values(VALUE, long, const VALUE *); VALUE rb_check_to_array(VALUE ary); @@ -56,7 +54,7 @@ static inline VALUE rb_ary_entry_internal(VALUE ary, long offset) { long len = RARRAY_LEN(ary); - const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary); + const VALUE *ptr = RARRAY_CONST_PTR(ary); if (len == 0) return Qnil; if (offset < 0) { offset += len; @@ -118,22 +116,6 @@ ARY_SHARED_ROOT_REFCNT(VALUE ary) return RARRAY(ary)->as.heap.aux.capa; } -static inline void -RARY_TRANSIENT_SET(VALUE ary) -{ -#if USE_TRANSIENT_HEAP - FL_SET_RAW(ary, RARRAY_TRANSIENT_FLAG); -#endif -} - -static inline void -RARY_TRANSIENT_UNSET(VALUE ary) -{ -#if USE_TRANSIENT_HEAP - FL_UNSET_RAW(ary, RARRAY_TRANSIENT_FLAG); -#endif -} - #undef rb_ary_new_from_args #if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments") # /* Skip it; clang -pedantic doesn't like the following */ @@ -156,7 +138,7 @@ RARRAY_AREF(VALUE ary, long i) { RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY); - return RARRAY_CONST_PTR_TRANSIENT(ary)[i]; + return RARRAY_CONST_PTR(ary)[i]; } #endif /* INTERNAL_ARRAY_H */ diff --git a/internal/cmdlineopt.h b/internal/cmdlineopt.h index 483a5d4f75fde2..b2e38bbb4795e4 100644 --- a/internal/cmdlineopt.h +++ b/internal/cmdlineopt.h @@ -23,11 +23,13 @@ typedef struct ruby_cmdline_options { ruby_features_t features; ruby_features_t warn; unsigned int dump; + int backtrace_length_limit; #if USE_RJIT struct rb_rjit_options rjit; #endif - int sflag, xflag; + signed int sflag: 2; + unsigned int xflag: 1; unsigned int warning: 1; unsigned int verbose: 1; unsigned int do_loop: 1; diff --git a/internal/struct.h b/internal/struct.h index 9b56254541149e..6da5bad10a4b00 100644 --- a/internal/struct.h +++ b/internal/struct.h @@ -15,7 +15,6 @@ enum { RSTRUCT_EMBED_LEN_MASK = RUBY_FL_USER7 | RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3 | RUBY_FL_USER2 | RUBY_FL_USER1, RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1), - RSTRUCT_TRANSIENT_FLAG = RUBY_FL_USER8, }; struct RStruct { @@ -61,9 +60,6 @@ VALUE rb_struct_init_copy(VALUE copy, VALUE s); VALUE rb_struct_lookup(VALUE s, VALUE idx); VALUE rb_struct_s_keyword_init(VALUE klass); static inline const VALUE *rb_struct_const_heap_ptr(VALUE st); -static inline bool RSTRUCT_TRANSIENT_P(VALUE st); -static inline void RSTRUCT_TRANSIENT_SET(VALUE st); -static inline void RSTRUCT_TRANSIENT_UNSET(VALUE st); static inline long RSTRUCT_EMBED_LEN(VALUE st); static inline long RSTRUCT_LEN(VALUE st); static inline int RSTRUCT_LENINT(VALUE st); @@ -71,32 +67,6 @@ static inline const VALUE *RSTRUCT_CONST_PTR(VALUE st); static inline void RSTRUCT_SET(VALUE st, long k, VALUE v); static inline VALUE RSTRUCT_GET(VALUE st, long k); -static inline bool -RSTRUCT_TRANSIENT_P(VALUE st) -{ -#if USE_TRANSIENT_HEAP - return FL_TEST_RAW(st, RSTRUCT_TRANSIENT_FLAG); -#else - return false; -#endif -} - -static inline void -RSTRUCT_TRANSIENT_SET(VALUE st) -{ -#if USE_TRANSIENT_HEAP - FL_SET_RAW(st, RSTRUCT_TRANSIENT_FLAG); -#endif -} - -static inline void -RSTRUCT_TRANSIENT_UNSET(VALUE st) -{ -#if USE_TRANSIENT_HEAP - FL_UNSET_RAW(st, RSTRUCT_TRANSIENT_FLAG); -#endif -} - static inline long RSTRUCT_EMBED_LEN(VALUE st) { diff --git a/internal/variable.h b/internal/variable.h index 4fb7b23cf5b62b..c467489b77baaa 100644 --- a/internal/variable.h +++ b/internal/variable.h @@ -15,10 +15,6 @@ #include "ruby/ruby.h" /* for VALUE */ #include "shape.h" /* for rb_shape_t */ -/* global variable */ - -#define ROBJECT_TRANSIENT_FLAG FL_USER2 - /* variable.c */ void rb_gc_mark_global_tbl(void); void rb_gc_update_global_tbl(void); @@ -32,9 +28,6 @@ rb_gvar_getter_t *rb_gvar_getter_function_of(ID); rb_gvar_setter_t *rb_gvar_setter_function_of(ID); void rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_); void rb_gvar_ractor_local(const char *name); -static inline bool ROBJ_TRANSIENT_P(VALUE obj); -static inline void ROBJ_TRANSIENT_SET(VALUE obj); -static inline void ROBJ_TRANSIENT_UNSET(VALUE obj); /** * Sets the name of a module. @@ -75,30 +68,4 @@ void rb_ensure_iv_list_size(VALUE obj, uint32_t len, uint32_t newsize); struct gen_ivtbl *rb_ensure_generic_iv_list_size(VALUE obj, rb_shape_t *shape, uint32_t newsize); attr_index_t rb_obj_ivar_set(VALUE obj, ID id, VALUE val); -static inline bool -ROBJ_TRANSIENT_P(VALUE obj) -{ -#if USE_TRANSIENT_HEAP - return FL_TEST_RAW(obj, ROBJECT_TRANSIENT_FLAG); -#else - return false; -#endif -} - -static inline void -ROBJ_TRANSIENT_SET(VALUE obj) -{ -#if USE_TRANSIENT_HEAP - FL_SET_RAW(obj, ROBJECT_TRANSIENT_FLAG); -#endif -} - -static inline void -ROBJ_TRANSIENT_UNSET(VALUE obj) -{ -#if USE_TRANSIENT_HEAP - FL_UNSET_RAW(obj, ROBJECT_TRANSIENT_FLAG); -#endif -} - #endif /* INTERNAL_VARIABLE_H */ diff --git a/internal/vm.h b/internal/vm.h index 81e5a9c94a5b37..0ae14a061475c4 100644 --- a/internal/vm.h +++ b/internal/vm.h @@ -77,6 +77,11 @@ VALUE rb_lambda_call(VALUE obj, ID mid, int argc, const VALUE *argv, VALUE data2); void rb_check_stack_overflow(void); +#if USE_YJIT +/* vm_exec.c */ +extern uint64_t rb_vm_insns_count; +#endif + /* vm_insnhelper.c */ VALUE rb_equal_opt(VALUE obj1, VALUE obj2); VALUE rb_eql_opt(VALUE obj1, VALUE obj2); diff --git a/lib/bundler/cli/gem.rb b/lib/bundler/cli/gem.rb index 7f1200f4a001b8..1645283a2c7ab3 100644 --- a/lib/bundler/cli/gem.rb +++ b/lib/bundler/cli/gem.rb @@ -348,7 +348,7 @@ def ask_and_set_linter Bundler.ui.confirm "Do you want to add a code linter and formatter to your gem? " \ "Supported Linters:\n" \ "* RuboCop: https://rubocop.org\n" \ - "* Standard: https://github.com/testdouble/standard\n" \ + "* Standard: https://github.com/standardrb/standard\n" \ "\n" Bundler.ui.info hint_text("linter") diff --git a/lib/bundler/man/bundle-config.1 b/lib/bundler/man/bundle-config.1 index 0e7046a4a266c5..8d5eb2de532cfe 100644 --- a/lib/bundler/man/bundle-config.1 +++ b/lib/bundler/man/bundle-config.1 @@ -299,6 +299,9 @@ The following is a list of all configuration keys and their purpose\. You can le \fBuser_agent\fR (\fBBUNDLE_USER_AGENT\fR): The custom user agent fragment Bundler includes in API requests\. . .IP "\(bu" 4 +\fBversion\fR (\fBBUNDLE_VERSION\fR): The version of Bundler to use when running under Bundler environment\. Defaults to \fBlocal\fR\. You can also specify \fBglobal\fR or \fBx\.y\.z\fR\. \fBlocal\fR will use the Bundler version specified in the \fBGemfile\.lock\fR, \fBglobal\fR will use the system version of Bundler, and \fBx\.y\.z\fR will use the specified version of Bundler\. +. +.IP "\(bu" 4 \fBwith\fR (\fBBUNDLE_WITH\fR): A \fB:\fR\-separated list of groups whose gems bundler should install\. . .IP "\(bu" 4 diff --git a/lib/bundler/man/bundle-config.1.ronn b/lib/bundler/man/bundle-config.1.ronn index bc8b27cf89cdbd..0a3d8e3866689d 100644 --- a/lib/bundler/man/bundle-config.1.ronn +++ b/lib/bundler/man/bundle-config.1.ronn @@ -277,6 +277,12 @@ learn more about their operation in [bundle install(1)](bundle-install.1.html). and disallow passing no options to `bundle update`. * `user_agent` (`BUNDLE_USER_AGENT`): The custom user agent fragment Bundler includes in API requests. +* `version` (`BUNDLE_VERSION`): + The version of Bundler to use when running under Bundler environment. + Defaults to `local`. You can also specify `global` or `x.y.z`. + `local` will use the Bundler version specified in the `Gemfile.lock`, + `global` will use the system version of Bundler, and `x.y.z` will use + the specified version of Bundler. * `with` (`BUNDLE_WITH`): A `:`-separated list of groups whose gems bundler should install. * `without` (`BUNDLE_WITHOUT`): diff --git a/lib/bundler/self_manager.rb b/lib/bundler/self_manager.rb index 827f3f92221d09..491800514dfffe 100644 --- a/lib/bundler/self_manager.rb +++ b/lib/bundler/self_manager.rb @@ -9,17 +9,23 @@ class SelfManager def restart_with_locked_bundler_if_needed return unless needs_switching? && installed? - restart_with(lockfile_version) + restart_with(restart_version) end def install_locked_bundler_and_restart_with_it_if_needed return unless needs_switching? - Bundler.ui.info \ - "Bundler #{current_version} is running, but your lockfile was generated with #{lockfile_version}. " \ - "Installing Bundler #{lockfile_version} and restarting using that version." + if restart_version == lockfile_version + Bundler.ui.info \ + "Bundler #{current_version} is running, but your lockfile was generated with #{lockfile_version}. " \ + "Installing Bundler #{lockfile_version} and restarting using that version." + else + Bundler.ui.info \ + "Bundler #{current_version} is running, but your configuration was #{restart_version}. " \ + "Installing Bundler #{restart_version} and restarting using that version." + end - install_and_restart_with(lockfile_version) + install_and_restart_with(restart_version) end def update_bundler_and_restart_with_it_if_needed(target) @@ -79,7 +85,8 @@ def needs_switching? autoswitching_applies? && released?(lockfile_version) && !running?(lockfile_version) && - !updating? + !updating? && + Bundler.settings[:version] != "global" end def autoswitching_applies? @@ -151,7 +158,7 @@ def updating? def installed? Bundler.configure - Bundler.rubygems.find_bundler(lockfile_version.to_s) + Bundler.rubygems.find_bundler(restart_version.to_s) end def current_version @@ -164,5 +171,14 @@ def lockfile_version parsed_version = Bundler::LockfileParser.bundled_with @lockfile_version = parsed_version ? Gem::Version.new(parsed_version) : nil end + + def restart_version + return @restart_version if defined?(@restart_version) + # BUNDLE_VERSION=x.y.z + @restart_version = Gem::Version.new(Bundler.settings[:version]) + rescue ArgumentError + # BUNDLE_VERSION=local + @restart_version = lockfile_version + end end end diff --git a/lib/bundler/settings.rb b/lib/bundler/settings.rb index b424bcfd521964..19489e34f5ba95 100644 --- a/lib/bundler/settings.rb +++ b/lib/bundler/settings.rb @@ -75,6 +75,7 @@ class Settings shebang system_bindir trust-policy + version ].freeze DEFAULT_CONFIG = { @@ -84,6 +85,7 @@ class Settings "BUNDLE_REDIRECT" => 5, "BUNDLE_RETRY" => 3, "BUNDLE_TIMEOUT" => 10, + "BUNDLE_VERSION" => "local", }.freeze def initialize(root = nil) diff --git a/lib/bundler/source/git.rb b/lib/bundler/source/git.rb index f7ad6057b46b79..4a9f3731bd1f56 100644 --- a/lib/bundler/source/git.rb +++ b/lib/bundler/source/git.rb @@ -69,19 +69,7 @@ def eql?(other) def to_s begin - at = if local? - path - elsif user_ref = options["ref"] - if /\A[a-z0-9]{4,}\z/i.match?(ref) - shortref_for_display(user_ref) - else - user_ref - end - elsif ref - ref - else - current_branch - end + at = humanized_ref || current_branch rev = "at #{at}@#{shortref_for_display(revision)}" rescue GitError @@ -91,6 +79,10 @@ def to_s uri_with_specifiers([rev, glob_for_display]) end + def identifier + uri_with_specifiers([humanized_ref, cached_revision, glob_for_display]) + end + def uri_with_specifiers(specifiers) specifiers.compact! @@ -256,6 +248,20 @@ def local? private + def humanized_ref + if local? + path + elsif user_ref = options["ref"] + if /\A[a-z0-9]{4,}\z/i.match?(ref) + shortref_for_display(user_ref) + else + user_ref + end + elsif ref + ref + end + end + def serialize_gemspecs_in(destination) destination = destination.expand_path(Bundler.root) if destination.relative? Dir["#{destination}/#{@glob}"].each do |spec_path| diff --git a/lib/bundler/templates/newgem/standard.yml.tt b/lib/bundler/templates/newgem/standard.yml.tt index 934b0b2c37ff1f..a0696cd2e9afa6 100644 --- a/lib/bundler/templates/newgem/standard.yml.tt +++ b/lib/bundler/templates/newgem/standard.yml.tt @@ -1,3 +1,3 @@ # For available configuration options, see: -# https://github.com/testdouble/standard +# https://github.com/standardrb/standard ruby_version: <%= ::Gem::Version.new(config[:required_ruby_version]).segments[0..1].join(".") %> diff --git a/lib/getoptlong.rb b/lib/getoptlong.rb index 5ae0e1497c123a..ec77272d2684bc 100644 --- a/lib/getoptlong.rb +++ b/lib/getoptlong.rb @@ -352,7 +352,7 @@ # # Command line: # -# $ ruby fibonacci.rb --number 6 --verbose yes +# $ ruby fibonacci.rb --number 6 --verbose yes # # Output: # diff --git a/lib/irb/context.rb b/lib/irb/context.rb index d755622f32bec7..bf5b4c5708cf15 100644 --- a/lib/irb/context.rb +++ b/lib/irb/context.rb @@ -154,8 +154,12 @@ def initialize(irb, workspace = nil, input_method = nil) def save_history=(val) IRB.conf[:SAVE_HISTORY] = val + if val - (IRB.conf[:MAIN_CONTEXT] || self).init_save_history + context = (IRB.conf[:MAIN_CONTEXT] || self) + if context.io.support_history_saving? && !context.io.singleton_class.include?(HistorySavingAbility) + context.io.extend(HistorySavingAbility) + end end end @@ -576,11 +580,5 @@ def transform_args?(command) command = command_aliases.fetch(command.to_sym, command) ExtendCommandBundle.load_command(command)&.respond_to?(:transform_args) end - - def init_save_history# :nodoc: - unless (class<<@io;self;end).include?(HistorySavingAbility) - @io.extend(HistorySavingAbility) - end - end end end diff --git a/lib/irb/history.rb b/lib/irb/history.rb index a1b0d5cba076d8..e18ff516b24e8c 100644 --- a/lib/irb/history.rb +++ b/lib/irb/history.rb @@ -7,7 +7,6 @@ def HistorySavingAbility.extended(obj) end def load_history - return unless self.class.const_defined?(:HISTORY) history = self.class::HISTORY if history_file = IRB.conf[:HISTORY_FILE] history_file = File.expand_path(history_file) @@ -31,7 +30,6 @@ def load_history end def save_history - return unless self.class.const_defined?(:HISTORY) history = self.class::HISTORY if num = IRB.conf[:SAVE_HISTORY] and (num = num.to_i) != 0 if history_file = IRB.conf[:HISTORY_FILE] diff --git a/lib/irb/input-method.rb b/lib/irb/input-method.rb index 300aa1140d4988..643e89f27e0b2a 100644 --- a/lib/irb/input-method.rb +++ b/lib/irb/input-method.rb @@ -47,6 +47,10 @@ def readable_after_eof? false end + def support_history_saving? + false + end + # For debug message def inspect 'Abstract InputMethod' @@ -230,6 +234,10 @@ def readable_after_eof? true end + def support_history_saving? + true + end + # Returns the current line number for #io. # # #line counts the number of times #gets is called. @@ -256,6 +264,7 @@ def inspect end class RelineInputMethod < InputMethod + HISTORY = Reline::HISTORY # Creates a new input method object using Reline def initialize IRB.__send__(:set_encoding, Reline.encoding_system_needs.name, override: false) @@ -397,7 +406,7 @@ def auto_indent(&block) mod_key = RUBY_PLATFORM.match?(/darwin/) ? "Option" : "Alt" message = "Press #{mod_key}+d to read the full document" contents = [message] + doc.accept(formatter).split("\n") - contents = contents.take(Reline.preferred_dialog_height) + contents = contents.take(preferred_dialog_height) y = cursor_pos_to_render.y Reline::DialogRenderInfo.new(pos: Reline::CursorPos.new(x, y), contents: contents, width: width, bg_color: '49') @@ -458,6 +467,10 @@ def inspect str += " and #{inputrc_path}" if File.exist?(inputrc_path) str end + + def support_history_saving? + true + end end class ReidlineInputMethod < RelineInputMethod diff --git a/lib/irb/version.rb b/lib/irb/version.rb index f8245b3a391c66..3ca5f2803b6a1c 100644 --- a/lib/irb/version.rb +++ b/lib/irb/version.rb @@ -5,7 +5,7 @@ # module IRB # :nodoc: - VERSION = "1.7.2" + VERSION = "1.7.3" @RELEASE_VERSION = VERSION @LAST_UPDATE_DATE = "2023-07-12" end diff --git a/lib/ruby_vm/rjit/insn_compiler.rb b/lib/ruby_vm/rjit/insn_compiler.rb index 1f0376dd04d871..c03f70df032b80 100644 --- a/lib/ruby_vm/rjit/insn_compiler.rb +++ b/lib/ruby_vm/rjit/insn_compiler.rb @@ -5810,7 +5810,7 @@ def jit_array_len(asm, array_reg, len_reg) asm.cmovz(len_reg, [array_reg, C.RArray.offsetof(:as, :heap, :len)]) end - # Generate RARRAY_CONST_PTR_TRANSIENT (part of RARRAY_AREF) + # Generate RARRAY_CONST_PTR (part of RARRAY_AREF) def jit_array_ptr(asm, array_reg, ary_opnd) # clobbers array_reg asm.comment('get array pointer for embedded or heap') diff --git a/lib/yarp/node.rb b/lib/yarp/node.rb index 393030d12d7931..d2f8863091c9bb 100644 --- a/lib/yarp/node.rb +++ b/lib/yarp/node.rb @@ -4427,7 +4427,7 @@ def deconstruct_keys(keys) end end - # Represents a parentesized expression + # Represents a parenthesized expression # # (10 + 34) # ^^^^^^^^^ diff --git a/missing/dtoa.c b/missing/dtoa.c index b7a83028758b3f..bce2cb22a1655c 100644 --- a/missing/dtoa.c +++ b/missing/dtoa.c @@ -183,7 +183,10 @@ #undef Long #undef ULong +#include #include +#include +#include #if (INT_MAX >> 30) && !(INT_MAX >> 31) #define Long int @@ -195,7 +198,7 @@ #error No 32bit integer #endif -#if HAVE_LONG_LONG +#if defined(HAVE_LONG_LONG) && (HAVE_LONG_LONG) #define Llong LONG_LONG #else #define NO_LONG_LONG @@ -221,12 +224,12 @@ #ifdef MALLOC extern void *MALLOC(size_t); #else -#define MALLOC xmalloc +#define MALLOC malloc #endif #ifdef FREE extern void FREE(void*); #else -#define FREE xfree +#define FREE free #endif #ifndef NO_SANITIZE #define NO_SANITIZE(x, y) y @@ -502,7 +505,7 @@ extern double rnd_prod(double, double), rnd_quot(double, double); #endif #ifndef ATOMIC_PTR_CAS -#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (old)) +#define ATOMIC_PTR_CAS(var, old, new) ((var) = (new), (void *)(old)) #endif #ifndef LIKELY #define LIKELY(x) (x) diff --git a/proc.c b/proc.c index 17c837d1647baf..08474506ac4df0 100644 --- a/proc.c +++ b/proc.c @@ -70,7 +70,7 @@ CLONESETUP(VALUE clone, VALUE obj) RBIMPL_ASSERT_OR_ASSUME(! RB_SPECIAL_CONST_P(obj)); RBIMPL_ASSERT_OR_ASSUME(! RB_SPECIAL_CONST_P(clone)); - const VALUE flags = RUBY_FL_PROMOTED0 | RUBY_FL_PROMOTED1 | RUBY_FL_FINALIZE; + const VALUE flags = RUBY_FL_PROMOTED | RUBY_FL_FINALIZE; rb_obj_setup(clone, rb_singleton_class_clone(obj), RB_FL_TEST_RAW(obj, ~flags)); rb_singleton_class_attached(RBASIC_CLASS(clone), clone); diff --git a/ractor.c b/ractor.c index bc0de756859d0f..7437baadfaae43 100644 --- a/ractor.c +++ b/ractor.c @@ -16,7 +16,6 @@ #include "internal/struct.h" #include "internal/thread.h" #include "variable.h" -#include "transient_heap.h" #include "yjit.h" #include "rjit.h" @@ -1906,7 +1905,6 @@ cancel_single_ractor_mode(void) VALUE was_disabled = rb_gc_enable(); rb_gc_start(); - rb_transient_heap_evacuate(); if (was_disabled) { rb_gc_disable(); @@ -3340,10 +3338,6 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data) (st_data_t)&d); } else { -#if USE_TRANSIENT_HEAP - if (data->move) rb_obj_transient_heap_evacuate(obj, TRUE); -#endif - uint32_t len = ROBJECT_IV_COUNT(obj); VALUE *ptr = ROBJECT_IVPTR(obj); @@ -3359,9 +3353,6 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data) case T_ARRAY: { rb_ary_cancel_sharing(obj); -#if USE_TRANSIENT_HEAP - if (data->move) rb_ary_transient_heap_evacuate(obj, TRUE); -#endif for (int i = 0; i < RARRAY_LENINT(obj); i++) { VALUE e = rb_ary_entry(obj, i); @@ -3402,9 +3393,6 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data) case T_STRUCT: { -#if USE_TRANSIENT_HEAP - if (data->move) rb_struct_transient_heap_evacuate(obj, TRUE); -#endif long len = RSTRUCT_LEN(obj); const VALUE *ptr = RSTRUCT_CONST_PTR(obj); diff --git a/ruby.c b/ruby.c index 52a016ae0c1c0e..28579022fe6b6b 100644 --- a/ruby.c +++ b/ruby.c @@ -217,6 +217,7 @@ cmdline_options_init(ruby_cmdline_options_t *opt) #elif defined(YJIT_FORCE_ENABLE) opt->features.set |= FEATURE_BIT(yjit); #endif + opt->backtrace_length_limit = -1; return opt; } @@ -811,10 +812,10 @@ toplevel_context(rb_binding_t *bind) return &bind->block; } -static void -process_sflag(int *sflag) +static int +process_sflag(int sflag) { - if (*sflag > 0) { + if (sflag > 0) { long n; const VALUE *args; VALUE argv = rb_argv; @@ -871,8 +872,9 @@ process_sflag(int *sflag) while (n--) { rb_ary_shift(argv); } - *sflag = -1; + return -1; } + return sflag; } static long proc_options(long argc, char **argv, ruby_cmdline_options_t *opt, int envopt); @@ -886,6 +888,15 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt) VALUE argstr, argary; void *ptr; + VALUE src_enc_name = opt->src.enc.name; + VALUE ext_enc_name = opt->ext.enc.name; + VALUE int_enc_name = opt->intern.enc.name; + ruby_features_t feat = opt->features; + ruby_features_t warn = opt->warn; + int backtrace_length_limit = opt->backtrace_length_limit; + + opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0; + while (ISSPACE(*s)) s++; if (!*s) return; argstr = rb_str_tmp_new((len = strlen(s)) + (envopt!=0)); @@ -921,6 +932,21 @@ moreswitches(const char *s, ruby_cmdline_options_t *opt, int envopt) } } + if (src_enc_name) { + opt->src.enc.name = src_enc_name; + } + if (ext_enc_name) { + opt->ext.enc.name = ext_enc_name; + } + if (int_enc_name) { + opt->intern.enc.name = int_enc_name; + } + FEATURE_SET_RESTORE(opt->features, feat); + FEATURE_SET_RESTORE(opt->warn, warn); + if (backtrace_length_limit >= 0) { + opt->backtrace_length_limit = backtrace_length_limit; + } + ruby_xfree(ptr); /* get rid of GC */ rb_str_resize(argary, 0); @@ -1424,7 +1450,7 @@ proc_long_options(ruby_cmdline_options_t *opt, const char *s, long argc, char ** char *e; long n = strtol(s, &e, 10); if (errno == ERANGE || n < 0 || *e) rb_raise(rb_eRuntimeError, "wrong limit for backtrace length"); - rb_backtrace_length_limit = n; + opt->backtrace_length_limit = (int)n; } else { rb_raise(rb_eRuntimeError, @@ -2002,22 +2028,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt) argv += i; if (FEATURE_SET_P(opt->features, rubyopt) && (s = getenv("RUBYOPT"))) { - VALUE src_enc_name = opt->src.enc.name; - VALUE ext_enc_name = opt->ext.enc.name; - VALUE int_enc_name = opt->intern.enc.name; - ruby_features_t feat = opt->features; - ruby_features_t warn = opt->warn; - - opt->src.enc.name = opt->ext.enc.name = opt->intern.enc.name = 0; moreswitches(s, opt, 1); - if (src_enc_name) - opt->src.enc.name = src_enc_name; - if (ext_enc_name) - opt->ext.enc.name = ext_enc_name; - if (int_enc_name) - opt->intern.enc.name = int_enc_name; - FEATURE_SET_RESTORE(opt->features, feat); - FEATURE_SET_RESTORE(opt->warn, warn); } if (opt->src.enc.name) @@ -2203,7 +2214,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt) #undef SET_COMPILE_OPTION } ruby_set_argv(argc, argv); - process_sflag(&opt->sflag); + opt->sflag = process_sflag(opt->sflag); if (opt->e_script) { VALUE progname = rb_progname; @@ -2233,7 +2244,9 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt) } else { VALUE f; - f = open_load_file(script_name, &opt->xflag); + int xflag = opt->xflag; + f = open_load_file(script_name, &xflag); + opt->xflag = xflag != 0; rb_parser_set_context(parser, 0, f == rb_stdin); ast = load_file(parser, opt->script_name, f, 1, opt); } @@ -2265,7 +2278,7 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt) return Qfalse; } - process_sflag(&opt->sflag); + opt->sflag = process_sflag(opt->sflag); opt->xflag = 0; if (dump & DUMP_BIT(syntax)) { @@ -2321,6 +2334,10 @@ process_options(int argc, char **argv, ruby_cmdline_options_t *opt) } if (opt->dump & dump_exit_bits) return Qtrue; + if (opt->backtrace_length_limit >= 0) { + rb_backtrace_length_limit = opt->backtrace_length_limit; + } + rb_define_readonly_boolean("$-p", opt->do_print); rb_define_readonly_boolean("$-l", opt->do_line); rb_define_readonly_boolean("$-a", opt->do_split); @@ -2636,7 +2653,9 @@ void * rb_parser_load_file(VALUE parser, VALUE fname_v) { ruby_cmdline_options_t opt; - VALUE f = open_load_file(fname_v, &cmdline_options_init(&opt)->xflag); + int xflag = 0; + VALUE f = open_load_file(fname_v, &xflag); + cmdline_options_init(&opt)->xflag = xflag != 0; return load_file(parser, fname_v, f, 0, &opt); } diff --git a/spec/bundler/install/gemfile/git_spec.rb b/spec/bundler/install/gemfile/git_spec.rb index c96a78bc1cff22..910f96f4ab2aa7 100644 --- a/spec/bundler/install/gemfile/git_spec.rb +++ b/spec/bundler/install/gemfile/git_spec.rb @@ -30,6 +30,13 @@ expect(Dir["#{default_bundle_path}/cache/bundler/git/foo-1.0-*"]).to have_attributes :size => 1 end + it "does not write to cache on bundler/setup" do + cache_path = default_bundle_path.join("cache") + FileUtils.rm_rf(cache_path) + ruby "require 'bundler/setup'" + expect(cache_path).not_to exist + end + it "caches the git repo globally and properly uses the cached repo on the next invocation" do simulate_new_machine bundle "config set global_gem_cache true" diff --git a/spec/bundler/install/git_spec.rb b/spec/bundler/install/git_spec.rb index 10c4bd73d96bf5..882f2a2d422767 100644 --- a/spec/bundler/install/git_spec.rb +++ b/spec/bundler/install/git_spec.rb @@ -147,8 +147,6 @@ #{Bundler::VERSION} L - original_lockfile = lockfile - # If GH#6743 is present, the first `bundle install` will change the # lockfile, by flipping the order (`other` would be moved to the top). # diff --git a/spec/bundler/runtime/self_management_spec.rb b/spec/bundler/runtime/self_management_spec.rb index 700084babf665b..0b21601019c4f9 100644 --- a/spec/bundler/runtime/self_management_spec.rb +++ b/spec/bundler/runtime/self_management_spec.rb @@ -6,6 +6,10 @@ "2.3.0" end + let(:current_version) do + "2.4.0" + end + before do build_repo2 @@ -103,6 +107,28 @@ expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION) end + it "installs BUNDLE_VERSION version when using bundle config version x.y.z" do + lockfile_bundled_with(current_version) + + bundle "config set --local version #{previous_minor}" + bundle "install", :artifice => "vcr" + expect(out).to include("Bundler #{Bundler::VERSION} is running, but your configuration was #{previous_minor}. Installing Bundler #{previous_minor} and restarting using that version.") + + bundle "-v" + expect(out).to eq(previous_minor[0] == "2" ? "Bundler version #{previous_minor}" : previous_minor) + end + + it "does not try to install when using bundle config version global" do + lockfile_bundled_with(previous_minor) + + bundle "config set version global" + bundle "install", :artifice => "vcr" + expect(out).not_to match(/restarting using that version/) + + bundle "-v" + expect(out).to eq(Bundler::VERSION[0] == "2" ? "Bundler version #{Bundler::VERSION}" : Bundler::VERSION) + end + private def lockfile_bundled_with(version) diff --git a/struct.c b/struct.c index 93053f0ad5a289..c47d8d086bf619 100644 --- a/struct.c +++ b/struct.c @@ -18,7 +18,6 @@ #include "internal/proc.h" #include "internal/struct.h" #include "internal/symbol.h" -#include "transient_heap.h" #include "vm_core.h" #include "builtin.h" @@ -798,39 +797,8 @@ rb_struct_initialize(VALUE self, VALUE values) static VALUE * struct_heap_alloc(VALUE st, size_t len) { - VALUE *ptr = rb_transient_heap_alloc((VALUE)st, sizeof(VALUE) * len); - - if (ptr) { - RSTRUCT_TRANSIENT_SET(st); - return ptr; - } - else { - RSTRUCT_TRANSIENT_UNSET(st); - return ALLOC_N(VALUE, len); - } -} - -#if USE_TRANSIENT_HEAP -void -rb_struct_transient_heap_evacuate(VALUE obj, int promote) -{ - if (RSTRUCT_TRANSIENT_P(obj)) { - const VALUE *old_ptr = rb_struct_const_heap_ptr(obj); - VALUE *new_ptr; - long len = RSTRUCT_LEN(obj); - - if (promote) { - new_ptr = ALLOC_N(VALUE, len); - FL_UNSET_RAW(obj, RSTRUCT_TRANSIENT_FLAG); - } - else { - new_ptr = struct_heap_alloc(obj, len); - } - MEMCPY(new_ptr, old_ptr, VALUE, len); - RSTRUCT(obj)->as.heap.ptr = new_ptr; - } + return ALLOC_N(VALUE, len); } -#endif static VALUE struct_alloc(VALUE klass) @@ -1722,6 +1690,18 @@ rb_data_s_def(int argc, VALUE *argv, VALUE klass) return data_class; } +VALUE +rb_data_define(VALUE super, ...) +{ + va_list ar; + VALUE ary; + va_start(ar, super); + ary = struct_make_members_list(ar); + va_end(ar); + if (!super) super = rb_cData; + return setup_data(anonymous_struct(super), ary); +} + /* * call-seq: * DataClass::members -> array_of_symbols diff --git a/test/-ext-/struct/test_data.rb b/test/-ext-/struct/test_data.rb new file mode 100644 index 00000000000000..8dbc9113a52b16 --- /dev/null +++ b/test/-ext-/struct/test_data.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: false +require 'test/unit' +require "-test-/struct" + +class Bug::Struct::Test_Data < Test::Unit::TestCase + def test_data_new_default + klass = Bug::Struct.data_new(false) + assert_equal Data, klass.superclass + assert_equal %i[mem1 mem2], klass.members + end + + def test_data_new_superclass + superclass = Data.define + klass = Bug::Struct.data_new(superclass) + assert_equal superclass, klass.superclass + assert_equal %i[mem1 mem2], klass.members + end +end diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb index b1557619a8445c..b28242b747be26 100644 --- a/test/bigdecimal/test_bigdecimal.rb +++ b/test/bigdecimal/test_bigdecimal.rb @@ -2275,6 +2275,12 @@ def test_reminder_infinity_gh_187 end end + def test_bsearch_for_bigdecimal + assert_raise(TypeError) { + (BigDecimal('0.5')..BigDecimal('2.25')).bsearch + } + end + def assert_no_memory_leak(code, *rest, **opt) code = "8.times {20_000.times {begin #{code}; rescue NoMemoryError; end}; GC.start}" super(["-rbigdecimal"], diff --git a/test/fiber/test_thread.rb b/test/fiber/test_thread.rb index 6fae2669555efb..5e3cc6d0e134f5 100644 --- a/test/fiber/test_thread.rb +++ b/test/fiber/test_thread.rb @@ -39,7 +39,7 @@ def test_thread_join_timeout assert_predicate sleeper, :alive? ensure - sleeper&.kill + sleeper&.kill&.join end def test_thread_join_implicit diff --git a/test/irb/yamatanooroti/test_rendering.rb b/test/irb/yamatanooroti/test_rendering.rb index 2bae7171cd76df..d2342d6a2311a6 100644 --- a/test/irb/yamatanooroti/test_rendering.rb +++ b/test/irb/yamatanooroti/test_rendering.rb @@ -8,7 +8,7 @@ return end -class IRB::TestRendering < Yamatanooroti::TestCase +class IRB::RenderingTest < Yamatanooroti::TestCase def setup @pwd = Dir.pwd suffix = '%010d' % Random.rand(0..65535) @@ -176,7 +176,7 @@ def test_symbol_with_backtick end def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_right - pend "Needs a dummy document to show doc" + omit if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.1') write_irbrc <<~'LINES' IRB.conf[:PROMPT][:MY_PROMPT] = { :PROMPT_I => "%03n> ", @@ -190,16 +190,28 @@ def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_right start_terminal(4, 19, %W{ruby -I/home/aycabta/ruby/reline/lib -I#{@pwd}/lib #{@pwd}/exe/irb}, startup_message: 'start IRB') write("Str\C-i") close - assert_screen(<<~EOC) - 001> String - StringPress A - StructString - of byte - EOC + + # This is because on macOS we display different shortcut for displaying the full doc + # 'O' is for 'Option' and 'A' is for 'Alt' + if RUBY_PLATFORM =~ /darwin/ + assert_screen(<<~EOC) + start IRB + 001> String + StringPress O + StructString + EOC + else + assert_screen(<<~EOC) + start IRB + 001> String + StringPress A + StructString + EOC + end end def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_left - pend "Needs a dummy document to show doc" + omit if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('3.1') write_irbrc <<~'LINES' IRB.conf[:PROMPT][:MY_PROMPT] = { :PROMPT_I => "%03n> ", @@ -214,10 +226,10 @@ def test_autocomplete_with_showdoc_in_gaps_on_narrow_screen_left write("Str\C-i") close assert_screen(<<~EOC) + start IRB 001> String PressString StrinStruct - of by EOC end diff --git a/test/openssl/test_pkey.rb b/test/openssl/test_pkey.rb index 2cd5290f49e515..691dd74aab5c91 100644 --- a/test/openssl/test_pkey.rb +++ b/test/openssl/test_pkey.rb @@ -109,6 +109,19 @@ def test_ed25519 assert_equal pub_pem, priv.public_to_pem assert_equal pub_pem, pub.public_to_pem + begin + assert_equal "4ccd089b28ff96da9db6c346ec114e0f5b8a319f35aba624da8cf6ed4fb8a6fb", + priv.raw_private_key.unpack1("H*") + assert_equal OpenSSL::PKey.new_raw_private_key("ED25519", priv.raw_private_key).private_to_pem, + priv.private_to_pem + assert_equal "3d4017c3e843895a92b70aa74d1b7ebc9c982ccf2ec4968cc0cd55f12af4660c", + priv.raw_public_key.unpack1("H*") + assert_equal OpenSSL::PKey.new_raw_public_key("ED25519", priv.raw_public_key).public_to_pem, + pub.public_to_pem + rescue NoMethodError + pend "running OpenSSL version does not have raw public key support" + end + sig = [<<~EOF.gsub(/[^0-9a-f]/, "")].pack("H*") 92a009a9f0d4cab8720e820b5f642540 a2b27b5416503f8fb3762223ebdb69da @@ -155,6 +168,32 @@ def test_x25519 assert_equal alice_pem, alice.private_to_pem assert_equal bob_pem, bob.public_to_pem assert_equal [shared_secret].pack("H*"), alice.derive(bob) + begin + alice_private = OpenSSL::PKey.new_raw_private_key("X25519", alice.raw_private_key) + bob_public = OpenSSL::PKey.new_raw_public_key("X25519", bob.raw_public_key) + alice_private_raw = alice.raw_private_key.unpack1("H*") + bob_public_raw = bob.raw_public_key.unpack1("H*") + rescue NoMethodError + # OpenSSL < 1.1.1 + pend "running OpenSSL version does not have raw public key support" + end + assert_equal alice_private.private_to_pem, + alice.private_to_pem + assert_equal bob_public.public_to_pem, + bob.public_to_pem + assert_equal "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a", + alice_private_raw + assert_equal "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f", + bob_public_raw + end + + def raw_initialize + pend "Ed25519 is not implemented" unless OpenSSL::OPENSSL_VERSION_NUMBER >= 0x10101000 && # >= v1.1.1 + + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("foo123", "xxx") } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_private_key("ED25519", "xxx") } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key("foo123", "xxx") } + assert_raise(OpenSSL::PKey::PKeyError) { OpenSSL::PKey.new_raw_public_key("ED25519", "xxx") } end def test_compare? diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb index 7650c68ecab6e6..640c5c6340b459 100644 --- a/test/ruby/test_gc.rb +++ b/test/ruby/test_gc.rb @@ -262,6 +262,9 @@ def test_latest_gc_info_need_major_by objects.append(100.times.map { '*' }) end + # We need to ensure that no GC gets ran before the call to GC.start since + # it would trigger a major GC. Assertions could allocate objects and + # trigger a GC so we don't run assertions until we perform the major GC. need_major_by = GC.latest_gc_info(:need_major_by) GC.start(full_mark: false) # should be upgraded to major major_by = GC.latest_gc_info(:major_by) diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb index 0a68824f11fa73..820ca9e9c23454 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -2,7 +2,6 @@ require 'test/unit' require 'delegate' require 'timeout' -require 'bigdecimal' require 'rbconfig/sizeof' class TestRange < Test::Unit::TestCase @@ -852,9 +851,6 @@ def test_bsearch_for_other_numerics assert_raise(TypeError) { (Rational(-1,2)..Rational(9,4)).bsearch } - assert_raise(TypeError) { - (BigDecimal('0.5')..BigDecimal('2.25')).bsearch - } end def test_bsearch_for_fixnum diff --git a/test/ruby/test_time.rb b/test/ruby/test_time.rb index f47a49d3e0c23b..0faad878fcf87d 100644 --- a/test/ruby/test_time.rb +++ b/test/ruby/test_time.rb @@ -75,6 +75,7 @@ def test_new_from_string Time.new("2020-12-25 00 +09:00") } + assert_equal(Time.new(2021), Time.new("2021")) assert_equal(Time.new(2021, 12, 25, in: "+09:00"), Time.new("2021-12-25+09:00")) assert_equal(0.123456r, Time.new("2021-12-25 00:00:00.123456 +09:00").subsec) @@ -138,6 +139,18 @@ def test_new_from_string assert_raise_with_message(ArgumentError, /mon out of range/) { Time.new("2020-17-25 00:56:17 +0900") } + assert_raise_with_message(ArgumentError, /no time information/) { + Time.new("2020-12") + } + assert_raise_with_message(ArgumentError, /no time information/) { + Time.new("2020-12-02") + } + assert_raise_with_message(ArgumentError, /can't parse/) { + Time.new(" 2020-12-02 00:00:00") + } + assert_raise_with_message(ArgumentError, /can't parse/) { + Time.new("2020-12-02 00:00:00 ") + } end def test_time_add() diff --git a/test/yarp/errors_test.rb b/test/yarp/errors_test.rb index 4e5f8cb9362323..03c0c7ce6482d1 100644 --- a/test/yarp/errors_test.rb +++ b/test/yarp/errors_test.rb @@ -426,9 +426,14 @@ def test_bad_arguments expected = DefNode( Location(), nil, - ParametersNode([], [], [], nil, [], nil, nil), - nil, - [], + ParametersNode([ + RequiredParameterNode(:A), + RequiredParameterNode(:@a), + RequiredParameterNode(:$A), + RequiredParameterNode(:@@a), + ], [], [], nil, [], nil, nil), + nil, + [:A, :@a, :$A, :@@a], Location(), nil, Location(), diff --git a/test/yarp/library_symbols_test.rb b/test/yarp/library_symbols_test.rb new file mode 100644 index 00000000000000..276b42a0280b51 --- /dev/null +++ b/test/yarp/library_symbols_test.rb @@ -0,0 +1,101 @@ +# frozen_string_literal: true + +require "yarp_test_helper" + +if RUBY_PLATFORM =~ /linux/ + # + # examine a yarp dll or static archive for expected external symbols. + # these tests only work on a linux system right now. + # + class LibrarySymbolsTest < Test::Unit::TestCase + def setup + super + + @librubyparser_a = File.expand_path(File.join(__dir__, "..", "build", "librubyparser.a")) + @librubyparser_so = File.expand_path(File.join(__dir__, "..", "build", "librubyparser.so")) + @yarp_so = File.expand_path(File.join(__dir__, "..", "lib", "yarp.so")) + end + + # objdump runner and helpers + def objdump(path) + assert_path_exist(path) + %x(objdump --section=.text --syms #{path}).split("\n") + end + + def global_objdump_symbols(path) + objdump(path).select { |line| line[17] == "g" } + end + + def hidden_global_objdump_symbols(path) + global_objdump_symbols(path).select { |line| line =~ / \.hidden / } + end + + def visible_global_objdump_symbols(path) + global_objdump_symbols(path).reject { |line| line =~ / \.hidden / } + end + + # nm runner and helpers + def nm(path) + assert_path_exist(path) + %x(nm #{path}).split("\n") + end + + def global_nm_symbols(path) + nm(path).select { |line| line[17] == "T" } + end + + def local_nm_symbols(path) + nm(path).select { |line| line[17] == "t" } + end + + # dig the symbol name out of each line. works for both `objdump` and `nm` output. + def names(symbol_lines) + symbol_lines.map { |line| line.split(/\s+/).last } + end + + # + # static archive - librubyparser.a + # + def test_librubyparser_a_contains_nothing_globally_visible + omit("librubyparser.a is not built") unless File.exist?(@librubyparser_a) + + assert_empty(names(visible_global_objdump_symbols(@librubyparser_a))) + end + + def test_librubyparser_a_contains_hidden_yp_symbols + omit("librubyparser.a is not built") unless File.exist?(@librubyparser_a) + + names(hidden_global_objdump_symbols(@librubyparser_a)).tap do |symbols| + assert_includes(symbols, "yp_parse") + assert_includes(symbols, "yp_version") + end + end + + # + # shared object - librubyparser.so + # + def test_librubyparser_so_exports_only_the_necessary_functions + omit("librubyparser.so is not built") unless File.exist?(@librubyparser_so) + + names(global_nm_symbols(@librubyparser_so)).tap do |symbols| + assert_includes(symbols, "yp_parse") + assert_includes(symbols, "yp_version") + end + names(local_nm_symbols(@librubyparser_so)).tap do |symbols| + assert_includes(symbols, "yp_encoding_shift_jis_isupper_char") + end + # TODO: someone who uses this library needs to finish this test + end + + # + # shared object - yarp.so + # + def test_yarp_so_exports_only_the_C_extension_init_function + omit("yarp.so is not built") unless File.exist?(@yarp_so) + + names(global_nm_symbols(@yarp_so)).tap do |symbols| + assert_equal(["Init_yarp"], symbols) + end + end + end +end diff --git a/thread.c b/thread.c index 1686a8fbf72c69..2618d95b976c37 100644 --- a/thread.c +++ b/thread.c @@ -590,7 +590,7 @@ thread_do_start_proc(rb_thread_t *th) if (args_len < 8) { /* free proc.args if the length is enough small */ args_ptr = ALLOCA_N(VALUE, args_len); - MEMCPY((VALUE *)args_ptr, RARRAY_CONST_PTR_TRANSIENT(args), VALUE, args_len); + MEMCPY((VALUE *)args_ptr, RARRAY_CONST_PTR(args), VALUE, args_len); th->invoke_arg.proc.args = Qnil; } else { diff --git a/thread_sync.c b/thread_sync.c index cbcb7c2eaf500f..85ebec4d8cfc3d 100644 --- a/thread_sync.c +++ b/thread_sync.c @@ -846,8 +846,8 @@ queue_closed_result(VALUE self, struct rb_queue *q) * information must be exchanged safely between multiple threads. The * Thread::Queue class implements all the required locking semantics. * - * The class implements FIFO type of queue. In a FIFO queue, the first - * tasks added are the first retrieved. + * The class implements FIFO (first in, first out) type of queue. + * In a FIFO queue, the first tasks added are the first retrieved. * * Example: * @@ -855,17 +855,17 @@ queue_closed_result(VALUE self, struct rb_queue *q) * * producer = Thread.new do * 5.times do |i| - * sleep rand(i) # simulate expense - * queue << i - * puts "#{i} produced" + * sleep rand(i) # simulate expense + * queue << i + * puts "#{i} produced" * end * end * * consumer = Thread.new do * 5.times do |i| - * value = queue.pop - * sleep rand(i/2) # simulate expense - * puts "consumed #{value}" + * value = queue.pop + * sleep rand(i/2) # simulate expense + * puts "consumed #{value}" * end * end * diff --git a/time.c b/time.c index d3eb4be682f6f0..f4faaf3fcf11a3 100644 --- a/time.c +++ b/time.c @@ -2545,7 +2545,9 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone, size_t ndigits; size_t prec = NIL_P(precision) ? SIZE_MAX : NUM2SIZET(precision); - while ((ptr < end) && ISSPACE(*ptr)) ptr++; + if ((ptr < end) && (ISSPACE(*ptr) || ISSPACE(*(end-1)))) { + rb_raise(rb_eArgError, "can't parse: %+"PRIsVALUE, str); + } year = parse_int(ptr, end, &ptr, &ndigits, true); if (NIL_P(year)) { rb_raise(rb_eArgError, "can't parse: %+"PRIsVALUE, str); @@ -2553,6 +2555,9 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone, else if (ndigits < 4) { rb_raise(rb_eArgError, "year must be 4 or more digits: %.*s", (int)ndigits, ptr - ndigits); } + else if (ptr == end) { + goto only_year; + } do { #define peekable_p(n) ((ptrdiff_t)(n) < (end - ptr)) #define peek_n(c, n) (peekable_p(n) && ((unsigned char)ptr[n] == (c))) @@ -2613,6 +2618,9 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone, if (zend > zstr) { zone = rb_str_subseq(str, zstr - begin, zend - zstr); } + else if (hour == -1) { + rb_raise(rb_eArgError, "no time information"); + } if (!NIL_P(subsec)) { /* subseconds is the last using ndigits */ static const size_t TIME_SCALE_NUMDIGITS = @@ -2629,6 +2637,9 @@ time_init_parse(rb_execution_context_t *ec, VALUE klass, VALUE str, VALUE zone, } } +only_year: + ; + struct vtm vtm = { .wday = VTM_WDAY_INITVAL, .yday = 0, diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb index 17b3ed5177bdbf..e5dec182220dd3 100755 --- a/tool/sync_default_gems.rb +++ b/tool/sync_default_gems.rb @@ -443,6 +443,7 @@ def sync_default_gems(gem) def message_filter(repo, sha, input: ARGF) log = input.read log.delete!("\r") + log << "\n" if !log.end_with?("\n") repo_url = "https://github.com/#{repo}" subject, log = log.split(/\n(?:[ \t]*(?:\n|\z))/, 2) conv = proc do |s| diff --git a/transient_heap.c b/transient_heap.c deleted file mode 100644 index 2e2b5d92f32d61..00000000000000 --- a/transient_heap.c +++ /dev/null @@ -1,1000 +0,0 @@ -/********************************************************************** - - transient_heap.c - implement transient_heap. - - Copyright (C) 2018 Koichi Sasada - -**********************************************************************/ - -#include "debug_counter.h" -#include "internal.h" -#include "internal/array.h" -#include "internal/gc.h" -#include "internal/sanitizers.h" -#include "internal/static_assert.h" -#include "internal/struct.h" -#include "internal/variable.h" -#include "ruby/debug.h" -#include "ruby/ruby.h" -#include "ruby_assert.h" -#include "transient_heap.h" -#include "vm_debug.h" -#include "vm_sync.h" - -#if USE_TRANSIENT_HEAP /* USE_TRANSIENT_HEAP */ -/* - * 1: enable assertions - * 2: enable verify all transient heaps - */ -#ifndef TRANSIENT_HEAP_CHECK_MODE -#define TRANSIENT_HEAP_CHECK_MODE 0 -#endif -#define TH_ASSERT(expr) RUBY_ASSERT_MESG_WHEN(TRANSIENT_HEAP_CHECK_MODE > 0, expr, #expr) - -/* - * 1: show events - * 2: show dump at events - * 3: show all operations - */ -#define TRANSIENT_HEAP_DEBUG 0 - -/* For Debug: Provide blocks infinitely. - * This mode generates blocks unlimitedly - * and prohibit access free'ed blocks to check invalid access. - */ -#define TRANSIENT_HEAP_DEBUG_INFINITE_BLOCK 0 - -#if TRANSIENT_HEAP_DEBUG_INFINITE_BLOCK -#include -#include -#endif - -/* For Debug: Prohibit promoting to malloc space. - */ -#define TRANSIENT_HEAP_DEBUG_DONT_PROMOTE 0 - -/* size configuration */ -#define TRANSIENT_HEAP_PROMOTED_DEFAULT_SIZE 1024 - - /* K M */ -#define TRANSIENT_HEAP_BLOCK_SIZE (1024 * 32 ) /* 32KB int16_t */ -#ifndef TRANSIENT_HEAP_TOTAL_SIZE -#define TRANSIENT_HEAP_TOTAL_SIZE (1024 * 1024 * 32) /* 32 MB */ -#endif -#define TRANSIENT_HEAP_ALLOC_MAX (1024 * 2 ) /* 2 KB */ -#define TRANSIENT_HEAP_BLOCK_NUM (TRANSIENT_HEAP_TOTAL_SIZE / TRANSIENT_HEAP_BLOCK_SIZE) -#define TRANSIENT_HEAP_USABLE_SIZE (TRANSIENT_HEAP_BLOCK_SIZE - sizeof(struct transient_heap_block_header)) - -#define TRANSIENT_HEAP_ALLOC_MAGIC 0xfeab -#define TRANSIENT_HEAP_ALLOC_ALIGN RUBY_ALIGNOF(void *) - -#define TRANSIENT_HEAP_ALLOC_MARKING_LAST -1 -#define TRANSIENT_HEAP_ALLOC_MARKING_FREE -2 - -enum transient_heap_status { - transient_heap_none, - transient_heap_marking, - transient_heap_escaping -}; - -struct transient_heap_block { - struct transient_heap_block_header { - int16_t index; - int16_t last_marked_index; - int16_t objects; - struct transient_heap_block *next_block; - } info; - char buff[TRANSIENT_HEAP_USABLE_SIZE]; -}; - -struct transient_heap { - struct transient_heap_block *using_blocks; - struct transient_heap_block *marked_blocks; - struct transient_heap_block *free_blocks; - int total_objects; - int total_marked_objects; - int total_blocks; - enum transient_heap_status status; - - VALUE *promoted_objects; - int promoted_objects_size; - int promoted_objects_index; - - struct transient_heap_block *arena; - int arena_index; /* increment only */ - - rb_nativethread_lock_t theap_lock; - int marking_count; -}; - -struct transient_alloc_header { - uint16_t magic; - uint16_t size; - int16_t next_marked_index; - int16_t dummy; - VALUE obj; -}; - -static struct transient_heap global_transient_heap; - -static void transient_heap_promote_add(struct transient_heap* theap, VALUE obj); -static const void *transient_heap_ptr(VALUE obj, int error); -static int transient_header_managed_ptr_p(struct transient_heap* theap, const void *ptr); - -#define ROUND_UP(v, a) (((size_t)(v) + (a) - 1) & ~((a) - 1)) - -static void -transient_heap_block_dump(struct transient_heap* theap, struct transient_heap_block *block) -{ - int i=0, n=0; - - while (iinfo.index) { - void *ptr = &block->buff[i]; - struct transient_alloc_header *header = ptr; - fprintf(stderr, "%4d %8d %p size:%4d next:%4d %s\n", n, i, ptr, header->size, header->next_marked_index, rb_obj_info(header->obj)); - i += header->size; - n++; - } -} - -static void -transient_heap_blocks_dump(struct transient_heap* theap, struct transient_heap_block *block, const char *type_str) -{ - while (block) { - fprintf(stderr, "- transient_heap_dump: %s:%p index:%d objects:%d last_marked_index:%d next:%p\n", - type_str, (void *)block, block->info.index, block->info.objects, block->info.last_marked_index, (void *)block->info.next_block); - - transient_heap_block_dump(theap, block); - block = block->info.next_block; - } -} - -static void -transient_heap_dump(struct transient_heap* theap) -{ - fprintf(stderr, "transient_heap_dump objects:%d marked_objects:%d blocks:%d\n", theap->total_objects, theap->total_marked_objects, theap->total_blocks); - transient_heap_blocks_dump(theap, theap->using_blocks, "using_blocks"); - transient_heap_blocks_dump(theap, theap->marked_blocks, "marked_blocks"); - transient_heap_blocks_dump(theap, theap->free_blocks, "free_blocks"); -} - -/* Debug: dump all transient_heap blocks */ -void -rb_transient_heap_dump(void) -{ - transient_heap_dump(&global_transient_heap); -} - -#if TRANSIENT_HEAP_CHECK_MODE >= 2 -ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static void transient_heap_ptr_check(struct transient_heap *theap, VALUE obj)); -static void -transient_heap_ptr_check(struct transient_heap *theap, VALUE obj) -{ - if (!UNDEF_P(obj)) { - const void *ptr = transient_heap_ptr(obj, FALSE); - TH_ASSERT(ptr == NULL || transient_header_managed_ptr_p(theap, ptr)); - } -} - -ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static int transient_heap_block_verify(struct transient_heap *theap, struct transient_heap_block *block)); -static int -transient_heap_block_verify(struct transient_heap *theap, struct transient_heap_block *block) -{ - int i=0, n=0; - struct transient_alloc_header *header; - - while (iinfo.index) { - header = (void *)&block->buff[i]; - TH_ASSERT(header->magic == TRANSIENT_HEAP_ALLOC_MAGIC); - transient_heap_ptr_check(theap, header->obj); - n ++; - i += header->size; - } - TH_ASSERT(block->info.objects == n); - - return n; -} - -static int -transient_heap_blocks_verify(struct transient_heap *theap, struct transient_heap_block *blocks, int *block_num_ptr) -{ - int n = 0; - struct transient_heap_block *block = blocks; - while (block) { - n += transient_heap_block_verify(theap, block); - *block_num_ptr += 1; - block = block->info.next_block; - } - - return n; -} -#endif - -static void -transient_heap_verify(struct transient_heap *theap) -{ -#if TRANSIENT_HEAP_CHECK_MODE >= 2 - int n=0, block_num=0; - - n += transient_heap_blocks_verify(theap, theap->using_blocks, &block_num); - n += transient_heap_blocks_verify(theap, theap->marked_blocks, &block_num); - - TH_ASSERT(n == theap->total_objects); - TH_ASSERT(n >= theap->total_marked_objects); - TH_ASSERT(block_num == theap->total_blocks); -#endif -} - -/* Debug: check assertions for all transient_heap blocks */ -void -rb_transient_heap_verify(void) -{ - transient_heap_verify(&global_transient_heap); -} - -static struct transient_heap* -transient_heap_get(void) -{ - struct transient_heap* theap = &global_transient_heap; - transient_heap_verify(theap); - return theap; -} - -static void -reset_block(struct transient_heap_block *block) -{ - __msan_allocated_memory(block, sizeof block); - block->info.index = 0; - block->info.objects = 0; - block->info.last_marked_index = TRANSIENT_HEAP_ALLOC_MARKING_LAST; - block->info.next_block = NULL; - __asan_poison_memory_region(&block->buff, sizeof block->buff); -} - -static void -connect_to_free_blocks(struct transient_heap *theap, struct transient_heap_block *block) -{ - block->info.next_block = theap->free_blocks; - theap->free_blocks = block; -} - -static void -connect_to_using_blocks(struct transient_heap *theap, struct transient_heap_block *block) -{ - block->info.next_block = theap->using_blocks; - theap->using_blocks = block; -} - -#if 0 -static void -connect_to_marked_blocks(struct transient_heap *theap, struct transient_heap_block *block) -{ - block->info.next_block = theap->marked_blocks; - theap->marked_blocks = block; -} -#endif - -static void -append_to_marked_blocks(struct transient_heap *theap, struct transient_heap_block *append_blocks) -{ - if (theap->marked_blocks) { - struct transient_heap_block *block = theap->marked_blocks, *last_block = NULL; - while (block) { - last_block = block; - block = block->info.next_block; - } - - TH_ASSERT(last_block->info.next_block == NULL); - last_block->info.next_block = append_blocks; - } - else { - theap->marked_blocks = append_blocks; - } -} - -static struct transient_heap_block * -transient_heap_block_alloc(struct transient_heap* theap) -{ - struct transient_heap_block *block; -#if TRANSIENT_HEAP_DEBUG_INFINITE_BLOCK - block = mmap(NULL, TRANSIENT_HEAP_BLOCK_SIZE, PROT_READ | PROT_WRITE, - MAP_PRIVATE | MAP_ANONYMOUS, - -1, 0); - if (block == MAP_FAILED) rb_bug("transient_heap_block_alloc: err:%d", errno); -#else - if (theap->arena == NULL) { - theap->arena = rb_aligned_malloc(TRANSIENT_HEAP_BLOCK_SIZE, TRANSIENT_HEAP_TOTAL_SIZE); - if (theap->arena == NULL) { - rb_bug("transient_heap_block_alloc: failed"); - } - } - - TH_ASSERT(theap->arena_index < TRANSIENT_HEAP_BLOCK_NUM); - block = &theap->arena[theap->arena_index++]; - TH_ASSERT(((intptr_t)block & (TRANSIENT_HEAP_BLOCK_SIZE - 1)) == 0); -#endif - reset_block(block); - - TH_ASSERT(((intptr_t)block->buff & (TRANSIENT_HEAP_ALLOC_ALIGN-1)) == 0); - if (0) fprintf(stderr, "transient_heap_block_alloc: %4d %p\n", theap->total_blocks, (void *)block); - return block; -} - - -static struct transient_heap_block * -transient_heap_allocatable_block(struct transient_heap* theap) -{ - struct transient_heap_block *block; - -#if TRANSIENT_HEAP_DEBUG_INFINITE_BLOCK - block = transient_heap_block_alloc(theap); - theap->total_blocks++; -#else - /* get one block from free_blocks */ - block = theap->free_blocks; - if (block) { - theap->free_blocks = block->info.next_block; - block->info.next_block = NULL; - theap->total_blocks++; - } -#endif - - return block; -} - -static struct transient_alloc_header * -transient_heap_allocatable_header(struct transient_heap* theap, size_t size) -{ - struct transient_heap_block *block = theap->using_blocks; - - while (block) { - TH_ASSERT(block->info.index <= (int16_t)TRANSIENT_HEAP_USABLE_SIZE); - - if (TRANSIENT_HEAP_USABLE_SIZE - block->info.index >= size) { - struct transient_alloc_header *header = (void *)&block->buff[block->info.index]; - block->info.index += size; - block->info.objects++; - return header; - } - else { - block = transient_heap_allocatable_block(theap); - if (block) connect_to_using_blocks(theap, block); - } - } - - return NULL; -} - -void * -rb_transient_heap_alloc(VALUE obj, size_t req_size) -{ - // only on single main ractor - if (ruby_single_main_ractor == NULL) return NULL; - - void *ret; - struct transient_heap* theap = transient_heap_get(); - size_t size = ROUND_UP(req_size + sizeof(struct transient_alloc_header), TRANSIENT_HEAP_ALLOC_ALIGN); - - TH_ASSERT(RB_TYPE_P(obj, T_ARRAY) || - RB_TYPE_P(obj, T_OBJECT) || - RB_TYPE_P(obj, T_STRUCT)); /* supported types */ - - if (size > TRANSIENT_HEAP_ALLOC_MAX) { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [too big: %ld] %s\n", (long)size, rb_obj_info(obj)); - ret = NULL; - } -#if TRANSIENT_HEAP_DEBUG_DONT_PROMOTE == 0 - else if (RB_OBJ_PROMOTED_RAW(obj)) { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [promoted object] %s\n", rb_obj_info(obj)); - ret = NULL; - } -#else - else if (RBASIC_CLASS(obj) == 0) { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [hidden object] %s\n", rb_obj_info(obj)); - ret = NULL; - } -#endif - else { - struct transient_alloc_header *header = transient_heap_allocatable_header(theap, size); - if (header) { - void *ptr; - - /* header is poisoned to prevent buffer overflow, should - * unpoison first... */ - asan_unpoison_memory_region(header, sizeof *header, true); - - header->size = size; - header->magic = TRANSIENT_HEAP_ALLOC_MAGIC; - header->next_marked_index = TRANSIENT_HEAP_ALLOC_MARKING_FREE; - header->obj = obj; /* TODO: can we eliminate it? */ - - /* header is fixed; shall poison again */ - asan_poison_memory_region(header, sizeof *header); - ptr = header + 1; - - theap->total_objects++; /* statistics */ - -#if TRANSIENT_HEAP_DEBUG_DONT_PROMOTE - if (RB_OBJ_PROMOTED_RAW(obj)) { - transient_heap_promote_add(theap, obj); - } -#endif - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: header:%p ptr:%p size:%d obj:%s\n", (void *)header, ptr, (int)size, rb_obj_info(obj)); - - RB_DEBUG_COUNTER_INC(theap_alloc); - - /* ptr is set up; OK to unpoison. */ - asan_unpoison_memory_region(ptr, size - sizeof *header, true); - ret = ptr; - } - else { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_alloc: [no enough space: %ld] %s\n", (long)size, rb_obj_info(obj)); - RB_DEBUG_COUNTER_INC(theap_alloc_fail); - ret = NULL; - } - } - - return ret; -} - -void -Init_TransientHeap(void) -{ - int i, block_num; - struct transient_heap* theap = transient_heap_get(); - -#if TRANSIENT_HEAP_DEBUG_INFINITE_BLOCK - block_num = 0; -#else - TH_ASSERT(TRANSIENT_HEAP_BLOCK_SIZE * TRANSIENT_HEAP_BLOCK_NUM == TRANSIENT_HEAP_TOTAL_SIZE); - block_num = TRANSIENT_HEAP_BLOCK_NUM; -#endif - for (i=0; iusing_blocks = transient_heap_allocatable_block(theap); - - theap->promoted_objects_size = TRANSIENT_HEAP_PROMOTED_DEFAULT_SIZE; - theap->promoted_objects_index = 0; - /* should not use ALLOC_N to be free from GC */ - theap->promoted_objects = malloc(sizeof(VALUE) * theap->promoted_objects_size); - STATIC_ASSERT( - integer_overflow, - sizeof(VALUE) <= SIZE_MAX / TRANSIENT_HEAP_PROMOTED_DEFAULT_SIZE); - if (theap->promoted_objects == NULL) rb_bug("Init_TransientHeap: malloc failed."); - - rb_nativethread_lock_initialize(&theap->theap_lock); - theap->marking_count = 0; -} - -static struct transient_heap_block * -blocks_alloc_header_to_block(struct transient_heap *theap, struct transient_heap_block *blocks, struct transient_alloc_header *header) -{ - struct transient_heap_block *block = blocks; - - while (block) { - if (block->buff <= (char *)header && (char *)header < block->buff + TRANSIENT_HEAP_USABLE_SIZE) { - return block; - } - block = block->info.next_block; - } - - return NULL; -} - -static struct transient_heap_block * -alloc_header_to_block_verbose(struct transient_heap *theap, struct transient_alloc_header *header) -{ - struct transient_heap_block *block; - - if ((block = blocks_alloc_header_to_block(theap, theap->marked_blocks, header)) != NULL) { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "alloc_header_to_block: found in marked_blocks\n"); - return block; - } - else if ((block = blocks_alloc_header_to_block(theap, theap->using_blocks, header)) != NULL) { - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "alloc_header_to_block: found in using_blocks\n"); - return block; - } - else { - return NULL; - } -} - -static struct transient_alloc_header * -ptr_to_alloc_header(const void *ptr) -{ - struct transient_alloc_header *header = (void *)ptr; - header -= 1; - return header; -} - -static int -transient_header_managed_ptr_p(struct transient_heap* theap, const void *ptr) -{ - if (alloc_header_to_block_verbose(theap, ptr_to_alloc_header(ptr))) { - return TRUE; - } - else { - return FALSE; - } -} - - -int -rb_transient_heap_managed_ptr_p(const void *ptr) -{ - return transient_header_managed_ptr_p(transient_heap_get(), ptr); -} - -static struct transient_heap_block * -alloc_header_to_block(struct transient_heap *theap, struct transient_alloc_header *header) -{ - struct transient_heap_block *block; -#if TRANSIENT_HEAP_DEBUG_INFINITE_BLOCK - block = alloc_header_to_block_verbose(theap, header); - if (block == NULL) { - transient_heap_dump(theap); - rb_bug("alloc_header_to_block: not found in mark_blocks (%p)", header); - } -#else - block = (void *)((intptr_t)header & ~(TRANSIENT_HEAP_BLOCK_SIZE-1)); - TH_ASSERT(block == alloc_header_to_block_verbose(theap, header)); -#endif - return block; -} - -void -rb_transient_heap_mark(VALUE obj, const void *ptr) -{ - struct transient_alloc_header *header = ptr_to_alloc_header(ptr); - asan_unpoison_memory_region(header, sizeof *header, false); - if (header->magic != TRANSIENT_HEAP_ALLOC_MAGIC) rb_bug("rb_transient_heap_mark: wrong header, %s (%p)", rb_obj_info(obj), ptr); - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_mark: %s (%p)\n", rb_obj_info(obj), ptr); - -#if TRANSIENT_HEAP_CHECK_MODE > 0 - { - struct transient_heap* theap = transient_heap_get(); - rb_native_mutex_lock(&theap->theap_lock); - ASSERT_ractor_safe_gc_state(); - TH_ASSERT(theap->status == transient_heap_marking); - TH_ASSERT(transient_header_managed_ptr_p(theap, ptr)); - - if (header->magic != TRANSIENT_HEAP_ALLOC_MAGIC) { - transient_heap_dump(theap); - rb_bug("rb_transient_heap_mark: magic is broken"); - } - else if (header->obj != obj) { - // transient_heap_dump(theap); - rb_bug("rb_transient_heap_mark: unmatch (%s is stored, but %s is given)", - rb_obj_info(header->obj), rb_obj_info(obj)); - } - rb_native_mutex_unlock(&theap->theap_lock); - } -#endif - - if (header->next_marked_index != TRANSIENT_HEAP_ALLOC_MARKING_FREE) { - /* already marked */ - return; - } - else { - struct transient_heap* theap = transient_heap_get(); - rb_native_mutex_lock(&theap->theap_lock); - struct transient_heap_block *block = alloc_header_to_block(theap, header); - __asan_unpoison_memory_region(&block->info, sizeof block->info); - header->next_marked_index = block->info.last_marked_index; - block->info.last_marked_index = (int)((char *)header - block->buff); - theap->total_marked_objects++; - - transient_heap_verify(theap); - rb_native_mutex_unlock(&theap->theap_lock); - } -} - -ATTRIBUTE_NO_ADDRESS_SAFETY_ANALYSIS(static const void *transient_heap_ptr(VALUE obj, int error)); -static const void * -transient_heap_ptr(VALUE obj, int error) -{ - const void *ptr = NULL; - - switch (BUILTIN_TYPE(obj)) { - case T_ARRAY: - if (RARRAY_TRANSIENT_P(obj)) { - TH_ASSERT(!ARY_EMBED_P(obj)); - ptr = RARRAY(obj)->as.heap.ptr; - } - break; - case T_OBJECT: - if (ROBJ_TRANSIENT_P(obj)) { - RUBY_ASSERT(!rb_shape_obj_too_complex(obj)); - ptr = ROBJECT_IVPTR(obj); - } - break; - case T_STRUCT: - if (RSTRUCT_TRANSIENT_P(obj)) { - ptr = rb_struct_const_heap_ptr(obj); - } - break; - default: - if (error) { - rb_bug("transient_heap_ptr: unknown obj %s", rb_obj_info(obj)); - } - } - - return ptr; -} - -static void -transient_heap_promote_add(struct transient_heap* theap, VALUE obj) -{ - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, "rb_transient_heap_promote: %s\n", rb_obj_info(obj)); - - if (TRANSIENT_HEAP_DEBUG_DONT_PROMOTE) { - /* duplicate check */ - int i; - for (i=0; ipromoted_objects_index; i++) { - if (theap->promoted_objects[i] == obj) return; - } - } - - if (theap->promoted_objects_size <= theap->promoted_objects_index) { - theap->promoted_objects_size *= 2; - if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "rb_transient_heap_promote: expand table to %d\n", theap->promoted_objects_size); - if (UNLIKELY((size_t)theap->promoted_objects_size > SIZE_MAX / sizeof(VALUE))) { - /* realloc failure due to integer overflow */ - theap->promoted_objects = NULL; - } - else { - theap->promoted_objects = realloc(theap->promoted_objects, theap->promoted_objects_size * sizeof(VALUE)); - } - if (theap->promoted_objects == NULL) rb_bug("rb_transient_heap_promote: realloc failed"); - } - theap->promoted_objects[theap->promoted_objects_index++] = obj; -} - -void -rb_transient_heap_promote(VALUE obj) -{ - if (transient_heap_ptr(obj, FALSE)) { - struct transient_heap* theap = transient_heap_get(); - rb_native_mutex_lock(&theap->theap_lock); - ASSERT_ractor_safe_gc_state(); - transient_heap_promote_add(theap, obj); - rb_native_mutex_unlock(&theap->theap_lock); - } - else { - /* ignore */ - } -} - -static struct transient_alloc_header * -alloc_header(struct transient_heap_block* block, int index) -{ - return (void *)&block->buff[index]; -} - -static void -transient_heap_reset(void) -{ - struct transient_heap* theap = transient_heap_get(); - struct transient_heap_block* block; - - if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! transient_heap_reset\n"); - - block = theap->marked_blocks; - while (block) { - struct transient_heap_block *next_block = block->info.next_block; - theap->total_objects -= block->info.objects; -#if TRANSIENT_HEAP_DEBUG_INFINITE_BLOCK - if (madvise(block, TRANSIENT_HEAP_BLOCK_SIZE, MADV_DONTNEED) != 0) { - rb_bug("madvise err:%d", errno); - } - if (mprotect(block, TRANSIENT_HEAP_BLOCK_SIZE, PROT_NONE) != 0) { - rb_bug("mprotect err:%d", errno); - } -#else - reset_block(block); - connect_to_free_blocks(theap, block); -#endif - theap->total_blocks--; - block = next_block; - } - - if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! transient_heap_reset block_num:%d\n", theap->total_blocks); - - theap->marked_blocks = NULL; - theap->total_marked_objects = 0; -} - -static void -transient_heap_block_evacuate(struct transient_heap* theap, struct transient_heap_block* block) -{ - int marked_index = block->info.last_marked_index; - block->info.last_marked_index = TRANSIENT_HEAP_ALLOC_MARKING_LAST; - - while (marked_index >= 0) { - struct transient_alloc_header *header = alloc_header(block, marked_index); - asan_unpoison_memory_region(header, sizeof *header, true); - VALUE obj = header->obj; - TH_ASSERT(header->magic == TRANSIENT_HEAP_ALLOC_MAGIC); - if (header->magic != TRANSIENT_HEAP_ALLOC_MAGIC) rb_bug("transient_heap_block_evacuate: wrong header %p %s", (void *)header, rb_obj_info(obj)); - - if (TRANSIENT_HEAP_DEBUG >= 3) fprintf(stderr, " * transient_heap_block_evacuate %p %s\n", (void *)header, rb_obj_info(obj)); - - if (obj != Qnil) { - RB_DEBUG_COUNTER_INC(theap_evacuate); - - switch (BUILTIN_TYPE(obj)) { - case T_ARRAY: - rb_ary_transient_heap_evacuate(obj, !TRANSIENT_HEAP_DEBUG_DONT_PROMOTE); - break; - case T_OBJECT: - rb_obj_transient_heap_evacuate(obj, !TRANSIENT_HEAP_DEBUG_DONT_PROMOTE); - break; - case T_STRUCT: - rb_struct_transient_heap_evacuate(obj, !TRANSIENT_HEAP_DEBUG_DONT_PROMOTE); - break; - default: - rb_bug("unsupported: %s", rb_obj_info(obj)); - } - header->obj = Qundef; /* for debug */ - } - marked_index = header->next_marked_index; - asan_poison_memory_region(header, sizeof *header); - } -} - -#if USE_RUBY_DEBUG_LOG -static const char * -transient_heap_status_cstr(enum transient_heap_status status) -{ - switch (status) { - case transient_heap_none: return "none"; - case transient_heap_marking: return "marking"; - case transient_heap_escaping: return "escaping"; - } - UNREACHABLE_RETURN(NULL); -} -#endif - -static void -transient_heap_update_status(struct transient_heap* theap, enum transient_heap_status status) -{ - RUBY_DEBUG_LOG("%s -> %s", - transient_heap_status_cstr(theap->status), - transient_heap_status_cstr(status)); - - TH_ASSERT(theap->status != status); - theap->status = status; -} - -static void -transient_heap_evacuate(void *dmy) -{ - struct transient_heap* theap = transient_heap_get(); - - if (theap->total_marked_objects == 0) return; - if (ruby_single_main_ractor == NULL) rb_bug("not single ractor mode"); - if (theap->status == transient_heap_marking) { - if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! transient_heap_evacuate: skip while transient_heap_marking\n"); - } - else { - VALUE gc_disabled = rb_gc_disable_no_rest(); - { - struct transient_heap_block* block; - - RUBY_DEBUG_LOG("start gc_disabled:%d", RTEST(gc_disabled)); - - if (TRANSIENT_HEAP_DEBUG >= 1) { - int i; - fprintf(stderr, "!! transient_heap_evacuate start total_blocks:%d\n", theap->total_blocks); - if (TRANSIENT_HEAP_DEBUG >= 4) { - for (i=0; ipromoted_objects_index; i++) fprintf(stderr, "%4d %s\n", i, rb_obj_info(theap->promoted_objects[i])); - } - } - if (TRANSIENT_HEAP_DEBUG >= 2) transient_heap_dump(theap); - - TH_ASSERT(theap->status == transient_heap_none); - transient_heap_update_status(theap, transient_heap_escaping); - - /* evacuate from marked blocks */ - block = theap->marked_blocks; - while (block) { - transient_heap_block_evacuate(theap, block); - block = block->info.next_block; - } - - /* evacuate from using blocks - only affect incremental marking */ - block = theap->using_blocks; - while (block) { - transient_heap_block_evacuate(theap, block); - block = block->info.next_block; - } - - ASSERT_vm_locking(); - - /* all objects in marked_objects are escaped. */ - transient_heap_reset(); - - if (TRANSIENT_HEAP_DEBUG > 0) { - fprintf(stderr, "!! transient_heap_evacuate end total_blocks:%d\n", theap->total_blocks); - } - - transient_heap_verify(theap); - transient_heap_update_status(theap, transient_heap_none); - } - if (gc_disabled != Qtrue) rb_gc_enable(); - RUBY_DEBUG_LOG("finish"); - } -} - -void -rb_transient_heap_evacuate(void) -{ - transient_heap_evacuate(NULL); -} - -static void -clear_marked_index(struct transient_heap_block* block) -{ - int marked_index = block->info.last_marked_index; - - while (marked_index != TRANSIENT_HEAP_ALLOC_MARKING_LAST) { - struct transient_alloc_header *header = alloc_header(block, marked_index); - /* header is poisoned to prevent buffer overflow, should - * unpoison first... */ - asan_unpoison_memory_region(header, sizeof *header, false); - TH_ASSERT(marked_index != TRANSIENT_HEAP_ALLOC_MARKING_FREE); - if (0) fprintf(stderr, "clear_marked_index - block:%p mark_index:%d\n", (void *)block, marked_index); - - marked_index = header->next_marked_index; - header->next_marked_index = TRANSIENT_HEAP_ALLOC_MARKING_FREE; - } - - block->info.last_marked_index = TRANSIENT_HEAP_ALLOC_MARKING_LAST; -} - -static void -blocks_clear_marked_index(struct transient_heap_block* block) -{ - while (block) { - clear_marked_index(block); - block = block->info.next_block; - } -} - -static void -transient_heap_block_update_refs(struct transient_heap* theap, struct transient_heap_block* block) -{ - int marked_index = block->info.last_marked_index; - - while (marked_index >= 0) { - struct transient_alloc_header *header = alloc_header(block, marked_index); - - asan_unpoison_memory_region(header, sizeof *header, false); - - header->obj = rb_gc_location(header->obj); - - marked_index = header->next_marked_index; - asan_poison_memory_region(header, sizeof *header); - } -} - -static void -transient_heap_blocks_update_refs(struct transient_heap* theap, struct transient_heap_block *block, const char *type_str) -{ - while (block) { - transient_heap_block_update_refs(theap, block); - block = block->info.next_block; - } -} - -void -rb_transient_heap_update_references(void) -{ - struct transient_heap* theap = transient_heap_get(); - rb_native_mutex_lock(&theap->theap_lock); - ASSERT_ractor_safe_gc_state(); - - int i; - - transient_heap_blocks_update_refs(theap, theap->using_blocks, "using_blocks"); - transient_heap_blocks_update_refs(theap, theap->marked_blocks, "marked_blocks"); - - for (i=0; ipromoted_objects_index; i++) { - VALUE obj = theap->promoted_objects[i]; - theap->promoted_objects[i] = rb_gc_location(obj); - } - rb_native_mutex_unlock(&theap->theap_lock); -} - -void -rb_transient_heap_start_marking(int full_marking) -{ - RUBY_DEBUG_LOG("full?:%d", full_marking); - - struct transient_heap* theap = transient_heap_get(); - - rb_native_mutex_lock(&theap->theap_lock); - theap->marking_count++; - if (theap->marking_count != 1) { - rb_native_mutex_unlock(&theap->theap_lock); - return; - } - - if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "!! rb_transient_heap_start_marking objects:%d blocks:%d promoted:%d full_marking:%d\n", - theap->total_objects, theap->total_blocks, theap->promoted_objects_index, full_marking); - if (TRANSIENT_HEAP_DEBUG >= 2) transient_heap_dump(theap); - - blocks_clear_marked_index(theap->marked_blocks); - blocks_clear_marked_index(theap->using_blocks); - - if (theap->using_blocks) { - if (theap->using_blocks->info.objects > 0) { - append_to_marked_blocks(theap, theap->using_blocks); - theap->using_blocks = NULL; - } - else { - append_to_marked_blocks(theap, theap->using_blocks->info.next_block); - theap->using_blocks->info.next_block = NULL; - } - } - - if (theap->using_blocks == NULL) { - theap->using_blocks = transient_heap_allocatable_block(theap); - } - - TH_ASSERT(theap->status == transient_heap_none); - transient_heap_update_status(theap, transient_heap_marking); - theap->total_marked_objects = 0; - - if (full_marking) { - theap->promoted_objects_index = 0; - } - else { /* mark promoted objects */ - int i; - for (i=0; ipromoted_objects_index; i++) { - VALUE obj = theap->promoted_objects[i]; - const void *ptr = transient_heap_ptr(obj, TRUE); - if (ptr) { - rb_transient_heap_mark(obj, ptr); - } - } - } - - transient_heap_verify(theap); - rb_native_mutex_unlock(&theap->theap_lock); -} - -void -rb_transient_heap_finish_marking(void) -{ - struct transient_heap* theap = transient_heap_get(); - rb_native_mutex_lock(&theap->theap_lock); - ASSERT_ractor_safe_gc_state(); - - RUBY_DEBUG_LOG("objects:%d, marked:%d", - theap->total_objects, - theap->total_marked_objects); - if (TRANSIENT_HEAP_DEBUG >= 2) transient_heap_dump(theap); - - TH_ASSERT(theap->total_objects >= theap->total_marked_objects); - - theap->marking_count--; - if (theap->marking_count == 0) { - TH_ASSERT(theap->status == transient_heap_marking); - transient_heap_update_status(theap, transient_heap_none); - } - - if (theap->total_marked_objects > 0) { - if (TRANSIENT_HEAP_DEBUG >= 1) fprintf(stderr, "-> rb_transient_heap_finish_marking register escape func.\n"); - rb_postponed_job_register_one(0, transient_heap_evacuate, NULL); - } - else { - transient_heap_reset(); - } - - transient_heap_verify(theap); - rb_native_mutex_unlock(&theap->theap_lock); -} -#endif /* USE_TRANSIENT_HEAP */ diff --git a/transient_heap.h b/transient_heap.h deleted file mode 100644 index 6c6141f71a6b9a..00000000000000 --- a/transient_heap.h +++ /dev/null @@ -1,63 +0,0 @@ -#ifndef RUBY_TRANSIENT_HEAP_H -#define RUBY_TRANSIENT_HEAP_H -/********************************************************************** - - transient_heap.h - declarations of transient_heap related APIs. - - Copyright (C) 2018 Koichi Sasada - -**********************************************************************/ - -#include "internal.h" - -#if USE_TRANSIENT_HEAP - -/* public API */ - -/* Allocate req_size bytes from transient_heap. - Allocated memories are free-ed when next GC - if this memory is not marked by `rb_transient_heap_mark()`. - */ -void *rb_transient_heap_alloc(VALUE obj, size_t req_size); - -/* If `obj` uses a memory pointed by `ptr` from transient_heap, - you need to call `rb_transient_heap_mark(obj, ptr)` - to assert liveness of `obj` (and ptr). */ -void rb_transient_heap_mark(VALUE obj, const void *ptr); - -/* used by gc.c */ -void rb_transient_heap_promote(VALUE obj); -void rb_transient_heap_start_marking(int full_marking); -void rb_transient_heap_finish_marking(void); -void rb_transient_heap_update_references(void); - -/* used by ractor.c */ -void rb_transient_heap_evacuate(void); - -/* for debug API */ -void rb_transient_heap_dump(void); -void rb_transient_heap_verify(void); -int rb_transient_heap_managed_ptr_p(const void *ptr); - -/* evacuate functions for each type */ -void rb_ary_transient_heap_evacuate(VALUE ary, int promote); -void rb_obj_transient_heap_evacuate(VALUE obj, int promote); -void rb_struct_transient_heap_evacuate(VALUE st, int promote); - -#else /* USE_TRANSIENT_HEAP */ - -#define rb_transient_heap_alloc(o, s) NULL -#define rb_transient_heap_verify() ((void)0) -#define rb_transient_heap_promote(obj) ((void)0) -#define rb_transient_heap_start_marking(full_marking) ((void)0) -#define rb_transient_heap_update_references() ((void)0) -#define rb_transient_heap_evacuate() ((void)0) -#define rb_transient_heap_finish_marking() ((void)0) -#define rb_transient_heap_mark(obj, ptr) ((void)0) - -#define rb_ary_transient_heap_evacuate(x, y) ((void)0) -#define rb_obj_transient_heap_evacuate(x, y) ((void)0) -#define rb_struct_transient_heap_evacuate(x, y) ((void)0) - -#endif /* USE_TRANSIENT_HEAP */ -#endif diff --git a/util.c b/util.c index 74f2d11b94fd25..1030c3ecbede16 100644 --- a/util.c +++ b/util.c @@ -203,22 +203,15 @@ ruby_strtoul(const char *str, char **endptr, int base) } } +#if !defined HAVE_GNU_QSORT_R #include -#include +#include #ifdef HAVE_UNISTD_H #include #endif -#if defined(HAVE_FCNTL_H) -#include -#endif - -#ifndef S_ISDIR -# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) -#endif typedef int (cmpfunc_t)(const void*, const void*, void*); -#if !defined HAVE_GNU_QSORT_R #if defined HAVE_QSORT_S && defined RUBY_MSVCRT_VERSION /* In contrast to its name, Visual Studio qsort_s is incompatible with * C11 in the order of the comparison function's arguments, and same diff --git a/variable.c b/variable.c index 200eabf3ababff..0122fa446bde7a 100644 --- a/variable.c +++ b/variable.c @@ -33,7 +33,6 @@ #include "ruby/encoding.h" #include "ruby/st.h" #include "ruby/util.h" -#include "transient_heap.h" #include "shape.h" #include "symbol.h" #include "variable.h" @@ -1441,67 +1440,18 @@ generic_ivar_set(VALUE obj, ID id, VALUE val) static VALUE * obj_ivar_heap_alloc(VALUE obj, size_t newsize) { - VALUE *newptr = rb_transient_heap_alloc(obj, sizeof(VALUE) * newsize); - - if (newptr != NULL) { - ROBJ_TRANSIENT_SET(obj); - } - else { - ROBJ_TRANSIENT_UNSET(obj); - newptr = ALLOC_N(VALUE, newsize); - } - return newptr; + return ALLOC_N(VALUE, newsize); } static VALUE * obj_ivar_heap_realloc(VALUE obj, int32_t len, size_t newsize) { - VALUE *newptr; - int i; - - if (ROBJ_TRANSIENT_P(obj)) { - const VALUE *orig_ptr = ROBJECT(obj)->as.heap.ivptr; - newptr = obj_ivar_heap_alloc(obj, newsize); - - assert(newptr); - ROBJECT(obj)->as.heap.ivptr = newptr; - for (i=0; i<(int)len; i++) { - newptr[i] = orig_ptr[i]; - } - } - else { - REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize); - newptr = ROBJECT(obj)->as.heap.ivptr; - } + REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize); + VALUE *newptr = ROBJECT(obj)->as.heap.ivptr; return newptr; } -#if USE_TRANSIENT_HEAP -void -rb_obj_transient_heap_evacuate(VALUE obj, int promote) -{ - if (ROBJ_TRANSIENT_P(obj)) { - assert(!RB_FL_TEST_RAW(obj, ROBJECT_EMBED)); - - uint32_t len = ROBJECT_IV_CAPACITY(obj); - RUBY_ASSERT(!rb_shape_obj_too_complex(obj)); - const VALUE *old_ptr = ROBJECT_IVPTR(obj); - VALUE *new_ptr; - - if (promote) { - new_ptr = ALLOC_N(VALUE, len); - ROBJ_TRANSIENT_UNSET(obj); - } - else { - new_ptr = obj_ivar_heap_alloc(obj, len); - } - MEMCPY(new_ptr, old_ptr, VALUE, len); - ROBJECT(obj)->as.heap.ivptr = new_ptr; - } -} -#endif - void rb_ensure_iv_list_size(VALUE obj, uint32_t current_capacity, uint32_t new_capacity) { @@ -1617,10 +1567,7 @@ rb_obj_ivar_set(VALUE obj, ID id, VALUE val) rb_shape_set_too_complex(obj); RUBY_ASSERT(rb_shape_obj_too_complex(obj)); - if (ROBJ_TRANSIENT_P(obj)) { - ROBJ_TRANSIENT_UNSET(obj); - } - else if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) { + if (!(RBASIC(obj)->flags & ROBJECT_EMBED)) { xfree(ROBJECT(obj)->as.heap.ivptr); } diff --git a/vm_args.c b/vm_args.c index 6832849e1ece1a..677f37c55a069b 100644 --- a/vm_args.c +++ b/vm_args.c @@ -165,7 +165,7 @@ args_copy(struct args_info *args) static inline const VALUE * args_rest_argv(struct args_info *args) { - return RARRAY_CONST_PTR_TRANSIENT(args->rest) + args->rest_index; + return RARRAY_CONST_PTR(args->rest) + args->rest_index; } static inline VALUE @@ -230,7 +230,7 @@ args_setup_post_parameters(struct args_info *args, int argc, VALUE *locals) { long len; len = RARRAY_LEN(args->rest); - MEMCPY(locals, RARRAY_CONST_PTR_TRANSIENT(args->rest) + len - argc, VALUE, argc); + MEMCPY(locals, RARRAY_CONST_PTR(args->rest) + len - argc, VALUE, argc); rb_ary_resize(args->rest, len - argc); } @@ -251,7 +251,7 @@ args_setup_opt_parameters(struct args_info *args, int opt_max, VALUE *locals) if (args->rest) { int len = RARRAY_LENINT(args->rest); - const VALUE *argv = RARRAY_CONST_PTR_TRANSIENT(args->rest); + const VALUE *argv = RARRAY_CONST_PTR(args->rest); for (; irest_index < len; i++, args->rest_index++) { locals[i] = argv[args->rest_index]; diff --git a/vm_eval.c b/vm_eval.c index 4fe1520d8677ee..7c2ca04cef481a 100644 --- a/vm_eval.c +++ b/vm_eval.c @@ -1102,7 +1102,7 @@ rb_apply(VALUE recv, ID mid, VALUE args) return ret; } argv = ALLOCA_N(VALUE, argc); - MEMCPY(argv, RARRAY_CONST_PTR_TRANSIENT(args), VALUE, argc); + MEMCPY(argv, RARRAY_CONST_PTR(args), VALUE, argc); return rb_funcallv(recv, mid, argc, argv); } diff --git a/vm_exec.c b/vm_exec.c index 441a95db48b1b1..1a4e0ad514e092 100644 --- a/vm_exec.c +++ b/vm_exec.c @@ -11,6 +11,11 @@ #include +#if USE_YJIT +// The number of instructions executed on vm_exec_core. --yjit-stats uses this. +uint64_t rb_vm_insns_count = 0; +#endif + #if VM_COLLECT_USAGE_DETAILS static void vm_analysis_insn(int insn); #endif @@ -39,18 +44,6 @@ static void vm_analysis_insn(int insn); static VALUE vm_exec_core(rb_execution_context_t *ec, VALUE initial) { - -#if OPT_STACK_CACHING -#if 0 -#elif __GNUC__ && __x86_64__ - DECL_SC_REG(VALUE, a, "12"); - DECL_SC_REG(VALUE, b, "13"); -#else - register VALUE reg_a; - register VALUE reg_b; -#endif -#endif - #if defined(__GNUC__) && defined(__i386__) DECL_SC_REG(const VALUE *, pc, "di"); DECL_SC_REG(rb_control_frame_t *, cfp, "si"); diff --git a/vm_insnhelper.c b/vm_insnhelper.c index f60a7c4ee2bc36..9a96fc3b93f132 100644 --- a/vm_insnhelper.c +++ b/vm_insnhelper.c @@ -1874,7 +1874,7 @@ vm_expandarray(VALUE *sp, VALUE ary, rb_num_t num, int flag) len = 1; } else { - ptr = RARRAY_CONST_PTR_TRANSIENT(ary); + ptr = RARRAY_CONST_PTR(ary); len = (rb_num_t)RARRAY_LEN(ary); } @@ -2564,7 +2564,7 @@ vm_caller_setup_arg_splat(rb_control_frame_t *cfp, struct rb_calling_info *calli bool ret = false; if (!NIL_P(ary)) { - const VALUE *ptr = RARRAY_CONST_PTR_TRANSIENT(ary); + const VALUE *ptr = RARRAY_CONST_PTR(ary); long len = RARRAY_LEN(ary); int argc = calling->argc; diff --git a/vm_insnhelper.h b/vm_insnhelper.h index ac60c40ef52c36..66895cd142d514 100644 --- a/vm_insnhelper.h +++ b/vm_insnhelper.h @@ -20,30 +20,29 @@ RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state; # define RJIT_STATS RUBY_DEBUG #endif +#if USE_YJIT // We want vm_insns_count on any YJIT-enabled build +// Increment vm_insns_count for --yjit-stats. We increment this even when +// --yjit or --yjit-stats is not used because branching to skip it is slower. +// We also don't use ATOMIC_INC for performance, allowing inaccuracy on Ractors. +#define YJIT_COLLECT_USAGE_INSN(insn) rb_vm_insns_count++ +#else +#define YJIT_COLLECT_USAGE_INSN(insn) // none +#endif + +#if RJIT_STATS +#define RJIT_COLLECT_USAGE_INSN(insn) rb_rjit_collect_vm_usage_insn(insn) +#else +#define RJIT_COLLECT_USAGE_INSN(insn) // none +#endif + #if VM_COLLECT_USAGE_DETAILS #define COLLECT_USAGE_INSN(insn) vm_collect_usage_insn(insn) #define COLLECT_USAGE_OPERAND(insn, n, op) vm_collect_usage_operand((insn), (n), ((VALUE)(op))) - #define COLLECT_USAGE_REGISTER(reg, s) vm_collect_usage_register((reg), (s)) -#elif RJIT_STATS && YJIT_STATS -// Both flags could be enabled at the same time. You need to call both in that case. -#define COLLECT_USAGE_INSN(insn) rb_rjit_collect_vm_usage_insn(insn); rb_yjit_collect_vm_usage_insn(insn) -#define COLLECT_USAGE_OPERAND(insn, n, op) /* none */ -#define COLLECT_USAGE_REGISTER(reg, s) /* none */ -#elif RJIT_STATS -// for --rjit-stats -#define COLLECT_USAGE_INSN(insn) rb_rjit_collect_vm_usage_insn(insn) -#define COLLECT_USAGE_OPERAND(insn, n, op) /* none */ -#define COLLECT_USAGE_REGISTER(reg, s) /* none */ -#elif YJIT_STATS -/* for --yjit-stats */ -#define COLLECT_USAGE_INSN(insn) rb_yjit_collect_vm_usage_insn(insn) -#define COLLECT_USAGE_OPERAND(insn, n, op) /* none */ -#define COLLECT_USAGE_REGISTER(reg, s) /* none */ #else -#define COLLECT_USAGE_INSN(insn) /* none */ -#define COLLECT_USAGE_OPERAND(insn, n, op) /* none */ -#define COLLECT_USAGE_REGISTER(reg, s) /* none */ +#define COLLECT_USAGE_INSN(insn) YJIT_COLLECT_USAGE_INSN(insn); RJIT_COLLECT_USAGE_INSN(insn) +#define COLLECT_USAGE_OPERAND(insn, n, op) // none +#define COLLECT_USAGE_REGISTER(reg, s) // none #endif /**********************************************************/ diff --git a/yarp/defines.h b/yarp/defines.h index e6a90bb51876ad..5dba303a3d3023 100644 --- a/yarp/defines.h +++ b/yarp/defines.h @@ -12,11 +12,9 @@ #include // YP_EXPORTED_FUNCTION -#if defined(YP_STATIC) -# define YP_EXPORTED_FUNCTION -#elif defined(_WIN32) +#if defined(_WIN32) # define YP_EXPORTED_FUNCTION __declspec(dllexport) extern -#else +#elif defined(YP_EXPORT_SYMBOLS) # ifndef YP_EXPORTED_FUNCTION # ifndef RUBY_FUNC_EXPORTED # define YP_EXPORTED_FUNCTION __attribute__((__visibility__("default"))) extern @@ -24,6 +22,8 @@ # define YP_EXPORTED_FUNCTION RUBY_FUNC_EXPORTED # endif # endif +#else +# define YP_EXPORTED_FUNCTION #endif // YP_ATTRIBUTE_UNUSED diff --git a/yarp/yarp.c b/yarp/yarp.c index 97b698279d98bd..8e920b3571a825 100644 --- a/yarp/yarp.c +++ b/yarp/yarp.c @@ -3412,7 +3412,6 @@ yp_required_destructured_parameter_node_closing_set(yp_required_destructured_par // Allocate a new RequiredParameterNode node. static yp_required_parameter_node_t * yp_required_parameter_node_create(yp_parser_t *parser, const yp_token_t *token) { - assert(token->type == YP_TOKEN_MISSING || token->type == YP_TOKEN_IDENTIFIER); yp_required_parameter_node_t *node = YP_ALLOC_NODE(parser, yp_required_parameter_node_t); *node = (yp_required_parameter_node_t) { @@ -8244,8 +8243,27 @@ parse_parameters( } break; } - case YP_TOKEN_IDENTIFIER: { + case YP_TOKEN_CLASS_VARIABLE: + case YP_TOKEN_IDENTIFIER: + case YP_TOKEN_CONSTANT: + case YP_TOKEN_INSTANCE_VARIABLE: + case YP_TOKEN_GLOBAL_VARIABLE: { parser_lex(parser); + switch (parser->previous.type) { + case YP_TOKEN_CONSTANT: + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a constant"); + break; + case YP_TOKEN_INSTANCE_VARIABLE: + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be an instance variable"); + break; + case YP_TOKEN_GLOBAL_VARIABLE: + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a global variable"); + break; + case YP_TOKEN_CLASS_VARIABLE: + yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a class variable"); + break; + default: break; + } if (parser->current.type == YP_TOKEN_EQUAL) { update_parameter_state(parser, &parser->current, &order); @@ -8387,22 +8405,6 @@ parse_parameters( yp_parameters_node_keyword_rest_set(params, param); break; } - case YP_TOKEN_CONSTANT: - parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a constant"); - break; - case YP_TOKEN_INSTANCE_VARIABLE: - parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be an instance variable"); - break; - case YP_TOKEN_GLOBAL_VARIABLE: - parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a global variable"); - break; - case YP_TOKEN_CLASS_VARIABLE: - parser_lex(parser); - yp_diagnostic_list_append(&parser->error_list, parser->previous.start, parser->previous.end, "Formal argument cannot be a class variable"); - break; default: if (parser->previous.type == YP_TOKEN_COMMA) { if (allows_trailing_comma) { @@ -8427,6 +8429,13 @@ parse_parameters( } while (looping && accept(parser, YP_TOKEN_COMMA)); yp_do_loop_stack_pop(parser); + + // If we don't have any parameters, return `NULL` instead of an empty `ParametersNode`. + if (params->base.location.start == params->base.location.end) { + yp_node_destroy(parser, (yp_node_t *) params); + return NULL; + } + return params; } diff --git a/yjit.h b/yjit.h index a640d5982abb45..a76dc6a850badc 100644 --- a/yjit.h +++ b/yjit.h @@ -30,7 +30,6 @@ bool rb_yjit_compile_new_iseqs(void); unsigned rb_yjit_call_threshold(void); void rb_yjit_invalidate_all_method_lookup_assumptions(void); void rb_yjit_cme_invalidate(rb_callable_method_entry_t *cme); -void rb_yjit_collect_vm_usage_insn(int insn); void rb_yjit_collect_binding_alloc(void); void rb_yjit_collect_binding_set(void); bool rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec); @@ -53,7 +52,6 @@ static inline bool rb_yjit_compile_new_iseqs(void) { return false; } static inline unsigned rb_yjit_call_threshold(void) { return UINT_MAX; } static inline void rb_yjit_invalidate_all_method_lookup_assumptions(void) {} static inline void rb_yjit_cme_invalidate(rb_callable_method_entry_t *cme) {} -static inline void rb_yjit_collect_vm_usage_insn(int insn) {} static inline void rb_yjit_collect_binding_alloc(void) {} static inline void rb_yjit_collect_binding_set(void) {} static inline bool rb_yjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec) { return false; } diff --git a/yjit.rb b/yjit.rb index dc4699c7e64273..06a3fd5e145c36 100644 --- a/yjit.rb +++ b/yjit.rb @@ -167,14 +167,11 @@ def self.runtime_stats(context: false) # Average length of instruction sequences executed by YJIT avg_len_in_yjit = total_exits > 0 ? retired_in_yjit.to_f / total_exits : 0 - # This only available on yjit stats builds - if stats.key?(:vm_insns_count) - # Proportion of instructions that retire in YJIT - total_insns_count = retired_in_yjit + stats[:vm_insns_count] - yjit_ratio_pct = 100.0 * retired_in_yjit.to_f / total_insns_count - stats[:total_insns_count] = total_insns_count - stats[:ratio_in_yjit] = yjit_ratio_pct - end + # Proportion of instructions that retire in YJIT + total_insns_count = retired_in_yjit + stats[:vm_insns_count] + yjit_ratio_pct = 100.0 * retired_in_yjit.to_f / total_insns_count + stats[:total_insns_count] = total_insns_count + stats[:ratio_in_yjit] = yjit_ratio_pct # Make those stats available in RubyVM::YJIT.runtime_stats as well stats[:side_exit_count] = side_exits @@ -318,14 +315,10 @@ def _print_stats(out: $stderr) # :nodoc: out.puts "object_shape_count: " + format_number(13, stats[:object_shape_count]) out.puts "side_exit_count: " + format_number(13, stats[:side_exit_count]) out.puts "total_exit_count: " + format_number(13, stats[:total_exit_count]) - out.puts "total_insns_count: " + format_number(13, stats[:total_insns_count]) if stats.key?(:total_insns_count) - if stats.key?(:vm_insns_count) - out.puts "vm_insns_count: " + format_number(13, stats[:vm_insns_count]) - end + out.puts "total_insns_count: " + format_number(13, stats[:total_insns_count]) + out.puts "vm_insns_count: " + format_number(13, stats[:vm_insns_count]) out.puts "yjit_insns_count: " + format_number(13, stats[:exec_instruction]) - if stats.key?(:ratio_in_yjit) - out.puts "ratio_in_yjit: " + ("%12.1f" % stats[:ratio_in_yjit]) + "%" - end + out.puts "ratio_in_yjit: " + ("%12.1f" % stats[:ratio_in_yjit]) + "%" out.puts "avg_len_in_yjit: " + ("%13.1f" % stats[:avg_len_in_yjit]) print_sorted_exit_counts(stats, out: out, prefix: "exit_") diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs index b9bef8e1768b68..30b4c8b5d7bdf1 100644 --- a/yjit/bindgen/src/main.rs +++ b/yjit/bindgen/src/main.rs @@ -357,6 +357,9 @@ fn main() { .allowlist_function("rb_ivar_defined") .allowlist_function("rb_ivar_get") + // From internal/vm.h + .allowlist_var("rb_vm_insns_count") + // From include/ruby/internal/intern/vm.h .allowlist_function("rb_get_alloc_func") diff --git a/yjit/src/codegen.rs b/yjit/src/codegen.rs index cda9c5f680ba95..d668b82301a0d1 100644 --- a/yjit/src/codegen.rs +++ b/yjit/src/codegen.rs @@ -5228,7 +5228,7 @@ fn get_array_len(asm: &mut Assembler, array_opnd: Opnd) -> Opnd { asm.csel_nz(emb_len_opnd, array_len_opnd) } -// Generate RARRAY_CONST_PTR_TRANSIENT (part of RARRAY_AREF) +// Generate RARRAY_CONST_PTR (part of RARRAY_AREF) fn get_array_ptr(asm: &mut Assembler, array_reg: Opnd) -> Opnd { asm.comment("get array pointer for embedded or heap"); diff --git a/yjit/src/core.rs b/yjit/src/core.rs index c8e17d325d079a..b5a9d692058b3f 100644 --- a/yjit/src/core.rs +++ b/yjit/src/core.rs @@ -1103,7 +1103,7 @@ pub extern "C" fn rb_yjit_iseq_free(payload: *mut c_void) { incr_counter!(freed_iseq_count); } -/// GC callback for marking GC objects in the the per-iseq payload. +/// GC callback for marking GC objects in the per-iseq payload. #[no_mangle] pub extern "C" fn rb_yjit_iseq_mark(payload: *mut c_void) { let payload = if payload.is_null() { @@ -1166,7 +1166,7 @@ pub extern "C" fn rb_yjit_iseq_mark(payload: *mut c_void) { } } -/// GC callback for updating GC objects in the the per-iseq payload. +/// GC callback for updating GC objects in the per-iseq payload. /// This is a mirror of [rb_yjit_iseq_mark]. #[no_mangle] pub extern "C" fn rb_yjit_iseq_update_references(payload: *mut c_void) { @@ -2954,7 +2954,7 @@ pub fn invalidate_block_version(blockref: &BlockRef) { // Get a pointer to the generated code for this block let block_start = block.start_addr; - // Make the the start of the block do an exit. This handles OOM situations + // Make the start of the block do an exit. This handles OOM situations // and some cases where we can't efficiently patch incoming branches. // Do this first, since in case there is a fallthrough branch into this // block, the patching loop below can overwrite the start of the block. diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs index 553f9cdbead7f5..c27fa1f29d1c80 100644 --- a/yjit/src/cruby_bindings.inc.rs +++ b/yjit/src/cruby_bindings.inc.rs @@ -192,9 +192,8 @@ pub type ruby_value_type = u32; pub const RUBY_FL_USHIFT: ruby_fl_ushift = 12; pub type ruby_fl_ushift = u32; pub const RUBY_FL_WB_PROTECTED: ruby_fl_type = 32; -pub const RUBY_FL_PROMOTED0: ruby_fl_type = 32; -pub const RUBY_FL_PROMOTED1: ruby_fl_type = 64; -pub const RUBY_FL_PROMOTED: ruby_fl_type = 96; +pub const RUBY_FL_PROMOTED: ruby_fl_type = 32; +pub const RUBY_FL_UNUSED6: ruby_fl_type = 64; pub const RUBY_FL_FINALIZE: ruby_fl_type = 128; pub const RUBY_FL_TAINT: ruby_fl_type = 0; pub const RUBY_FL_SHAREABLE: ruby_fl_type = 256; @@ -245,7 +244,6 @@ pub type st_foreach_callback_func = ::std::option::Option< >; pub const RARRAY_EMBED_FLAG: ruby_rarray_flags = 8192; pub const RARRAY_EMBED_LEN_MASK: ruby_rarray_flags = 4161536; -pub const RARRAY_TRANSIENT_FLAG: ruby_rarray_flags = 33554432; pub type ruby_rarray_flags = u32; pub const RARRAY_EMBED_LEN_SHIFT: ruby_rarray_consts = 15; pub type ruby_rarray_consts = u32; @@ -1137,6 +1135,7 @@ extern "C" { n: ::std::os::raw::c_long, elts: *const VALUE, ) -> VALUE; + pub static mut rb_vm_insns_count: u64; pub fn rb_method_entry_at(obj: VALUE, id: ID) -> *const rb_method_entry_t; pub fn rb_callable_method_entry(klass: VALUE, id: ID) -> *const rb_callable_method_entry_t; pub fn rb_callable_method_entry_or_negative( diff --git a/yjit/src/stats.rs b/yjit/src/stats.rs index 7f1a4e3d9f4497..216c7bddc86f65 100644 --- a/yjit/src/stats.rs +++ b/yjit/src/stats.rs @@ -369,7 +369,6 @@ make_counters! { binding_allocations, binding_set, - vm_insns_count, compiled_iseq_entry, compiled_iseq_count, compiled_blockid_count, @@ -507,7 +506,6 @@ fn rb_yjit_gen_stats_dict(context: bool) -> VALUE { let hash = unsafe { rb_hash_new() }; - // CodeBlock stats unsafe { // Get the inline and outlined code blocks let cb = CodegenGlobals::get_inline_cb(); @@ -547,6 +545,9 @@ fn rb_yjit_gen_stats_dict(context: bool) -> VALUE { hash_aset_usize!(hash, "live_context_count", live_context_count); hash_aset_usize!(hash, "live_context_size", live_context_count * context_size); } + + // VM instructions count + hash_aset_usize!(hash, "vm_insns_count", rb_vm_insns_count as usize); } // If we're not generating stats, the hash is done @@ -566,13 +567,6 @@ fn rb_yjit_gen_stats_dict(context: bool) -> VALUE { let counter_ptr = get_counter_ptr(counter_name); let counter_val = *counter_ptr; - #[cfg(not(feature = "stats"))] - if counter_name == &"vm_insns_count" { - // If the stats feature is disabled, we don't have vm_insns_count - // so we are going to exclude the key - continue; - } - // Put counter into hash let key = rust_str_to_sym(counter_name); let value = VALUE::fixnum_from_usize(counter_val as usize); @@ -750,12 +744,6 @@ pub extern "C" fn rb_yjit_reset_stats_bang(_ec: EcPtr, _ruby_self: VALUE) -> VAL return Qnil; } -/// Increment the number of instructions executed by the interpreter -#[no_mangle] -pub extern "C" fn rb_yjit_collect_vm_usage_insn() { - incr_counter!(vm_insns_count); -} - #[no_mangle] pub extern "C" fn rb_yjit_collect_binding_alloc() { incr_counter!(binding_allocations); diff --git a/yjit/src/utils.rs b/yjit/src/utils.rs index 396b330abf9579..3a8f0ef590a701 100644 --- a/yjit/src/utils.rs +++ b/yjit/src/utils.rs @@ -5,7 +5,7 @@ use crate::cruby::*; use std::slice; /// Trait for casting to [usize] that allows you to say `.as_usize()`. -/// Implementation conditional on the the cast preserving the numeric value on +/// Implementation conditional on the cast preserving the numeric value on /// all inputs and being inexpensive. /// /// [usize] is only guaranteed to be more than 16-bit wide, so we can't use