mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Merge branch 'master' into feature/enumerator-lazy-peek
This commit is contained in:
commit
3a9ee4a553
141 changed files with 4446 additions and 2107 deletions
2
.github/actions/setup/directories/action.yml
vendored
2
.github/actions/setup/directories/action.yml
vendored
|
@ -93,7 +93,7 @@ runs:
|
|||
path: ${{ inputs.srcdir }}
|
||||
fetch-depth: ${{ inputs.fetch-depth }}
|
||||
|
||||
- uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
- uses: actions/cache@0400d5f644dc74513175e3cd8d07132dd4860809 # v4.2.4
|
||||
with:
|
||||
path: ${{ inputs.srcdir }}/.downloaded-cache
|
||||
key: ${{ runner.os }}-${{ runner.arch }}-downloaded-cache
|
||||
|
|
41
.github/workflows/check_misc.yml
vendored
41
.github/workflows/check_misc.yml
vendored
|
@ -61,14 +61,11 @@ jobs:
|
|||
exit $fail
|
||||
working-directory: include
|
||||
|
||||
- name: Generate docs
|
||||
id: docs
|
||||
- name: Check if to generate documents
|
||||
id: rdoc
|
||||
run: |
|
||||
$RDOC -C -x ^ext -x ^lib .
|
||||
$RDOC --op html .
|
||||
echo htmlout=ruby-html-${GITHUB_SHA:0:10} >> $GITHUB_OUTPUT
|
||||
env:
|
||||
RDOC: ruby -W0 --disable-gems tool/rdoc-srcdir -q
|
||||
ref=$(sed 's/#.*//;/^rdoc /!d' gems/bundled_gems | awk '{print $4}')
|
||||
echo ref=$ref >> $GITHUB_OUTPUT
|
||||
# Generate only when document commit/PR
|
||||
if: >-
|
||||
${{false
|
||||
|
@ -80,6 +77,36 @@ jobs:
|
|||
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
|
||||
}}
|
||||
|
||||
- name: Checkout rdoc
|
||||
uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0
|
||||
with:
|
||||
repository: ruby/rdoc
|
||||
ref: ${{ steps.rdoc.outputs.ref }}
|
||||
path: .bundle/gems/rdoc-0
|
||||
if: ${{ steps.rdoc.outputs.ref != '' }}
|
||||
|
||||
- name: Generate rdoc
|
||||
run: |
|
||||
set -x
|
||||
gempath=$(ruby -e 'print Gem.user_dir, "/bin"')
|
||||
PATH=$gempath:$PATH
|
||||
gem install --user bundler
|
||||
bundle config --local path vendor/bundle
|
||||
bundle install --jobs 4
|
||||
bundle exec rake generate
|
||||
working-directory: .bundle/gems/rdoc-0
|
||||
if: ${{ steps.rdoc.outputs.ref != '' }}
|
||||
|
||||
- name: Generate docs
|
||||
id: docs
|
||||
run: |
|
||||
$RDOC -C -x ^ext -x ^lib .
|
||||
$RDOC --op html .
|
||||
echo htmlout=ruby-html-${GITHUB_SHA:0:10} >> $GITHUB_OUTPUT
|
||||
env:
|
||||
RDOC: ruby -W0 --disable-gems tool/rdoc-srcdir -q
|
||||
if: ${{ steps.rdoc.outcome == 'success' }}
|
||||
|
||||
- name: Upload docs
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
|
|
1
.github/workflows/compilers.yml
vendored
1
.github/workflows/compilers.yml
vendored
|
@ -107,6 +107,7 @@ jobs:
|
|||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with: { sparse-checkout-cone-mode: false, sparse-checkout: /.github }
|
||||
- { uses: './.github/actions/setup/directories', with: { srcdir: 'src', builddir: 'build', makeup: true, fetch-depth: 10 } }
|
||||
- { uses: './.github/actions/compilers', name: 'clang 22', with: { tag: 'clang-22' } }
|
||||
- { uses: './.github/actions/compilers', name: 'clang 21', with: { tag: 'clang-21' } }
|
||||
- { uses: './.github/actions/compilers', name: 'clang 20', with: { tag: 'clang-20' } }
|
||||
- { uses: './.github/actions/compilers', name: 'clang 19', with: { tag: 'clang-19' } }
|
||||
|
|
105
.github/workflows/mingw.yml
vendored
105
.github/workflows/mingw.yml
vendored
|
@ -65,33 +65,88 @@ jobs:
|
|||
)}}
|
||||
|
||||
steps:
|
||||
- name: Set up Ruby & MSYS2
|
||||
uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: msys2/setup-msys2@40677d36a502eb2cf0fb808cc9dec31bf6152638 # v2.28.0
|
||||
id: msys2
|
||||
with:
|
||||
ruby-version: '3.2'
|
||||
msystem: UCRT64
|
||||
update: true
|
||||
install: >-
|
||||
git
|
||||
make
|
||||
ruby
|
||||
autoconf
|
||||
mingw-w64-ucrt-x86_64-gcc
|
||||
mingw-w64-ucrt-x86_64-ragel
|
||||
mingw-w64-ucrt-x86_64-openssl
|
||||
mingw-w64-ucrt-x86_64-libyaml
|
||||
mingw-w64-ucrt-x86_64-libffi
|
||||
|
||||
- name: Set up env
|
||||
id: setup-env
|
||||
working-directory:
|
||||
run: |
|
||||
$msys2 = ${env:MSYS2_LOCATION}
|
||||
echo $msys2\usr\bin $msys2\ucrt64\bin |
|
||||
Tee-Object ${env:GITHUB_PATH} -Append -Encoding utf-8
|
||||
|
||||
# Use the fast device for the temporary directory.
|
||||
# %TEMP% is inconsistent with %TMP% and test-all expects they are consistent.
|
||||
# https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302
|
||||
$tmp = ${env:RUNNER_TEMP}
|
||||
echo HOME=$home TMP=$tmp TEMP=$tmp TMPDIR=$tmp |
|
||||
Tee-Object ${env:GITHUB_ENV} -Append -Encoding utf-8
|
||||
shell: pwsh # cmd.exe does not strip spaces before `|`.
|
||||
env:
|
||||
MSYS2_LOCATION: ${{ steps.msys2.outputs.msys2-location }}
|
||||
|
||||
- name: Remove Strawberry Perl pkg-config
|
||||
working-directory:
|
||||
# `pkg-config.bat` included in Strawberry Perl is written in
|
||||
# Perl and doesn't work when another msys2 `perl` precede its
|
||||
# own `perl`.
|
||||
#
|
||||
# ```
|
||||
# Can't find C:\Strawberry\perl\bin\pkg-config.bat on PATH, '.' not in PATH.
|
||||
# ```
|
||||
run: |
|
||||
Get-Command pkg-config.bat | % { ren $_.path ($_.path + "~") }
|
||||
shell: pwsh
|
||||
|
||||
- name: Misc system & package info
|
||||
working-directory:
|
||||
run: |
|
||||
# show where
|
||||
result=true
|
||||
for e in gcc.exe ragel.exe make.exe libcrypto-3-x64.dll libssl-3-x64.dll; do
|
||||
echo ::group::$'\033[93m'$e$'\033[m'
|
||||
where $e || result=false
|
||||
echo ::endgroup::
|
||||
done
|
||||
# show version
|
||||
for e in gcc ragel make "openssl version"; do
|
||||
case "$e" in *" "*) ;; *) e="$e --version";; esac
|
||||
echo ::group::$'\033[93m'$e$'\033[m'
|
||||
$e || result=false
|
||||
echo ::endgroup::
|
||||
done
|
||||
# show packages
|
||||
echo ::group::$'\033[93m'Packages$'\033[m'
|
||||
pacman -Qs mingw-w64-ucrt-x86_64-* | sed -n "s,local/mingw-w64-ucrt-x86_64-,,p"
|
||||
echo ::endgroup::
|
||||
$result
|
||||
group() { echo ::group::$'\e[94;1m'"$*"$'\e[m'; }
|
||||
endgroup() { echo ::endgroup::; }
|
||||
|
||||
group Path
|
||||
cygpath -wa / . $(type -p cygpath bash sh)
|
||||
endgroup
|
||||
|
||||
I() {
|
||||
group $1
|
||||
run Where type -pa $1 && { [ $# -eq 1 ] || run Version "$@"; } ||
|
||||
failed+=($1)
|
||||
endgroup
|
||||
}
|
||||
run() { local w m=$1; shift; w="$("$@")" && show "$m" && indent "$w"; }
|
||||
indent() { [ -z "$1" ] || echo "$1" | /bin/sed '/^$/!s/^/ /'; }
|
||||
show() { echo $'\e[96m'"$*"$'\e[m'; }
|
||||
|
||||
failed=()
|
||||
|
||||
I gcc.exe --version
|
||||
I ragel.exe --version
|
||||
I make.exe --version
|
||||
I openssl.exe version
|
||||
I libcrypto-3-x64.dll
|
||||
I libssl-3-x64.dll
|
||||
|
||||
group Packages
|
||||
pacman -Qs mingw-w64-ucrt-x86_64-* | /bin/sed -n "s,local/mingw-w64-ucrt-x86_64-,,p"
|
||||
endgroup
|
||||
|
||||
[ ${#failed[@]} -eq 0 ]
|
||||
shell: sh
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
|
@ -110,6 +165,7 @@ jobs:
|
|||
run: >
|
||||
../src/configure --disable-install-doc --prefix=/.
|
||||
--build=$CHOST --host=$CHOST --target=$CHOST
|
||||
shell: sh
|
||||
|
||||
- name: make all
|
||||
timeout-minutes: 30
|
||||
|
@ -132,7 +188,6 @@ jobs:
|
|||
- name: test
|
||||
timeout-minutes: 30
|
||||
run: make test
|
||||
shell: cmd
|
||||
env:
|
||||
GNUMAKEFLAGS: ''
|
||||
RUBY_TESTOPTS: '-v --tty=no'
|
||||
|
@ -140,7 +195,6 @@ jobs:
|
|||
|
||||
- name: test-all
|
||||
timeout-minutes: 45
|
||||
shell: cmd
|
||||
run: |
|
||||
make ${{ StartsWith(matrix.test_task, 'test/') && matrix.test_task || 'test-all' }}
|
||||
env:
|
||||
|
@ -155,7 +209,6 @@ jobs:
|
|||
timeout-minutes: 10
|
||||
run: |
|
||||
make ${{ StartsWith(matrix.test_task, 'spec/') && matrix.test_task || 'test-spec' }}
|
||||
shell: cmd
|
||||
if: ${{ matrix.test_task == 'check' || matrix.test_task == 'test-spec' || StartsWith(matrix.test_task, 'spec/') }}
|
||||
|
||||
- uses: ./src/.github/actions/slack
|
||||
|
@ -167,4 +220,4 @@ jobs:
|
|||
defaults:
|
||||
run:
|
||||
working-directory: build
|
||||
shell: sh
|
||||
shell: cmd
|
||||
|
|
53
.github/workflows/rust-warnings.yml
vendored
Normal file
53
.github/workflows/rust-warnings.yml
vendored
Normal file
|
@ -0,0 +1,53 @@
|
|||
# Surface Rust warnings on PRs that touch any Rust code.
|
||||
# Not a required check so we never block people over new warnings
|
||||
# that might come from a new Rust version being released.
|
||||
name: Rust warnings
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- opened
|
||||
- synchronize
|
||||
- reopened
|
||||
paths:
|
||||
- '**.rs'
|
||||
- '!**.inc.rs'
|
||||
merge_group:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }} / ${{ startsWith(github.event_name, 'pull') && github.ref_name || github.sha }}
|
||||
cancel-in-progress: ${{ startsWith(github.event_name, 'pull') }}
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
make:
|
||||
env:
|
||||
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
|
||||
|
||||
runs-on: ubuntu-24.04
|
||||
|
||||
if: >-
|
||||
${{!(false
|
||||
|| contains(github.event.head_commit.message, '[DOC]')
|
||||
|| contains(github.event.head_commit.message, 'Document')
|
||||
|| contains(github.event.pull_request.title, '[DOC]')
|
||||
|| contains(github.event.pull_request.title, 'Document')
|
||||
|| contains(github.event.pull_request.labels.*.name, 'Documentation')
|
||||
|| (github.event_name == 'push' && github.event.pull_request.user.login == 'dependabot[bot]')
|
||||
)}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- name: Install Rust
|
||||
run: rustup default beta
|
||||
|
||||
- name: Rust warnings
|
||||
run: |
|
||||
set -euo pipefail
|
||||
cargo check --quiet --all-features --message-format=json \
|
||||
| jq -r 'select(.reason == "compiler-message" and .message.level == "warning") | .message.rendered' \
|
||||
> warnings.txt
|
||||
cat warnings.txt
|
||||
! grep --quiet '[^[:space:]]' warnings.txt
|
56
.github/workflows/ubuntu.yml
vendored
56
.github/workflows/ubuntu.yml
vendored
|
@ -24,6 +24,22 @@ jobs:
|
|||
make:
|
||||
strategy:
|
||||
matrix:
|
||||
test_task: [check]
|
||||
configure: ['']
|
||||
arch: ['']
|
||||
os:
|
||||
- ubuntu-24.04
|
||||
- ubuntu-24.04-arm
|
||||
# FIXME Comment out ppc64le due to failing tests on GitHub Actions
|
||||
# ppc64le
|
||||
# https://bugs.ruby-lang.org/issues/21534
|
||||
# - ubuntu-24.04-ppc64le
|
||||
- ubuntu-24.04-s390x
|
||||
# The ppc64le/s390x runners work only in the registered repositories.
|
||||
# They don't work in forked repositories.
|
||||
# https://github.com/IBM/actionspz/blob/main/docs/FAQ.md#what-about-forked-repos
|
||||
upstream:
|
||||
- ${{ github.repository == 'ruby/ruby' }}
|
||||
include:
|
||||
- test_task: check
|
||||
configure: 'cppflags=-DVM_CHECK_MODE'
|
||||
|
@ -36,10 +52,11 @@ jobs:
|
|||
- test_task: test-bundler-parallel
|
||||
timeout: 50
|
||||
- test_task: test-bundled-gems
|
||||
- test_task: check
|
||||
os: ubuntu-24.04
|
||||
- test_task: check
|
||||
os: ubuntu-24.04-arm
|
||||
exclude:
|
||||
- os: ubuntu-24.04-ppc64le
|
||||
upstream: false
|
||||
- os: ubuntu-24.04-s390x
|
||||
upstream: false
|
||||
fail-fast: false
|
||||
|
||||
env:
|
||||
|
@ -72,7 +89,25 @@ jobs:
|
|||
with:
|
||||
ruby-version: '3.1'
|
||||
bundler: none
|
||||
if: ${{ !endsWith(matrix.os, 'arm') }}
|
||||
if: ${{ !endsWith(matrix.os, 'arm') && !endsWith(matrix.os, 'ppc64le') && !endsWith(matrix.os, 's390x') }}
|
||||
|
||||
# Avoid possible test failures with the zlib applying the following patch
|
||||
# on s390x CPU architecture.
|
||||
# https://github.com/madler/zlib/pull/410
|
||||
- name: Disable DFLTCC
|
||||
run: echo "DFLTCC=0" >> $GITHUB_ENV
|
||||
working-directory:
|
||||
if: ${{ endsWith(matrix.os, 's390x') }}
|
||||
|
||||
# A temporary workaround: Set HOME env to pass the step
|
||||
# ./.github/actions/setup/directories.
|
||||
# https://github.com/IBM/actionspz/issues/30
|
||||
- name: Set HOME env
|
||||
run: |
|
||||
echo "HOME: #{HOME}"
|
||||
echo "HOME=$(ls -d ~)" >> $GITHUB_ENV
|
||||
working-directory:
|
||||
if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }}
|
||||
|
||||
- uses: ./.github/actions/setup/directories
|
||||
with:
|
||||
|
@ -122,6 +157,17 @@ jobs:
|
|||
continue-on-error: true
|
||||
timeout-minutes: 3
|
||||
|
||||
# A temporary workaround: Skip user ground id test
|
||||
# There is a mismatch between the group IDs of "id -g" and C function
|
||||
# getpwuid(uid_t uid) pw_gid.
|
||||
# https://github.com/IBM/actionspz/issues/31
|
||||
- name: Skip user group id test
|
||||
run: |
|
||||
sed -i.orig '/^ it "returns user group id" do/a\ skip' \
|
||||
../src/spec/ruby/library/etc/struct_passwd_spec.rb
|
||||
diff -u ../src/spec/ruby/library/etc/struct_passwd_spec.rb{.orig,} || :
|
||||
if: ${{ endsWith(matrix.os, 'ppc64le') || endsWith(matrix.os, 's390x') }}
|
||||
|
||||
- name: make ${{ matrix.test_task }}
|
||||
run: |
|
||||
test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
|
||||
|
|
6
.github/workflows/windows.yml
vendored
6
.github/workflows/windows.yml
vendored
|
@ -39,7 +39,7 @@ jobs:
|
|||
test_task: test-bundled-gems
|
||||
fail-fast: false
|
||||
|
||||
runs-on: windows-${{ matrix.os < 2022 && '2019' || matrix.os }}
|
||||
runs-on: windows-${{ matrix.os }}
|
||||
|
||||
if: >-
|
||||
${{!(false
|
||||
|
@ -94,7 +94,7 @@ jobs:
|
|||
|
||||
- name: Install libraries with vcpkg
|
||||
run: |
|
||||
vcpkg install --vcpkg-root=C:\Users\runneradmin\scoop\apps\vcpkg\current
|
||||
vcpkg install --vcpkg-root=%USERPROFILE%\scoop\apps\vcpkg\current
|
||||
working-directory: src
|
||||
|
||||
- name: Save vcpkg artifact
|
||||
|
@ -184,7 +184,7 @@ jobs:
|
|||
- name: Set up Launchable
|
||||
uses: ./.github/actions/launchable/setup
|
||||
with:
|
||||
os: windows-${{ matrix.os < 2022 && '2019' || matrix.os }}
|
||||
os: windows-${{ matrix.os }}
|
||||
launchable-token: ${{ secrets.LAUNCHABLE_TOKEN }}
|
||||
builddir: build
|
||||
srcdir: src
|
||||
|
|
10
.github/workflows/zjit-macos.yml
vendored
10
.github/workflows/zjit-macos.yml
vendored
|
@ -34,6 +34,7 @@ jobs:
|
|||
include:
|
||||
- test_task: 'zjit-check'
|
||||
configure: '--enable-yjit=dev --enable-zjit'
|
||||
rust_version: "1.85.0"
|
||||
|
||||
- test_task: 'ruby' # build test for combo build
|
||||
configure: '--enable-yjit --enable-zjit'
|
||||
|
@ -81,14 +82,17 @@ jobs:
|
|||
# Set fetch-depth: 10 so that Launchable can receive commits information.
|
||||
fetch-depth: 10
|
||||
|
||||
- name: Install Rust
|
||||
if: ${{ matrix.rust_version }}
|
||||
run: |
|
||||
rustup install ${{ matrix.rust_version }} --profile minimal
|
||||
rustup default ${{ matrix.rust_version }}
|
||||
|
||||
- uses: taiki-e/install-action@v2
|
||||
with:
|
||||
tool: nextest@0.9
|
||||
if: ${{ matrix.test_task == 'zjit-check' }}
|
||||
|
||||
- name: Install Rust # TODO(alan): remove when GitHub images catch up past 1.85.0
|
||||
run: rustup default 1.85.0
|
||||
|
||||
- name: Run configure
|
||||
run: ../src/configure -C --disable-install-doc ${{ matrix.configure }}
|
||||
|
||||
|
|
6
.github/workflows/zjit-ubuntu.yml
vendored
6
.github/workflows/zjit-ubuntu.yml
vendored
|
@ -39,6 +39,7 @@ jobs:
|
|||
|
||||
- test_task: 'zjit-check'
|
||||
configure: '--enable-yjit --enable-zjit=dev'
|
||||
rust_version: '1.85.0'
|
||||
|
||||
- test_task: 'zjit-test-all'
|
||||
configure: '--enable-zjit=dev'
|
||||
|
@ -98,7 +99,10 @@ jobs:
|
|||
fetch-depth: 10
|
||||
|
||||
- name: Install Rust
|
||||
run: rustup default 1.85.0
|
||||
if: ${{ matrix.rust_version }}
|
||||
run: |
|
||||
rustup install ${{ matrix.rust_version }} --profile minimal
|
||||
rustup default ${{ matrix.rust_version }}
|
||||
|
||||
- name: Install rustfmt
|
||||
if: ${{ matrix.test_task == 'zjit-bindgen' }}
|
||||
|
|
|
@ -19,5 +19,7 @@ autolink_excluded_words:
|
|||
- RDoc
|
||||
- Ruby
|
||||
- Set
|
||||
- ZJIT
|
||||
- YJIT
|
||||
|
||||
canonical_root: https://docs.ruby-lang.org/en/master
|
||||
|
|
12
array.c
12
array.c
|
@ -3659,9 +3659,9 @@ rb_ary_collect(VALUE ary)
|
|||
|
||||
/*
|
||||
* call-seq:
|
||||
* collect! {|element| ... } -> new_array
|
||||
* collect! {|element| ... } -> self
|
||||
* collect! -> new_enumerator
|
||||
* map! {|element| ... } -> new_array
|
||||
* map! {|element| ... } -> self
|
||||
* map! -> new_enumerator
|
||||
*
|
||||
* With a block given, calls the block with each element of +self+
|
||||
|
@ -4755,10 +4755,10 @@ rb_ary_clear(VALUE ary)
|
|||
|
||||
/*
|
||||
* call-seq:
|
||||
* fill(object, start = nil, count = nil) -> new_array
|
||||
* fill(object, range) -> new_array
|
||||
* fill(start = nil, count = nil) {|element| ... } -> new_array
|
||||
* fill(range) {|element| ... } -> new_array
|
||||
* fill(object, start = nil, count = nil) -> self
|
||||
* fill(object, range) -> self
|
||||
* fill(start = nil, count = nil) {|element| ... } -> self
|
||||
* fill(range) {|element| ... } -> self
|
||||
*
|
||||
* Replaces selected elements in +self+;
|
||||
* may add elements to +self+;
|
||||
|
|
11
ast.c
11
ast.c
|
@ -866,6 +866,17 @@ node_locations(VALUE ast_value, const NODE *node)
|
|||
location_new(&RNODE_IF(node)->if_keyword_loc),
|
||||
location_new(&RNODE_IF(node)->then_keyword_loc),
|
||||
location_new(&RNODE_IF(node)->end_keyword_loc));
|
||||
case NODE_IN:
|
||||
return rb_ary_new_from_args(4,
|
||||
location_new(nd_code_loc(node)),
|
||||
location_new(&RNODE_IN(node)->in_keyword_loc),
|
||||
location_new(&RNODE_IN(node)->then_keyword_loc),
|
||||
location_new(&RNODE_IN(node)->operator_loc));
|
||||
case NODE_MODULE:
|
||||
return rb_ary_new_from_args(3,
|
||||
location_new(nd_code_loc(node)),
|
||||
location_new(&RNODE_MODULE(node)->module_keyword_loc),
|
||||
location_new(&RNODE_MODULE(node)->end_keyword_loc));
|
||||
case NODE_NEXT:
|
||||
return rb_ary_new_from_args(2,
|
||||
location_new(nd_code_loc(node)),
|
||||
|
|
|
@ -10,7 +10,7 @@ case "$0" in
|
|||
* ) srcdir="";; # Otherwise
|
||||
esac
|
||||
|
||||
# If install-only is explicitly requested, disbale symlink flags
|
||||
# If install-only is explicitly requested, disable symlink flags
|
||||
case " $* " in
|
||||
*" -i "* | *" --install"* ) symlink_flags="" ;;
|
||||
* ) symlink_flags="--install --symlink" ;;
|
||||
|
|
|
@ -20,7 +20,9 @@ benchmark:
|
|||
casecmp-10: lstr10.casecmp(ustr10)
|
||||
casecmp-100: lstr100.casecmp(ustr100)
|
||||
casecmp-1000: lstr1000.casecmp(ustr1000)
|
||||
casecmp-1000vs10: lstr1000.casecmp(ustr10)
|
||||
casecmp-nonascii1: lnonascii1.casecmp(unonascii1)
|
||||
casecmp-nonascii10: lnonascii10.casecmp(unonascii10)
|
||||
casecmp-nonascii100: lnonascii100.casecmp(unonascii100)
|
||||
casecmp-nonascii1000: lnonascii1000.casecmp(unonascii1000)
|
||||
casecmp-nonascii1000vs10: lnonascii1000.casecmp(unonascii10)
|
||||
|
|
|
@ -1,5 +1,12 @@
|
|||
prelude: |
|
||||
C = Struct.new(:x) do
|
||||
def initialize(...)
|
||||
super
|
||||
@ivar = 42
|
||||
end
|
||||
|
||||
attr_accessor :ivar
|
||||
|
||||
class_eval <<-END
|
||||
def r
|
||||
#{'x;'*256}
|
||||
|
@ -15,11 +22,16 @@ prelude: |
|
|||
m = method(:x=)
|
||||
#{'m.call(nil);'*256}
|
||||
end
|
||||
def r_ivar
|
||||
#{'ivar;'*256}
|
||||
end
|
||||
END
|
||||
end
|
||||
C.new(nil) # ensure common shape is known
|
||||
obj = C.new(nil)
|
||||
benchmark:
|
||||
member_reader: "obj.r"
|
||||
member_writer: "obj.w"
|
||||
member_reader_method: "obj.rm"
|
||||
member_writer_method: "obj.wm"
|
||||
ivar_reader: "obj.r_ivar"
|
||||
|
|
16
common.mk
16
common.mk
|
@ -1353,11 +1353,11 @@ preludes: {$(VPATH)}miniprelude.c
|
|||
|
||||
{$(srcdir)}.rb.rbbin:
|
||||
$(ECHO) making $@
|
||||
$(Q) $(MINIRUBY) $(tooldir)/mk_rbbin.rb $< > $@
|
||||
$(Q) $(MINIRUBY) $(tooldir)/mk_rbbin.rb $(SRC_FILE) > $(OS_DEST_FILE)
|
||||
|
||||
{$(srcdir)}.rb.rbinc:
|
||||
$(ECHO) making $@
|
||||
$(Q) $(BASERUBY) $(tooldir)/mk_builtin_loader.rb $<
|
||||
$(Q) $(BASERUBY) $(tooldir)/mk_builtin_loader.rb $(SRC_FILE)
|
||||
|
||||
$(BUILTIN_BINARY:yes=built)in_binary.rbbin: $(PREP) $(BUILTIN_RB_SRCS) $(srcdir)/template/builtin_binary.rbbin.tmpl
|
||||
$(Q) $(MINIRUBY) $(tooldir)/generic_erb.rb -o $@ \
|
||||
|
@ -1539,12 +1539,14 @@ prepare-gems: $(HAVE_BASERUBY:yes=update-gems) $(HAVE_BASERUBY:yes=extract-gems)
|
|||
extract-gems: $(HAVE_BASERUBY:yes=update-gems) $(HAVE_BASERUBY:yes=outdate-bundled-gems)
|
||||
update-gems: $(HAVE_BASERUBY:yes=outdate-bundled-gems)
|
||||
|
||||
split_option = -F"\s+|$(HASH_SIGN).*"
|
||||
|
||||
update-gems$(sequential): PHONY
|
||||
$(ECHO) Downloading bundled gem files...
|
||||
$(Q) $(BASERUBY) -C "$(srcdir)" \
|
||||
-I./tool -rdownloader -answ \
|
||||
-I./tool -rdownloader $(split_option) -answ \
|
||||
-e 'gem, ver = *$$F' \
|
||||
-e 'next if !ver or /^#/=~gem' \
|
||||
-e 'next if !ver' \
|
||||
-e 'old = Dir.glob("gems/#{gem}-*.gem")' \
|
||||
-e 'gem = "#{gem}-#{ver}.gem"' \
|
||||
-e 'Downloader::RubyGems.download(gem, "gems", nil) and' \
|
||||
|
@ -1556,10 +1558,10 @@ update-gems$(sequential): PHONY
|
|||
extract-gems$(sequential): PHONY
|
||||
$(ECHO) Extracting bundled gem files...
|
||||
$(Q) $(BASERUBY) -C "$(srcdir)" \
|
||||
-Itool/lib -rfileutils -rbundled_gem -answ \
|
||||
-Itool/lib -rfileutils -rbundled_gem $(split_option) -answ \
|
||||
-e 'BEGIN {d = ".bundle/gems"}' \
|
||||
-e 'gem, ver, _, rev = *$$F' \
|
||||
-e 'next if !ver or /^#/=~gem' \
|
||||
-e 'next if !ver' \
|
||||
-e 'g = "#{gem}-#{ver}"' \
|
||||
-e 'unless File.directory?("#{d}/#{g}")' \
|
||||
-e 'if rev and File.exist?(gs = "gems/src/#{gem}/#{gem}.gemspec")' \
|
||||
|
@ -1623,7 +1625,7 @@ yes-install-for-test-bundled-gems: yes-update-default-gemspecs
|
|||
test-bundled-gems-fetch: yes-test-bundled-gems-fetch
|
||||
yes-test-bundled-gems-fetch: clone-bundled-gems-src
|
||||
clone-bundled-gems-src: PHONY
|
||||
$(Q) $(BASERUBY) -C $(srcdir)/gems ../tool/fetch-bundled_gems.rb BUNDLED_GEMS="$(BUNDLED_GEMS)" src bundled_gems
|
||||
$(Q) $(BASERUBY) -C $(srcdir) tool/fetch-bundled_gems.rb BUNDLED_GEMS="$(BUNDLED_GEMS)" gems/src gems/bundled_gems
|
||||
no-test-bundled-gems-fetch:
|
||||
|
||||
test-bundled-gems-prepare: $(TEST_RUNNABLE)-test-bundled-gems-prepare
|
||||
|
|
|
@ -309,7 +309,7 @@ HELP_EXTRA_TASKS = \
|
|||
# 4. "gem x.y.z URL" -> "gem-x.y.z"
|
||||
bundled-gems := $(shell sed \
|
||||
-e 's/[ ][ ]*/ /g' \
|
||||
-e 's/^ //;/\#/d;s/ *$$//;/^$$/d' \
|
||||
-e 's/^ //;s/\#.*//;s/ *$$//;/^$$/d' \
|
||||
$(if $(filter yes,$(HAVE_GIT)), \
|
||||
-e 's/^\(.*\) \(.*\) \(.*\) \(.*\)/\1|\2|\4|\3/' \
|
||||
) \
|
||||
|
|
9
depend
9
depend
|
@ -6065,6 +6065,7 @@ hash.$(OBJEXT): $(top_srcdir)/internal/set_table.h
|
|||
hash.$(OBJEXT): $(top_srcdir)/internal/st.h
|
||||
hash.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
|
||||
hash.$(OBJEXT): $(top_srcdir)/internal/string.h
|
||||
hash.$(OBJEXT): $(top_srcdir)/internal/struct.h
|
||||
hash.$(OBJEXT): $(top_srcdir)/internal/symbol.h
|
||||
hash.$(OBJEXT): $(top_srcdir)/internal/thread.h
|
||||
hash.$(OBJEXT): $(top_srcdir)/internal/time.h
|
||||
|
@ -6288,6 +6289,7 @@ hash.$(OBJEXT): {$(VPATH)}symbol.h
|
|||
hash.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
|
||||
hash.$(OBJEXT): {$(VPATH)}thread_native.h
|
||||
hash.$(OBJEXT): {$(VPATH)}util.h
|
||||
hash.$(OBJEXT): {$(VPATH)}variable.h
|
||||
hash.$(OBJEXT): {$(VPATH)}vm_core.h
|
||||
hash.$(OBJEXT): {$(VPATH)}vm_debug.h
|
||||
hash.$(OBJEXT): {$(VPATH)}vm_opts.h
|
||||
|
@ -12700,6 +12702,7 @@ ractor.$(OBJEXT): {$(VPATH)}vm_debug.h
|
|||
ractor.$(OBJEXT): {$(VPATH)}vm_opts.h
|
||||
ractor.$(OBJEXT): {$(VPATH)}vm_sync.h
|
||||
ractor.$(OBJEXT): {$(VPATH)}yjit.h
|
||||
ractor.$(OBJEXT): {$(VPATH)}zjit.h
|
||||
random.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
|
||||
random.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
|
||||
random.$(OBJEXT): $(CCAN_DIR)/list/list.h
|
||||
|
@ -12926,6 +12929,7 @@ range.$(OBJEXT): $(top_srcdir)/internal/enumerator.h
|
|||
range.$(OBJEXT): $(top_srcdir)/internal/error.h
|
||||
range.$(OBJEXT): $(top_srcdir)/internal/fixnum.h
|
||||
range.$(OBJEXT): $(top_srcdir)/internal/gc.h
|
||||
range.$(OBJEXT): $(top_srcdir)/internal/imemo.h
|
||||
range.$(OBJEXT): $(top_srcdir)/internal/numeric.h
|
||||
range.$(OBJEXT): $(top_srcdir)/internal/range.h
|
||||
range.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
||||
|
@ -12948,6 +12952,7 @@ range.$(OBJEXT): {$(VPATH)}config.h
|
|||
range.$(OBJEXT): {$(VPATH)}defines.h
|
||||
range.$(OBJEXT): {$(VPATH)}encoding.h
|
||||
range.$(OBJEXT): {$(VPATH)}id.h
|
||||
range.$(OBJEXT): {$(VPATH)}id_table.h
|
||||
range.$(OBJEXT): {$(VPATH)}intern.h
|
||||
range.$(OBJEXT): {$(VPATH)}internal.h
|
||||
range.$(OBJEXT): {$(VPATH)}internal/abi.h
|
||||
|
@ -15580,6 +15585,7 @@ shape.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
|||
shape.$(OBJEXT): $(top_srcdir)/internal/set_table.h
|
||||
shape.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
|
||||
shape.$(OBJEXT): $(top_srcdir)/internal/string.h
|
||||
shape.$(OBJEXT): $(top_srcdir)/internal/struct.h
|
||||
shape.$(OBJEXT): $(top_srcdir)/internal/symbol.h
|
||||
shape.$(OBJEXT): $(top_srcdir)/internal/variable.h
|
||||
shape.$(OBJEXT): $(top_srcdir)/internal/vm.h
|
||||
|
@ -16569,6 +16575,7 @@ string.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
|||
string.$(OBJEXT): $(top_srcdir)/internal/set_table.h
|
||||
string.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
|
||||
string.$(OBJEXT): $(top_srcdir)/internal/string.h
|
||||
string.$(OBJEXT): $(top_srcdir)/internal/struct.h
|
||||
string.$(OBJEXT): $(top_srcdir)/internal/transcode.h
|
||||
string.$(OBJEXT): $(top_srcdir)/internal/variable.h
|
||||
string.$(OBJEXT): $(top_srcdir)/internal/vm.h
|
||||
|
@ -16766,6 +16773,7 @@ string.$(OBJEXT): {$(VPATH)}thread.h
|
|||
string.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
|
||||
string.$(OBJEXT): {$(VPATH)}thread_native.h
|
||||
string.$(OBJEXT): {$(VPATH)}util.h
|
||||
string.$(OBJEXT): {$(VPATH)}variable.h
|
||||
string.$(OBJEXT): {$(VPATH)}vm_core.h
|
||||
string.$(OBJEXT): {$(VPATH)}vm_debug.h
|
||||
string.$(OBJEXT): {$(VPATH)}vm_opts.h
|
||||
|
@ -18103,6 +18111,7 @@ variable.$(OBJEXT): $(top_srcdir)/internal/serial.h
|
|||
variable.$(OBJEXT): $(top_srcdir)/internal/set_table.h
|
||||
variable.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
|
||||
variable.$(OBJEXT): $(top_srcdir)/internal/string.h
|
||||
variable.$(OBJEXT): $(top_srcdir)/internal/struct.h
|
||||
variable.$(OBJEXT): $(top_srcdir)/internal/symbol.h
|
||||
variable.$(OBJEXT): $(top_srcdir)/internal/thread.h
|
||||
variable.$(OBJEXT): $(top_srcdir)/internal/variable.h
|
||||
|
|
|
@ -367,11 +367,11 @@ Outstanding ones only.
|
|||
* Fiber.blocking? tells whether the current execution context is
|
||||
blocking. [[Feature #16786]]
|
||||
|
||||
* Thread
|
||||
|
||||
* Thread#join invokes the scheduler hooks `block`/`unblock` in a
|
||||
non-blocking execution context. [[Feature #16786]]
|
||||
|
||||
* Thread
|
||||
|
||||
* Thread.ignore_deadlock accessor has been added for disabling the
|
||||
default deadlock detection, allowing the use of signal handlers to
|
||||
break deadlock. [[Bug #13768]]
|
||||
|
|
|
@ -502,7 +502,7 @@ An added _quantifier_ specifies how many matches are required or allowed:
|
|||
/\w*/.match('x')
|
||||
# => #<MatchData "x">
|
||||
/\w*/.match('xyz')
|
||||
# => #<MatchData "yz">
|
||||
# => #<MatchData "xyz">
|
||||
|
||||
- <tt>+</tt> - Matches one or more times:
|
||||
|
||||
|
|
572
doc/globals.md
Normal file
572
doc/globals.md
Normal file
|
@ -0,0 +1,572 @@
|
|||
# Pre-Defined Global Variables
|
||||
|
||||
Some of the pre-defined global variables have synonyms
|
||||
that are available via module English.
|
||||
For each of those, the \English synonym is given.
|
||||
|
||||
To use the module:
|
||||
|
||||
```ruby
|
||||
require 'English'
|
||||
```
|
||||
|
||||
## Summary
|
||||
|
||||
### Exceptions
|
||||
|
||||
| Variable | English | Contains |
|
||||
|-------------|-------------------|----------------------------------------------------|
|
||||
| `$!` | `$ERROR_INFO` | Exception object; set by Kernel#raise. |
|
||||
| `$@` | `$ERROR_POSITION` | Array of backtrace positions; set by Kernel#raise. |
|
||||
|
||||
### Pattern Matching
|
||||
|
||||
| Variable | English | Contains |
|
||||
|---------------|---------------------|--------------------------------------------------|
|
||||
| `$~` | `$LAST_MATCH_INFO` | MatchData object; set by matcher method. |
|
||||
| `$&` | `$MATCH` | Matched substring; set by matcher method. |
|
||||
| `` $` `` | `$PRE_MATCH` | Substring left of match; set by matcher method. |
|
||||
| `$'` | `$POST_MATCH` | Substring right of match; set by matcher method. |
|
||||
| `$+` | `$LAST_PAREN_MATCH` | Last group matched; set by matcher method. |
|
||||
| `$1` | | First group matched; set by matcher method. |
|
||||
| `$2` | | Second group matched; set by matcher method. |
|
||||
| <tt>$_n_</tt> | | <i>n</i>th group matched; set by matcher method. |
|
||||
|
||||
### Separators
|
||||
|
||||
| Variable | English | Contains |
|
||||
|----------|----------------------------|--------------------------------------------|
|
||||
| `$/` | `$INPUT_RECORD_SEPARATOR` | Input record separator; initially newline. |
|
||||
| `$\` | `$OUTPUT_RECORD_SEPARATOR` | Output record separator; initially `nil`. |
|
||||
|
||||
### Streams
|
||||
|
||||
| Variable | English | Contains |
|
||||
|-----------|-----------------------------|-----------------------------------------------|
|
||||
| `$stdin` | | Standard input stream; initially `STDIN`. |
|
||||
| `$stdout` | | Standard input stream; initially `STDIOUT`. |
|
||||
| `$stderr` | | Standard input stream; initially `STDERR`. |
|
||||
| `$<` | `$DEFAULT_INPUT` | Default standard input; `ARGF` or `$stdin`. |
|
||||
| `$>` | `$DEFAULT_OUTPUT` | Default standard output; initially `$stdout`. |
|
||||
| `$.` | `$INPUT_LINE_NUMBER`, `$NR` | Input position of most recently read stream. |
|
||||
| `$_` | `$LAST_READ_LINE` | String from most recently read stream. |
|
||||
|
||||
### Processes
|
||||
|
||||
| Variable | English | Contains |
|
||||
|---------------------------|-----------------------|--------------------------------------------------------|
|
||||
| `$0` | | Initially, the name of the executing program. |
|
||||
| `$*` | `$ARGV` | Points to the `ARGV` array. |
|
||||
| `$$` | `$PROCESS_ID`, `$PID` | Process ID of the current process. |
|
||||
| `$?` | `$CHILD_STATUS` | Process::Status of most recently exited child process. |
|
||||
| `$LOAD_PATH`, `$:`, `$-I` | | Array of paths to be searched. |
|
||||
| `$LOADED_FEATURES`, `$"` | | Array of paths to loaded files. |
|
||||
|
||||
### Debugging
|
||||
|
||||
| Variable | English | Contains |
|
||||
|-------------|---------|--------------------------------------------------------|
|
||||
| `$FILENAME` | | The value returned by method ARGF.filename. |
|
||||
| `$DEBUG` | | Initially, whether option `-d` or `--debug` was given. |
|
||||
| `$VERBOSE` | | Initially, whether option `-V` or `-W` was given. |
|
||||
|
||||
### Other Variables
|
||||
|
||||
| Variable | English | Contains |
|
||||
|----------|---------|------------------------------------------------|
|
||||
| `$-a` | | Whether option `-a` was given. |
|
||||
| `$-i` | | Extension given with command-line option `-i`. |
|
||||
| `$-l` | | Whether option `-l` was given. |
|
||||
| `$-p` | | Whether option `-p` was given. |
|
||||
|
||||
## Exceptions
|
||||
|
||||
### `$!` (\Exception)
|
||||
|
||||
Contains the Exception object set by Kernel#raise:
|
||||
|
||||
```ruby
|
||||
begin
|
||||
raise RuntimeError.new('Boo!')
|
||||
rescue RuntimeError
|
||||
p $!
|
||||
end
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
#<RuntimeError: Boo!>
|
||||
```
|
||||
|
||||
English - `$ERROR_INFO`
|
||||
|
||||
### `$@` (Backtrace)
|
||||
|
||||
Same as `$!.backtrace`;
|
||||
returns an array of backtrace positions:
|
||||
|
||||
```ruby
|
||||
begin
|
||||
raise RuntimeError.new('Boo!')
|
||||
rescue RuntimeError
|
||||
pp $@.take(4)
|
||||
end
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
["(irb):338:in `<top (required)>'",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/irb/workspace.rb:119:in `eval'",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/irb/workspace.rb:119:in `evaluate'",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/irb/context.rb:502:in `evaluate'"]
|
||||
```
|
||||
|
||||
English - `$ERROR_POSITION`.
|
||||
|
||||
## Pattern Matching
|
||||
|
||||
These global variables store information about the most recent
|
||||
successful match in the current scope.
|
||||
|
||||
For details and examples,
|
||||
see {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
|
||||
|
||||
### `$~` (\MatchData)
|
||||
|
||||
MatchData object created from the match;
|
||||
thread-local and frame-local.
|
||||
|
||||
English - `$LAST_MATCH_INFO`.
|
||||
|
||||
### `$&` (Matched Substring)
|
||||
|
||||
The matched string.
|
||||
|
||||
English - `$MATCH`.
|
||||
|
||||
### `` $` `` (Pre-Match Substring)
|
||||
The string to the left of the match.
|
||||
|
||||
English - `$PREMATCH`.
|
||||
|
||||
### `$'` (Post-Match Substring)
|
||||
|
||||
The string to the right of the match.
|
||||
|
||||
English - `$POSTMATCH`.
|
||||
|
||||
### `$+` (Last Matched Group)
|
||||
|
||||
The last group matched.
|
||||
|
||||
English - `$LAST_PAREN_MATCH`.
|
||||
|
||||
### `$1`, `$2`, \Etc. (Matched Group)
|
||||
|
||||
For <tt>$_n_</tt> the <i>n</i>th group of the match.
|
||||
|
||||
No \English.
|
||||
|
||||
## Separators
|
||||
|
||||
### `$/` (Input Record Separator)
|
||||
|
||||
An input record separator, initially newline.
|
||||
|
||||
English - `$INPUT_RECORD_SEPARATOR`, `$RS`.
|
||||
|
||||
Aliased as `$-0`.
|
||||
|
||||
### `$\` (Output Record Separator)
|
||||
|
||||
An output record separator, initially `nil`.
|
||||
|
||||
English - `$OUTPUT_RECORD_SEPARATOR`, `$ORS`.
|
||||
|
||||
## Streams
|
||||
|
||||
### `$stdin` (Standard Input)
|
||||
|
||||
The current standard input stream; initially:
|
||||
|
||||
```ruby
|
||||
$stdin # => #<IO:<STDIN>>
|
||||
```
|
||||
|
||||
### `$stdout` (Standard Output)
|
||||
|
||||
The current standard output stream; initially:
|
||||
|
||||
```ruby
|
||||
$stdout # => #<IO:<STDOUT>>
|
||||
```
|
||||
|
||||
### `$stderr` (Standard Error)
|
||||
|
||||
The current standard error stream; initially:
|
||||
|
||||
```ruby
|
||||
$stderr # => #<IO:<STDERR>>
|
||||
```
|
||||
|
||||
### `$<` (\ARGF or $stdin)
|
||||
|
||||
Points to stream ARGF if not empty, else to stream $stdin; read-only.
|
||||
|
||||
English - `$DEFAULT_INPUT`.
|
||||
|
||||
### `$>` (Default Standard Output)
|
||||
|
||||
An output stream, initially `$stdout`.
|
||||
|
||||
English - `$DEFAULT_OUTPUT`
|
||||
|
||||
### `$.` (Input Position)
|
||||
|
||||
The input position (line number) in the most recently read stream.
|
||||
|
||||
English - `$INPUT_LINE_NUMBER`, `$NR`
|
||||
|
||||
### `$_` (Last Read Line)
|
||||
|
||||
The line (string) from the most recently read stream.
|
||||
|
||||
English - `$LAST_READ_LINE`.
|
||||
|
||||
## Processes
|
||||
|
||||
### `$0`
|
||||
|
||||
Initially, contains the name of the script being executed;
|
||||
may be reassigned.
|
||||
|
||||
### `$*` (\ARGV)
|
||||
|
||||
Points to ARGV.
|
||||
|
||||
English - `$ARGV`.
|
||||
|
||||
### `$$` (Process ID)
|
||||
|
||||
The process ID of the current process. Same as Process.pid.
|
||||
|
||||
English - `$PROCESS_ID`, `$PID`.
|
||||
|
||||
### `$?` (Child Status)
|
||||
|
||||
Initially `nil`, otherwise the Process::Status object
|
||||
created for the most-recently exited child process;
|
||||
thread-local.
|
||||
|
||||
English - `$CHILD_STATUS`.
|
||||
|
||||
### `$LOAD_PATH` (Load Path)
|
||||
|
||||
Contains the array of paths to be searched
|
||||
by Kernel#load and Kernel#require.
|
||||
|
||||
Singleton method `$LOAD_PATH.resolve_feature_path(feature)`
|
||||
returns:
|
||||
|
||||
- <tt>[:rb, _path_]</tt>, where `path` is the path to the Ruby file to be
|
||||
loaded for the given `feature`.
|
||||
- <tt>[:so, _path_]</tt>, where `path` is the path to the shared object file
|
||||
to be loaded for the given `feature`.
|
||||
- `nil` if there is no such `feature` and `path`.
|
||||
|
||||
Examples:
|
||||
|
||||
```ruby
|
||||
$LOAD_PATH.resolve_feature_path('timeout')
|
||||
# => [:rb, "/snap/ruby/317/lib/ruby/3.2.0/timeout.rb"]
|
||||
$LOAD_PATH.resolve_feature_path('date_core')
|
||||
# => [:so, "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/date_core.so"]
|
||||
$LOAD_PATH.resolve_feature_path('foo')
|
||||
# => nil
|
||||
```
|
||||
|
||||
Aliased as `$:` and `$-I`.
|
||||
|
||||
### `$LOADED_FEATURES`
|
||||
|
||||
Contains an array of the paths to the loaded files:
|
||||
|
||||
```ruby
|
||||
$LOADED_FEATURES.take(10)
|
||||
# =>
|
||||
["enumerator.so",
|
||||
"thread.rb",
|
||||
"fiber.so",
|
||||
"rational.so",
|
||||
"complex.so",
|
||||
"ruby2_keywords.rb",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/enc/encdb.so",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/enc/trans/transdb.so",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/rbconfig.rb",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/rubygems/compatibility.rb"]
|
||||
```
|
||||
|
||||
Aliased as `$"`.
|
||||
|
||||
## Debugging
|
||||
|
||||
### `$FILENAME`
|
||||
|
||||
The value returned by method ARGF.filename.
|
||||
|
||||
### `$DEBUG`
|
||||
|
||||
Initially `true` if command-line option `-d` or `--debug` is given,
|
||||
otherwise initially `false`;
|
||||
may be set to either value in the running program.
|
||||
|
||||
When `true`, prints each raised exception to `$stderr`.
|
||||
|
||||
Aliased as `$-d`.
|
||||
|
||||
### `$VERBOSE`
|
||||
|
||||
Initially `true` if command-line option `-v` or `-w` is given,
|
||||
otherwise initially `false`;
|
||||
may be set to either value, or to `nil`, in the running program.
|
||||
|
||||
When `true`, enables Ruby warnings.
|
||||
|
||||
When `nil`, disables warnings, including those from Kernel#warn.
|
||||
|
||||
Aliased as `$-v` and `$-w`.
|
||||
|
||||
## Other Variables
|
||||
|
||||
### `$-a`
|
||||
|
||||
Whether command-line option `-a` was given; read-only.
|
||||
|
||||
### `$-i`
|
||||
|
||||
Contains the extension given with command-line option `-i`,
|
||||
or `nil` if none.
|
||||
|
||||
An alias of ARGF.inplace_mode.
|
||||
|
||||
### `$-l`
|
||||
|
||||
Whether command-line option `-l` was set; read-only.
|
||||
|
||||
### `$-p`
|
||||
|
||||
Whether command-line option `-p` was given; read-only.
|
||||
|
||||
## Deprecated
|
||||
|
||||
### `$=`
|
||||
|
||||
### `$,`
|
||||
|
||||
### `$;`
|
||||
|
||||
# Pre-Defined Global Constants
|
||||
|
||||
## Summary
|
||||
|
||||
### Streams
|
||||
|
||||
| Constant | Contains |
|
||||
|----------|-------------------------|
|
||||
| `STDIN` | Standard input stream. |
|
||||
| `STDOUT` | Standard output stream. |
|
||||
| `STDERR` | Standard error stream. |
|
||||
|
||||
### Environment
|
||||
|
||||
| Constant | Contains |
|
||||
|-----------------------|-------------------------------------------------------------------------------|
|
||||
| `ENV` | Hash of current environment variable names and values. |
|
||||
| `ARGF` | String concatenation of files given on the command line, or `$stdin` if none. |
|
||||
| `ARGV` | Array of the given command-line arguments. |
|
||||
| `TOPLEVEL_BINDING` | Binding of the top level scope. |
|
||||
| `RUBY_VERSION` | String Ruby version. |
|
||||
| `RUBY_RELEASE_DATE` | String Ruby release date. |
|
||||
| `RUBY_PLATFORM` | String Ruby platform. |
|
||||
| `RUBY_PATCH_LEVEL` | String Ruby patch level. |
|
||||
| `RUBY_REVISION` | String Ruby revision. |
|
||||
| `RUBY_COPYRIGHT` | String Ruby copyright. |
|
||||
| `RUBY_ENGINE` | String Ruby engine. |
|
||||
| `RUBY_ENGINE_VERSION` | String Ruby engine version. |
|
||||
| `RUBY_DESCRIPTION` | String Ruby description. |
|
||||
|
||||
### Embedded Data
|
||||
|
||||
| Constant | Contains |
|
||||
|----------|--------------------------------------------------------------------|
|
||||
| `DATA` | File containing embedded data (lines following `__END__`, if any). |
|
||||
|
||||
## Streams
|
||||
|
||||
### `STDIN`
|
||||
|
||||
The standard input stream (the default value for `$stdin`):
|
||||
|
||||
```ruby
|
||||
STDIN # => #<IO:<STDIN>>
|
||||
```
|
||||
|
||||
### `STDOUT`
|
||||
|
||||
The standard output stream (the default value for `$stdout`):
|
||||
|
||||
```ruby
|
||||
STDOUT # => #<IO:<STDOUT>>
|
||||
```
|
||||
|
||||
### `STDERR`
|
||||
|
||||
The standard error stream (the default value for `$stderr`):
|
||||
|
||||
```ruby
|
||||
STDERR # => #<IO:<STDERR>>
|
||||
```
|
||||
|
||||
## Environment
|
||||
|
||||
### `ENV`
|
||||
|
||||
A hash of the contains current environment variables names and values:
|
||||
|
||||
```ruby
|
||||
ENV.take(5)
|
||||
# =>
|
||||
[["COLORTERM", "truecolor"],
|
||||
["DBUS_SESSION_BUS_ADDRESS", "unix:path=/run/user/1000/bus"],
|
||||
["DESKTOP_SESSION", "ubuntu"],
|
||||
["DISPLAY", ":0"],
|
||||
["GDMSESSION", "ubuntu"]]
|
||||
```
|
||||
|
||||
### `ARGF`
|
||||
|
||||
The virtual concatenation of the files given on the command line, or from
|
||||
`$stdin` if no files were given, `"-"` is given, or after
|
||||
all files have been read.
|
||||
|
||||
### `ARGV`
|
||||
|
||||
An array of the given command-line arguments.
|
||||
|
||||
### `TOPLEVEL_BINDING`
|
||||
|
||||
The Binding of the top level scope:
|
||||
|
||||
```ruby
|
||||
TOPLEVEL_BINDING # => #<Binding:0x00007f58da0da7c0>
|
||||
```
|
||||
|
||||
### `RUBY_VERSION`
|
||||
|
||||
The Ruby version:
|
||||
|
||||
```ruby
|
||||
RUBY_VERSION # => "3.2.2"
|
||||
```
|
||||
|
||||
### `RUBY_RELEASE_DATE`
|
||||
|
||||
The release date string:
|
||||
|
||||
```ruby
|
||||
RUBY_RELEASE_DATE # => "2023-03-30"
|
||||
```
|
||||
|
||||
### `RUBY_PLATFORM`
|
||||
|
||||
The platform identifier:
|
||||
|
||||
```ruby
|
||||
RUBY_PLATFORM # => "x86_64-linux"
|
||||
```
|
||||
|
||||
### `RUBY_PATCHLEVEL`
|
||||
|
||||
The integer patch level for this Ruby:
|
||||
|
||||
```ruby
|
||||
RUBY_PATCHLEVEL # => 53
|
||||
```
|
||||
|
||||
For a development build the patch level will be -1.
|
||||
|
||||
### `RUBY_REVISION`
|
||||
|
||||
The git commit hash for this Ruby:
|
||||
|
||||
```ruby
|
||||
RUBY_REVISION # => "e51014f9c05aa65cbf203442d37fef7c12390015"
|
||||
```
|
||||
|
||||
### `RUBY_COPYRIGHT`
|
||||
|
||||
The copyright string:
|
||||
|
||||
```ruby
|
||||
RUBY_COPYRIGHT
|
||||
# => "ruby - Copyright (C) 1993-2023 Yukihiro Matsumoto"
|
||||
```
|
||||
|
||||
### `RUBY_ENGINE`
|
||||
|
||||
The name of the Ruby implementation:
|
||||
|
||||
```ruby
|
||||
RUBY_ENGINE # => "ruby"
|
||||
```
|
||||
|
||||
### `RUBY_ENGINE_VERSION`
|
||||
|
||||
The version of the Ruby implementation:
|
||||
|
||||
```ruby
|
||||
RUBY_ENGINE_VERSION # => "3.2.2"
|
||||
```
|
||||
|
||||
### `RUBY_DESCRIPTION`
|
||||
|
||||
The description of the Ruby implementation:
|
||||
|
||||
```ruby
|
||||
RUBY_DESCRIPTION
|
||||
# => "ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]"
|
||||
```
|
||||
|
||||
## Embedded \Data
|
||||
|
||||
### `DATA`
|
||||
|
||||
Defined if and only if the program has this line:
|
||||
|
||||
```ruby
|
||||
__END__
|
||||
```
|
||||
|
||||
When defined, `DATA` is a File object
|
||||
containing the lines following the `__END__`,
|
||||
positioned at the first of those lines:
|
||||
|
||||
```ruby
|
||||
p DATA
|
||||
DATA.each_line { |line| p line }
|
||||
__END__
|
||||
Foo
|
||||
Bar
|
||||
Baz
|
||||
```
|
||||
|
||||
Output:
|
||||
|
||||
```
|
||||
#<File:t.rb>
|
||||
"Foo\n"
|
||||
"Bar\n"
|
||||
"Baz\n"
|
||||
```
|
416
doc/globals.rdoc
416
doc/globals.rdoc
|
@ -1,416 +0,0 @@
|
|||
= Pre-Defined Global Variables
|
||||
|
||||
Some of the pre-defined global variables have synonyms
|
||||
that are available via module English.
|
||||
For each of those, the \English synonym is given.
|
||||
|
||||
To use the module:
|
||||
|
||||
require 'English'
|
||||
|
||||
== Exceptions
|
||||
|
||||
=== <tt>$!</tt> (\Exception)
|
||||
|
||||
Contains the Exception object set by Kernel#raise:
|
||||
|
||||
begin
|
||||
raise RuntimeError.new('Boo!')
|
||||
rescue RuntimeError
|
||||
p $!
|
||||
end
|
||||
|
||||
Output:
|
||||
|
||||
#<RuntimeError: Boo!>
|
||||
|
||||
English - <tt>$ERROR_INFO</tt>
|
||||
|
||||
=== <tt>$@</tt> (Backtrace)
|
||||
|
||||
Same as <tt>$!.backtrace</tt>;
|
||||
returns an array of backtrace positions:
|
||||
|
||||
begin
|
||||
raise RuntimeError.new('Boo!')
|
||||
rescue RuntimeError
|
||||
pp $@.take(4)
|
||||
end
|
||||
|
||||
Output:
|
||||
|
||||
["(irb):338:in `<top (required)>'",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/irb/workspace.rb:119:in `eval'",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/irb/workspace.rb:119:in `evaluate'",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/irb/context.rb:502:in `evaluate'"]
|
||||
|
||||
English - <tt>$ERROR_POSITION</tt>.
|
||||
|
||||
== Pattern Matching
|
||||
|
||||
These global variables store information about the most recent
|
||||
successful match in the current scope.
|
||||
|
||||
For details and examples,
|
||||
see {Regexp Global Variables}[rdoc-ref:Regexp@Global+Variables].
|
||||
|
||||
=== <tt>$~</tt> (\MatchData)
|
||||
|
||||
MatchData object created from the match;
|
||||
thread-local and frame-local.
|
||||
|
||||
English - <tt>$LAST_MATCH_INFO</tt>.
|
||||
|
||||
=== <tt>$&</tt> (Matched Substring)
|
||||
|
||||
The matched string.
|
||||
|
||||
English - <tt>$MATCH</tt>.
|
||||
|
||||
=== <tt>$`</tt> (Pre-Match Substring)
|
||||
|
||||
The string to the left of the match.
|
||||
|
||||
English - <tt>$PREMATCH</tt>.
|
||||
|
||||
=== <tt>$'</tt> (Post-Match Substring)
|
||||
|
||||
The string to the right of the match.
|
||||
|
||||
English - <tt>$POSTMATCH</tt>.
|
||||
|
||||
=== <tt>$+</tt> (Last Matched Group)
|
||||
|
||||
The last group matched.
|
||||
|
||||
English - <tt>$LAST_PAREN_MATCH</tt>.
|
||||
|
||||
=== <tt>$1</tt>, <tt>$2</tt>, \Etc. (Matched Group)
|
||||
|
||||
For <tt>$_n_</tt> the _nth_ group of the match.
|
||||
|
||||
No \English.
|
||||
|
||||
== Separators
|
||||
|
||||
=== <tt>$/</tt> (Input Record Separator)
|
||||
|
||||
An input record separator, initially newline.
|
||||
|
||||
English - <tt>$INPUT_RECORD_SEPARATOR</tt>, <tt>$RS</tt>.
|
||||
|
||||
Aliased as <tt>$-0</tt>.
|
||||
|
||||
=== <tt>$\\</tt> (Output Record Separator)
|
||||
|
||||
An output record separator, initially +nil+.
|
||||
|
||||
English - <tt>$OUTPUT_RECORD_SEPARATOR</tt>, <tt>$ORS</tt>.
|
||||
|
||||
== Streams
|
||||
|
||||
=== <tt>$stdin</tt> (Standard Input)
|
||||
|
||||
The current standard input stream; initially:
|
||||
|
||||
$stdin # => #<IO:<STDIN>>
|
||||
|
||||
=== <tt>$stdout</tt> (Standard Output)
|
||||
|
||||
The current standard output stream; initially:
|
||||
|
||||
$stdout # => #<IO:<STDOUT>>
|
||||
|
||||
=== <tt>$stderr</tt> (Standard Error)
|
||||
|
||||
The current standard error stream; initially:
|
||||
|
||||
$stderr # => #<IO:<STDERR>>
|
||||
|
||||
=== <tt>$<</tt> (\ARGF or $stdin)
|
||||
|
||||
Points to stream ARGF if not empty, else to stream $stdin; read-only.
|
||||
|
||||
English - <tt>$DEFAULT_INPUT</tt>.
|
||||
|
||||
=== <tt>$></tt> (Default Standard Output)
|
||||
|
||||
An output stream, initially <tt>$stdout</tt>.
|
||||
|
||||
English - <tt>$DEFAULT_OUTPUT</tt>
|
||||
|
||||
=== <tt>$.</tt> (Input Position)
|
||||
|
||||
The input position (line number) in the most recently read stream.
|
||||
|
||||
English - <tt>$INPUT_LINE_NUMBER</tt>, <tt>$NR</tt>
|
||||
|
||||
=== <tt>$_</tt> (Last Read Line)
|
||||
|
||||
The line (string) from the most recently read stream.
|
||||
|
||||
English - <tt>$LAST_READ_LINE</tt>.
|
||||
|
||||
== Processes
|
||||
|
||||
=== <tt>$0</tt>
|
||||
|
||||
Initially, contains the name of the script being executed;
|
||||
may be reassigned.
|
||||
|
||||
=== <tt>$*</tt> (\ARGV)
|
||||
|
||||
Points to ARGV.
|
||||
|
||||
English - <tt>$ARGV</tt>.
|
||||
|
||||
=== <tt>$$</tt> (Process ID)
|
||||
|
||||
The process ID of the current process. Same as Process.pid.
|
||||
|
||||
English - <tt>$PROCESS_ID</tt>, <tt>$PID</tt>.
|
||||
|
||||
=== <tt>$?</tt> (Child Status)
|
||||
|
||||
Initially +nil+, otherwise the Process::Status object
|
||||
created for the most-recently exited child process;
|
||||
thread-local.
|
||||
|
||||
English - <tt>$CHILD_STATUS</tt>.
|
||||
|
||||
=== <tt>$LOAD_PATH</tt> (Load Path)
|
||||
|
||||
Contains the array of paths to be searched
|
||||
by Kernel#load and Kernel#require.
|
||||
|
||||
Singleton method <tt>$LOAD_PATH.resolve_feature_path(feature)</tt>
|
||||
returns:
|
||||
|
||||
- <tt>[:rb, _path_]</tt>, where +path+ is the path to the Ruby file
|
||||
to be loaded for the given +feature+.
|
||||
- <tt>[:so+ _path_]</tt>, where +path+ is the path to the shared object file
|
||||
to be loaded for the given +feature+.
|
||||
- +nil+ if there is no such +feature+ and +path+.
|
||||
|
||||
Examples:
|
||||
|
||||
$LOAD_PATH.resolve_feature_path('timeout')
|
||||
# => [:rb, "/snap/ruby/317/lib/ruby/3.2.0/timeout.rb"]
|
||||
$LOAD_PATH.resolve_feature_path('date_core')
|
||||
# => [:so, "/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/date_core.so"]
|
||||
$LOAD_PATH.resolve_feature_path('foo')
|
||||
# => nil
|
||||
|
||||
Aliased as <tt>$:</tt> and <tt>$-I</tt>.
|
||||
|
||||
=== <tt>$LOADED_FEATURES</tt>
|
||||
|
||||
Contains an array of the paths to the loaded files:
|
||||
|
||||
$LOADED_FEATURES.take(10)
|
||||
# =>
|
||||
["enumerator.so",
|
||||
"thread.rb",
|
||||
"fiber.so",
|
||||
"rational.so",
|
||||
"complex.so",
|
||||
"ruby2_keywords.rb",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/enc/encdb.so",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/enc/trans/transdb.so",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/x86_64-linux/rbconfig.rb",
|
||||
"/snap/ruby/317/lib/ruby/3.2.0/rubygems/compatibility.rb"]
|
||||
|
||||
Aliased as <tt>$"</tt>.
|
||||
|
||||
== Debugging
|
||||
|
||||
=== <tt>$FILENAME</tt>
|
||||
|
||||
The value returned by method ARGF.filename.
|
||||
|
||||
=== <tt>$DEBUG</tt>
|
||||
|
||||
Initially +true+ if command-line option <tt>-d</tt> or <tt>--debug</tt> is given,
|
||||
otherwise initially +false+;
|
||||
may be set to either value in the running program.
|
||||
|
||||
When +true+, prints each raised exception to <tt>$stderr</tt>.
|
||||
|
||||
Aliased as <tt>$-d</tt>.
|
||||
|
||||
=== <tt>$VERBOSE</tt>
|
||||
|
||||
Initially +true+ if command-line option <tt>-v</tt> or <tt>-w</tt> is given,
|
||||
otherwise initially +false+;
|
||||
may be set to either value, or to +nil+, in the running program.
|
||||
|
||||
When +true+, enables Ruby warnings.
|
||||
|
||||
When +nil+, disables warnings, including those from Kernel#warn.
|
||||
|
||||
Aliased as <tt>$-v</tt> and <tt>$-w</tt>.
|
||||
|
||||
== Other Variables
|
||||
|
||||
=== <tt>$-a</tt>
|
||||
|
||||
Whether command-line option <tt>-a</tt> was given; read-only.
|
||||
|
||||
=== <tt>$-i</tt>
|
||||
|
||||
Contains the extension given with command-line option <tt>-i</tt>,
|
||||
or +nil+ if none.
|
||||
|
||||
An alias of ARGF.inplace_mode.
|
||||
|
||||
=== <tt>$-l</tt>
|
||||
|
||||
Whether command-line option <tt>-l</tt> was set; read-only.
|
||||
|
||||
=== <tt>$-p</tt>
|
||||
|
||||
Whether command-line option <tt>-p</tt> was given; read-only.
|
||||
|
||||
== Deprecated
|
||||
|
||||
=== <tt>$=</tt>
|
||||
|
||||
=== <tt>$,</tt>
|
||||
|
||||
=== <tt>$;</tt>
|
||||
|
||||
= Pre-Defined Global Constants
|
||||
|
||||
= Streams
|
||||
|
||||
=== <tt>STDIN</tt>
|
||||
|
||||
The standard input stream (the default value for <tt>$stdin</tt>):
|
||||
|
||||
STDIN # => #<IO:<STDIN>>
|
||||
|
||||
=== <tt>STDOUT</tt>
|
||||
|
||||
The standard output stream (the default value for <tt>$stdout</tt>):
|
||||
|
||||
STDOUT # => #<IO:<STDOUT>>
|
||||
|
||||
=== <tt>STDERR</tt>
|
||||
|
||||
The standard error stream (the default value for <tt>$stderr</tt>):
|
||||
|
||||
STDERR # => #<IO:<STDERR>>
|
||||
|
||||
== Environment
|
||||
|
||||
=== ENV
|
||||
|
||||
A hash of the contains current environment variables names and values:
|
||||
|
||||
ENV.take(5)
|
||||
# =>
|
||||
[["COLORTERM", "truecolor"],
|
||||
["DBUS_SESSION_BUS_ADDRESS", "unix:path=/run/user/1000/bus"],
|
||||
["DESKTOP_SESSION", "ubuntu"],
|
||||
["DISPLAY", ":0"],
|
||||
["GDMSESSION", "ubuntu"]]
|
||||
|
||||
=== ARGF
|
||||
|
||||
The virtual concatenation of the files given on the command line, or from
|
||||
<tt>$stdin</tt> if no files were given, <tt>"-"</tt> is given, or after
|
||||
all files have been read.
|
||||
|
||||
=== <tt>ARGV</tt>
|
||||
|
||||
An array of the given command-line arguments.
|
||||
|
||||
=== <tt>TOPLEVEL_BINDING</tt>
|
||||
|
||||
The Binding of the top level scope:
|
||||
|
||||
TOPLEVEL_BINDING # => #<Binding:0x00007f58da0da7c0>
|
||||
|
||||
=== <tt>RUBY_VERSION</tt>
|
||||
|
||||
The Ruby version:
|
||||
|
||||
RUBY_VERSION # => "3.2.2"
|
||||
|
||||
=== <tt>RUBY_RELEASE_DATE</tt>
|
||||
|
||||
The release date string:
|
||||
|
||||
RUBY_RELEASE_DATE # => "2023-03-30"
|
||||
|
||||
=== <tt>RUBY_PLATFORM</tt>
|
||||
|
||||
The platform identifier:
|
||||
|
||||
RUBY_PLATFORM # => "x86_64-linux"
|
||||
|
||||
=== <tt>RUBY_PATCHLEVEL</tt>
|
||||
|
||||
The integer patch level for this Ruby:
|
||||
|
||||
RUBY_PATCHLEVEL # => 53
|
||||
|
||||
For a development build the patch level will be -1.
|
||||
|
||||
=== <tt>RUBY_REVISION</tt>
|
||||
|
||||
The git commit hash for this Ruby:
|
||||
|
||||
RUBY_REVISION # => "e51014f9c05aa65cbf203442d37fef7c12390015"
|
||||
|
||||
=== <tt>RUBY_COPYRIGHT</tt>
|
||||
|
||||
The copyright string:
|
||||
|
||||
RUBY_COPYRIGHT
|
||||
# => "ruby - Copyright (C) 1993-2023 Yukihiro Matsumoto"
|
||||
|
||||
=== <tt>RUBY_ENGINE</tt>
|
||||
|
||||
The name of the Ruby implementation:
|
||||
|
||||
RUBY_ENGINE # => "ruby"
|
||||
|
||||
=== <tt>RUBY_ENGINE_VERSION</tt>
|
||||
|
||||
The version of the Ruby implementation:
|
||||
|
||||
RUBY_ENGINE_VERSION # => "3.2.2"
|
||||
|
||||
=== <tt>RUBY_DESCRIPTION</tt>
|
||||
|
||||
The description of the Ruby implementation:
|
||||
|
||||
RUBY_DESCRIPTION
|
||||
# => "ruby 3.2.2 (2023-03-30 revision e51014f9c0) [x86_64-linux]"
|
||||
|
||||
== Embedded \Data
|
||||
|
||||
=== <tt>DATA</tt>
|
||||
|
||||
Defined if and only if the program has this line:
|
||||
|
||||
__END__
|
||||
|
||||
When defined, <tt>DATA</tt> is a File object
|
||||
containing the lines following the <tt>__END__</tt>,
|
||||
positioned at the first of those lines:
|
||||
|
||||
p DATA
|
||||
DATA.each_line { |line| p line }
|
||||
__END__
|
||||
Foo
|
||||
Bar
|
||||
Baz
|
||||
|
||||
Output:
|
||||
|
||||
#<File:t.rb>
|
||||
"Foo\n"
|
||||
"Bar\n"
|
||||
"Baz\n"
|
|
@ -672,6 +672,11 @@ $ ruby --internal-encoding=cesu-8 -e 'puts Encoding::default_internal'
|
|||
CESU-8
|
||||
```
|
||||
|
||||
### `--jit`
|
||||
|
||||
Option `--jit` is an alias for option `--yjit`, which enables YJIT;
|
||||
see additional YJIT options in the [YJIT documentation](rdoc-ref:yjit/yjit.md).
|
||||
|
||||
### `--verbose`: Set `$VERBOSE`
|
||||
|
||||
Option `--verbose` sets global variable `$VERBOSE` to `true`
|
||||
|
@ -681,44 +686,3 @@ and disables input from `$stdin`.
|
|||
|
||||
Option `--version` prints the version of the Ruby interpreter, then exits.
|
||||
|
||||
## Experimental Options
|
||||
|
||||
These options are experimental in the current Ruby release,
|
||||
and may be modified or withdrawn in later releases.
|
||||
|
||||
### `--jit`
|
||||
|
||||
Option `-jit` enables JIT compilation with the default option.
|
||||
|
||||
#### `--jit-debug`
|
||||
|
||||
Option `--jit-debug` enables JIT debugging (very slow);
|
||||
adds compiler flags if given.
|
||||
|
||||
#### `--jit-max-cache=num`
|
||||
|
||||
Option `--jit-max-cache=num` sets the maximum number of methods
|
||||
to be JIT-ed in a cache; default: 100).
|
||||
|
||||
#### `--jit-min-calls=num`
|
||||
|
||||
Option `jit-min-calls=num` sets the minimum number of calls to trigger JIT
|
||||
(for testing); default: 10000).
|
||||
|
||||
#### `--jit-save-temps`
|
||||
|
||||
Option `--jit-save-temps` saves JIT temporary files in $TMP or /tmp (for testing).
|
||||
|
||||
#### `--jit-verbose`
|
||||
|
||||
Option `--jit-verbose` prints JIT logs of level `num` or less
|
||||
to `$stderr`; default: 0.
|
||||
|
||||
#### `--jit-wait`
|
||||
|
||||
Option `--jit-wait` waits until JIT compilation finishes every time (for testing).
|
||||
|
||||
#### `--jit-warnings`
|
||||
|
||||
Option `--jit-warnings` enables printing of JIT warnings.
|
||||
|
||||
|
|
|
@ -1,6 +1,19 @@
|
|||
Returns an array of the grapheme clusters in +self+
|
||||
(see {Unicode Grapheme Cluster Boundaries}[https://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries]):
|
||||
|
||||
s = "\u0061\u0308-pqr-\u0062\u0308-xyz-\u0063\u0308" # => "ä-pqr-b̈-xyz-c̈"
|
||||
s = "ä-pqr-b̈-xyz-c̈"
|
||||
s.size # => 16
|
||||
s.bytesize # => 19
|
||||
s.grapheme_clusters.size # => 13
|
||||
s.grapheme_clusters
|
||||
# => ["ä", "-", "p", "q", "r", "-", "b̈", "-", "x", "y", "z", "-", "c̈"]
|
||||
|
||||
Details:
|
||||
|
||||
s = "ä"
|
||||
s.grapheme_clusters # => ["ä"] # One grapheme cluster.
|
||||
s.bytes # => [97, 204, 136] # Three bytes.
|
||||
s.chars # => ["a", "̈"] # Two characters.
|
||||
s.chars.map {|char| char.ord } # => [97, 776] # Their values.
|
||||
|
||||
Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
|
||||
|
|
|
@ -279,7 +279,7 @@ An uninitialized global variable has a value of +nil+.
|
|||
|
||||
Ruby has some special globals that behave differently depending on context
|
||||
such as the regular expression match variables or that have a side-effect when
|
||||
assigned to. See the {global variables documentation}[rdoc-ref:globals.rdoc]
|
||||
assigned to. See the {global variables documentation}[rdoc-ref:globals.md]
|
||||
for details.
|
||||
|
||||
== Assignment Methods
|
||||
|
|
|
@ -99,16 +99,18 @@ sh ../../ruby/configure -C --disable-install-doc --with-opt-dir=C:\Users\usernam
|
|||
To cross build arm64 binary:
|
||||
|
||||
```
|
||||
cmd /k win32\vssetup.cmd -arch arm64
|
||||
cmd /k win32\vssetup.cmd -arch=arm64
|
||||
```
|
||||
|
||||
To cross build x64 binary:
|
||||
|
||||
```
|
||||
cmd /k win32\vssetup.cmd -arch x64
|
||||
cmd /k win32\vssetup.cmd -arch=x64
|
||||
```
|
||||
|
||||
See `win32\vssetup.cmd -help` for other command line options.
|
||||
This batch file is a wrapper of `vsdevcmd.bat` and options are
|
||||
passed to it as-is. `win32\vssetup.cmd -help` for other command
|
||||
line options.
|
||||
|
||||
**Note** building ruby requires following commands.
|
||||
|
||||
|
|
101
encoding.c
101
encoding.c
|
@ -29,6 +29,7 @@
|
|||
#include "ruby/util.h"
|
||||
#include "ruby_assert.h"
|
||||
#include "vm_sync.h"
|
||||
#include "ruby_atomic.h"
|
||||
|
||||
#ifndef ENC_DEBUG
|
||||
#define ENC_DEBUG 0
|
||||
|
@ -144,10 +145,14 @@ enc_list_update(int index, rb_raw_encoding *encoding)
|
|||
{
|
||||
RUBY_ASSERT(index < ENCODING_LIST_CAPA);
|
||||
|
||||
VALUE list = rb_encoding_list;
|
||||
VALUE list = RUBY_ATOMIC_VALUE_LOAD(rb_encoding_list);
|
||||
|
||||
if (list && NIL_P(rb_ary_entry(list, index))) {
|
||||
VALUE new_list = rb_ary_dup(list);
|
||||
RBASIC_CLEAR_CLASS(new_list);
|
||||
/* initialize encoding data */
|
||||
rb_ary_store(list, index, enc_new(encoding));
|
||||
rb_ary_store(new_list, index, enc_new(encoding));
|
||||
RUBY_ATOMIC_VALUE_SET(rb_encoding_list, new_list);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -157,7 +162,7 @@ enc_list_lookup(int idx)
|
|||
VALUE list, enc = Qnil;
|
||||
|
||||
if (idx < ENCODING_LIST_CAPA) {
|
||||
list = rb_encoding_list;
|
||||
list = RUBY_ATOMIC_VALUE_LOAD(rb_encoding_list);
|
||||
RUBY_ASSERT(list);
|
||||
enc = rb_ary_entry(list, idx);
|
||||
}
|
||||
|
@ -258,6 +263,7 @@ must_encindex(int index)
|
|||
int
|
||||
rb_to_encoding_index(VALUE enc)
|
||||
{
|
||||
ASSERT_vm_unlocking(); // can load encoding, so must not hold VM lock
|
||||
int idx;
|
||||
const char *name;
|
||||
|
||||
|
@ -667,15 +673,15 @@ int
|
|||
rb_enc_alias(const char *alias, const char *orig)
|
||||
{
|
||||
int idx, r;
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
enc_check_addable(enc_table, alias); // can raise
|
||||
}
|
||||
|
||||
idx = rb_enc_find_index(orig);
|
||||
if (idx < 0) return -1;
|
||||
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
enc_check_addable(enc_table, alias);
|
||||
if ((idx = rb_enc_find_index(orig)) < 0) {
|
||||
r = -1;
|
||||
}
|
||||
else {
|
||||
r = enc_alias(enc_table, alias, idx);
|
||||
}
|
||||
r = enc_alias(enc_table, alias, idx);
|
||||
}
|
||||
|
||||
return r;
|
||||
|
@ -742,6 +748,7 @@ int rb_require_internal_silent(VALUE fname);
|
|||
static int
|
||||
load_encoding(const char *name)
|
||||
{
|
||||
ASSERT_vm_unlocking();
|
||||
VALUE enclib = rb_sprintf("enc/%s.so", name);
|
||||
VALUE debug = ruby_debug;
|
||||
VALUE errinfo;
|
||||
|
@ -757,7 +764,7 @@ load_encoding(const char *name)
|
|||
enclib = rb_fstring(enclib);
|
||||
ruby_debug = Qfalse;
|
||||
errinfo = rb_errinfo();
|
||||
loaded = rb_require_internal_silent(enclib);
|
||||
loaded = rb_require_internal_silent(enclib); // must run without VM_LOCK
|
||||
ruby_debug = debug;
|
||||
rb_set_errinfo(errinfo);
|
||||
|
||||
|
@ -781,6 +788,7 @@ enc_autoload_body(rb_encoding *enc)
|
|||
{
|
||||
rb_encoding *base;
|
||||
int i = 0;
|
||||
ASSERT_vm_unlocking();
|
||||
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
base = enc_table->list[ENC_TO_ENCINDEX(enc)].base;
|
||||
|
@ -792,30 +800,32 @@ enc_autoload_body(rb_encoding *enc)
|
|||
}
|
||||
} while (enc_table->list[i].enc != base && (++i, 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (i != -1) {
|
||||
if (base) {
|
||||
bool do_register = true;
|
||||
if (rb_enc_autoload_p(base)) {
|
||||
if (rb_enc_autoload(base) < 0) {
|
||||
do_register = false;
|
||||
i = -1;
|
||||
}
|
||||
|
||||
if (i != -1) {
|
||||
if (base) {
|
||||
bool do_register = true;
|
||||
if (rb_enc_autoload_p(base)) {
|
||||
if (rb_enc_autoload(base) < 0) {
|
||||
do_register = false;
|
||||
i = -1;
|
||||
}
|
||||
}
|
||||
|
||||
i = enc->ruby_encoding_index;
|
||||
if (do_register) {
|
||||
if (do_register) {
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
i = enc->ruby_encoding_index;
|
||||
enc_register_at(enc_table, i & ENC_INDEX_MASK, rb_enc_name(enc), base);
|
||||
((rb_raw_encoding *)enc)->ruby_encoding_index = i;
|
||||
}
|
||||
}
|
||||
|
||||
i &= ENC_INDEX_MASK;
|
||||
}
|
||||
else {
|
||||
i = -2;
|
||||
}
|
||||
i &= ENC_INDEX_MASK;
|
||||
}
|
||||
else {
|
||||
i = -2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return i;
|
||||
|
@ -824,6 +834,7 @@ enc_autoload_body(rb_encoding *enc)
|
|||
int
|
||||
rb_enc_autoload(rb_encoding *enc)
|
||||
{
|
||||
ASSERT_vm_unlocking();
|
||||
int i = enc_autoload_body(enc);
|
||||
if (i == -2) {
|
||||
i = load_encoding(rb_enc_name(enc));
|
||||
|
@ -844,6 +855,7 @@ int
|
|||
rb_enc_find_index(const char *name)
|
||||
{
|
||||
int i;
|
||||
ASSERT_vm_unlocking(); // it needs to be unlocked so it can call `load_encoding` if necessary
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
i = enc_registered(enc_table, name);
|
||||
}
|
||||
|
@ -1019,7 +1031,6 @@ rb_enc_associate_index(VALUE obj, int idx)
|
|||
rb_encoding *enc;
|
||||
int oldidx, oldtermlen, termlen;
|
||||
|
||||
/* enc_check_capable(obj);*/
|
||||
rb_check_frozen(obj);
|
||||
oldidx = rb_enc_get_index(obj);
|
||||
if (oldidx == idx)
|
||||
|
@ -1355,7 +1366,10 @@ enc_names(VALUE self)
|
|||
|
||||
args[0] = (VALUE)rb_to_encoding_index(self);
|
||||
args[1] = rb_ary_new2(0);
|
||||
st_foreach(global_enc_table.names, enc_names_i, (st_data_t)args);
|
||||
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
st_foreach(enc_table->names, enc_names_i, (st_data_t)args);
|
||||
}
|
||||
return args[1];
|
||||
}
|
||||
|
||||
|
@ -1380,8 +1394,9 @@ enc_names(VALUE self)
|
|||
static VALUE
|
||||
enc_list(VALUE klass)
|
||||
{
|
||||
VALUE ary = rb_ary_new2(0);
|
||||
rb_ary_replace(ary, rb_encoding_list);
|
||||
VALUE ary = rb_ary_new2(ENCODING_LIST_CAPA);
|
||||
VALUE list = RUBY_ATOMIC_VALUE_LOAD(rb_encoding_list);
|
||||
rb_ary_replace(ary, list);
|
||||
return ary;
|
||||
}
|
||||
|
||||
|
@ -1526,6 +1541,9 @@ int rb_locale_charmap_index(void);
|
|||
int
|
||||
rb_locale_encindex(void)
|
||||
{
|
||||
// `rb_locale_charmap_index` can call `enc_find_index`, which can
|
||||
// load an encoding. This needs to be done without VM lock held.
|
||||
ASSERT_vm_unlocking();
|
||||
int idx = rb_locale_charmap_index();
|
||||
|
||||
if (idx < 0) idx = ENCINDEX_UTF_8;
|
||||
|
@ -1584,6 +1602,10 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
|
|||
/* Already set */
|
||||
overridden = TRUE;
|
||||
|
||||
if (!NIL_P(encoding)) {
|
||||
enc_check_encoding(encoding); // loads it if necessary. Needs to be done outside of VM lock.
|
||||
}
|
||||
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
if (NIL_P(encoding)) {
|
||||
def->index = -1;
|
||||
|
@ -1854,8 +1876,11 @@ rb_enc_name_list_i(st_data_t name, st_data_t idx, st_data_t arg)
|
|||
static VALUE
|
||||
rb_enc_name_list(VALUE klass)
|
||||
{
|
||||
VALUE ary = rb_ary_new2(global_enc_table.names->num_entries);
|
||||
st_foreach(global_enc_table.names, rb_enc_name_list_i, (st_data_t)ary);
|
||||
VALUE ary;
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
ary = rb_ary_new2(enc_table->names->num_entries);
|
||||
st_foreach(enc_table->names, rb_enc_name_list_i, (st_data_t)ary);
|
||||
}
|
||||
return ary;
|
||||
}
|
||||
|
||||
|
@ -1901,7 +1926,9 @@ rb_enc_aliases(VALUE klass)
|
|||
aliases[0] = rb_hash_new();
|
||||
aliases[1] = rb_ary_new();
|
||||
|
||||
st_foreach(global_enc_table.names, rb_enc_aliases_enc_i, (st_data_t)aliases);
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
st_foreach(enc_table->names, rb_enc_aliases_enc_i, (st_data_t)aliases);
|
||||
}
|
||||
|
||||
return aliases[0];
|
||||
}
|
||||
|
@ -1969,9 +1996,9 @@ Init_Encoding(void)
|
|||
|
||||
struct enc_table *enc_table = &global_enc_table;
|
||||
|
||||
rb_gc_register_address(&rb_encoding_list);
|
||||
list = rb_encoding_list = rb_ary_new2(ENCODING_LIST_CAPA);
|
||||
RBASIC_CLEAR_CLASS(list);
|
||||
rb_vm_register_global_object(list);
|
||||
|
||||
for (i = 0; i < enc_table->count; ++i) {
|
||||
rb_ary_push(list, enc_new(enc_table->list[i].enc));
|
||||
|
@ -2003,5 +2030,7 @@ Init_encodings(void)
|
|||
void
|
||||
rb_enc_foreach_name(int (*func)(st_data_t name, st_data_t idx, st_data_t arg), st_data_t arg)
|
||||
{
|
||||
st_foreach(global_enc_table.names, func, arg);
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
st_foreach(enc_table->names, func, arg);
|
||||
}
|
||||
}
|
||||
|
|
111
enumerator.c
111
enumerator.c
|
@ -280,28 +280,20 @@ enumerator_ptr(VALUE obj)
|
|||
}
|
||||
|
||||
static void
|
||||
proc_entry_mark(void *p)
|
||||
proc_entry_mark_and_move(void *p)
|
||||
{
|
||||
struct proc_entry *ptr = p;
|
||||
rb_gc_mark_movable(ptr->proc);
|
||||
rb_gc_mark_movable(ptr->memo);
|
||||
}
|
||||
|
||||
static void
|
||||
proc_entry_compact(void *p)
|
||||
{
|
||||
struct proc_entry *ptr = p;
|
||||
ptr->proc = rb_gc_location(ptr->proc);
|
||||
ptr->memo = rb_gc_location(ptr->memo);
|
||||
rb_gc_mark_and_move(&ptr->proc);
|
||||
rb_gc_mark_and_move(&ptr->memo);
|
||||
}
|
||||
|
||||
static const rb_data_type_t proc_entry_data_type = {
|
||||
"proc_entry",
|
||||
{
|
||||
proc_entry_mark,
|
||||
proc_entry_mark_and_move,
|
||||
RUBY_TYPED_DEFAULT_FREE,
|
||||
NULL, // Nothing allocated externally, so don't need a memsize function
|
||||
proc_entry_compact,
|
||||
proc_entry_mark_and_move,
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
|
||||
};
|
||||
|
@ -1280,26 +1272,19 @@ enumerator_size(VALUE obj)
|
|||
* Yielder
|
||||
*/
|
||||
static void
|
||||
yielder_mark(void *p)
|
||||
yielder_mark_and_move(void *p)
|
||||
{
|
||||
struct yielder *ptr = p;
|
||||
rb_gc_mark_movable(ptr->proc);
|
||||
}
|
||||
|
||||
static void
|
||||
yielder_compact(void *p)
|
||||
{
|
||||
struct yielder *ptr = p;
|
||||
ptr->proc = rb_gc_location(ptr->proc);
|
||||
rb_gc_mark_and_move(&ptr->proc);
|
||||
}
|
||||
|
||||
static const rb_data_type_t yielder_data_type = {
|
||||
"yielder",
|
||||
{
|
||||
yielder_mark,
|
||||
yielder_mark_and_move,
|
||||
RUBY_TYPED_DEFAULT_FREE,
|
||||
NULL,
|
||||
yielder_compact,
|
||||
yielder_mark_and_move,
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
|
||||
};
|
||||
|
@ -1410,28 +1395,20 @@ yielder_new(void)
|
|||
* Generator
|
||||
*/
|
||||
static void
|
||||
generator_mark(void *p)
|
||||
generator_mark_and_move(void *p)
|
||||
{
|
||||
struct generator *ptr = p;
|
||||
rb_gc_mark_movable(ptr->proc);
|
||||
rb_gc_mark_movable(ptr->obj);
|
||||
}
|
||||
|
||||
static void
|
||||
generator_compact(void *p)
|
||||
{
|
||||
struct generator *ptr = p;
|
||||
ptr->proc = rb_gc_location(ptr->proc);
|
||||
ptr->obj = rb_gc_location(ptr->obj);
|
||||
rb_gc_mark_and_move(&ptr->proc);
|
||||
rb_gc_mark_and_move(&ptr->obj);
|
||||
}
|
||||
|
||||
static const rb_data_type_t generator_data_type = {
|
||||
"generator",
|
||||
{
|
||||
generator_mark,
|
||||
generator_mark_and_move,
|
||||
RUBY_TYPED_DEFAULT_FREE,
|
||||
NULL,
|
||||
generator_compact,
|
||||
generator_mark_and_move,
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
|
||||
};
|
||||
|
@ -2940,19 +2917,11 @@ stop_result(VALUE self)
|
|||
*/
|
||||
|
||||
static void
|
||||
producer_mark(void *p)
|
||||
producer_mark_and_move(void *p)
|
||||
{
|
||||
struct producer *ptr = p;
|
||||
rb_gc_mark_movable(ptr->init);
|
||||
rb_gc_mark_movable(ptr->proc);
|
||||
}
|
||||
|
||||
static void
|
||||
producer_compact(void *p)
|
||||
{
|
||||
struct producer *ptr = p;
|
||||
ptr->init = rb_gc_location(ptr->init);
|
||||
ptr->proc = rb_gc_location(ptr->proc);
|
||||
rb_gc_mark_and_move(&ptr->init);
|
||||
rb_gc_mark_and_move(&ptr->proc);
|
||||
}
|
||||
|
||||
#define producer_free RUBY_TYPED_DEFAULT_FREE
|
||||
|
@ -2966,10 +2935,10 @@ producer_memsize(const void *p)
|
|||
static const rb_data_type_t producer_data_type = {
|
||||
"producer",
|
||||
{
|
||||
producer_mark,
|
||||
producer_mark_and_move,
|
||||
producer_free,
|
||||
producer_memsize,
|
||||
producer_compact,
|
||||
producer_mark_and_move,
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
|
||||
};
|
||||
|
@ -3128,17 +3097,10 @@ enumerator_s_produce(int argc, VALUE *argv, VALUE klass)
|
|||
*/
|
||||
|
||||
static void
|
||||
enum_chain_mark(void *p)
|
||||
enum_chain_mark_and_move(void *p)
|
||||
{
|
||||
struct enum_chain *ptr = p;
|
||||
rb_gc_mark_movable(ptr->enums);
|
||||
}
|
||||
|
||||
static void
|
||||
enum_chain_compact(void *p)
|
||||
{
|
||||
struct enum_chain *ptr = p;
|
||||
ptr->enums = rb_gc_location(ptr->enums);
|
||||
rb_gc_mark_and_move(&ptr->enums);
|
||||
}
|
||||
|
||||
#define enum_chain_free RUBY_TYPED_DEFAULT_FREE
|
||||
|
@ -3152,12 +3114,12 @@ enum_chain_memsize(const void *p)
|
|||
static const rb_data_type_t enum_chain_data_type = {
|
||||
"chain",
|
||||
{
|
||||
enum_chain_mark,
|
||||
enum_chain_mark_and_move,
|
||||
enum_chain_free,
|
||||
enum_chain_memsize,
|
||||
enum_chain_compact,
|
||||
enum_chain_mark_and_move,
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
||||
};
|
||||
|
||||
static struct enum_chain *
|
||||
|
@ -3207,7 +3169,7 @@ enum_chain_initialize(VALUE obj, VALUE enums)
|
|||
|
||||
if (!ptr) rb_raise(rb_eArgError, "unallocated chain");
|
||||
|
||||
ptr->enums = rb_ary_freeze(enums);
|
||||
RB_OBJ_WRITE(obj, &ptr->enums, rb_ary_freeze(enums));
|
||||
ptr->pos = -1;
|
||||
|
||||
return obj;
|
||||
|
@ -3241,7 +3203,7 @@ enum_chain_init_copy(VALUE obj, VALUE orig)
|
|||
|
||||
if (!ptr1) rb_raise(rb_eArgError, "unallocated chain");
|
||||
|
||||
ptr1->enums = ptr0->enums;
|
||||
RB_OBJ_WRITE(obj, &ptr1->enums, ptr0->enums);
|
||||
ptr1->pos = ptr0->pos;
|
||||
|
||||
return obj;
|
||||
|
@ -3450,17 +3412,10 @@ enumerator_plus(VALUE obj, VALUE eobj)
|
|||
*/
|
||||
|
||||
static void
|
||||
enum_product_mark(void *p)
|
||||
enum_product_mark_and_move(void *p)
|
||||
{
|
||||
struct enum_product *ptr = p;
|
||||
rb_gc_mark_movable(ptr->enums);
|
||||
}
|
||||
|
||||
static void
|
||||
enum_product_compact(void *p)
|
||||
{
|
||||
struct enum_product *ptr = p;
|
||||
ptr->enums = rb_gc_location(ptr->enums);
|
||||
rb_gc_mark_and_move(&ptr->enums);
|
||||
}
|
||||
|
||||
#define enum_product_free RUBY_TYPED_DEFAULT_FREE
|
||||
|
@ -3474,12 +3429,12 @@ enum_product_memsize(const void *p)
|
|||
static const rb_data_type_t enum_product_data_type = {
|
||||
"product",
|
||||
{
|
||||
enum_product_mark,
|
||||
enum_product_mark_and_move,
|
||||
enum_product_free,
|
||||
enum_product_memsize,
|
||||
enum_product_compact,
|
||||
enum_product_mark_and_move,
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
||||
};
|
||||
|
||||
static struct enum_product *
|
||||
|
@ -3535,7 +3490,7 @@ enum_product_initialize(int argc, VALUE *argv, VALUE obj)
|
|||
|
||||
if (!ptr) rb_raise(rb_eArgError, "unallocated product");
|
||||
|
||||
ptr->enums = rb_ary_freeze(enums);
|
||||
RB_OBJ_WRITE(obj, &ptr->enums, rb_ary_freeze(enums));
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
@ -3553,7 +3508,7 @@ enum_product_init_copy(VALUE obj, VALUE orig)
|
|||
|
||||
if (!ptr1) rb_raise(rb_eArgError, "unallocated product");
|
||||
|
||||
ptr1->enums = ptr0->enums;
|
||||
RB_OBJ_WRITE(obj, &ptr1->enums, ptr0->enums);
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
|
23
error.c
23
error.c
|
@ -1883,7 +1883,7 @@ exc_inspect(VALUE exc)
|
|||
* # String
|
||||
* end
|
||||
*
|
||||
* The value returned by this method migth be adjusted when raising (see Kernel#raise),
|
||||
* The value returned by this method might be adjusted when raising (see Kernel#raise),
|
||||
* or during intermediate handling by #set_backtrace.
|
||||
*
|
||||
* See also #backtrace_locations that provide the same value, as structured objects.
|
||||
|
@ -2517,30 +2517,21 @@ typedef struct name_error_message_struct {
|
|||
} name_error_message_t;
|
||||
|
||||
static void
|
||||
name_err_mesg_mark(void *p)
|
||||
name_err_mesg_mark_and_move(void *p)
|
||||
{
|
||||
name_error_message_t *ptr = (name_error_message_t *)p;
|
||||
rb_gc_mark_movable(ptr->mesg);
|
||||
rb_gc_mark_movable(ptr->recv);
|
||||
rb_gc_mark_movable(ptr->name);
|
||||
}
|
||||
|
||||
static void
|
||||
name_err_mesg_update(void *p)
|
||||
{
|
||||
name_error_message_t *ptr = (name_error_message_t *)p;
|
||||
ptr->mesg = rb_gc_location(ptr->mesg);
|
||||
ptr->recv = rb_gc_location(ptr->recv);
|
||||
ptr->name = rb_gc_location(ptr->name);
|
||||
rb_gc_mark_and_move(&ptr->mesg);
|
||||
rb_gc_mark_and_move(&ptr->recv);
|
||||
rb_gc_mark_and_move(&ptr->name);
|
||||
}
|
||||
|
||||
static const rb_data_type_t name_err_mesg_data_type = {
|
||||
"name_err_mesg",
|
||||
{
|
||||
name_err_mesg_mark,
|
||||
name_err_mesg_mark_and_move,
|
||||
RUBY_TYPED_DEFAULT_FREE,
|
||||
NULL, // No external memory to report,
|
||||
name_err_mesg_update,
|
||||
name_err_mesg_mark_and_move,
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
|
||||
};
|
||||
|
|
|
@ -451,13 +451,16 @@ dump_object(VALUE obj, struct dump_config *dc)
|
|||
break;
|
||||
|
||||
case imemo_callcache:
|
||||
mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id;
|
||||
if (mid != 0) {
|
||||
dump_append(dc, ", \"called_id\":");
|
||||
dump_append_id(dc, mid);
|
||||
|
||||
{
|
||||
VALUE klass = ((const struct rb_callcache *)obj)->klass;
|
||||
if (klass != 0) {
|
||||
if (klass != Qundef) {
|
||||
mid = vm_cc_cme((const struct rb_callcache *)obj)->called_id;
|
||||
if (mid != 0) {
|
||||
dump_append(dc, ", \"called_id\":");
|
||||
dump_append_id(dc, mid);
|
||||
|
||||
}
|
||||
|
||||
dump_append(dc, ", \"receiver_class\":");
|
||||
dump_append_ref(dc, klass);
|
||||
}
|
||||
|
|
|
@ -203,6 +203,18 @@ check_modifiable(struct StringIO *ptr)
|
|||
}
|
||||
}
|
||||
|
||||
static inline bool
|
||||
outside_p(struct StringIO *ptr, long pos)
|
||||
{
|
||||
return NIL_P(ptr->string) || pos >= RSTRING_LEN(ptr->string);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
eos_p(struct StringIO *ptr)
|
||||
{
|
||||
return outside_p(ptr, ptr->pos);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
strio_s_allocate(VALUE klass)
|
||||
{
|
||||
|
@ -628,9 +640,8 @@ static struct StringIO *
|
|||
strio_to_read(VALUE self)
|
||||
{
|
||||
struct StringIO *ptr = readable(self);
|
||||
if (NIL_P(ptr->string)) return NULL;
|
||||
if (ptr->pos < RSTRING_LEN(ptr->string)) return ptr;
|
||||
return NULL;
|
||||
if (eos_p(ptr)) return NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -837,7 +848,11 @@ strio_seek(int argc, VALUE *argv, VALUE self)
|
|||
offset = ptr->pos;
|
||||
break;
|
||||
case 2:
|
||||
offset = RSTRING_LEN(ptr->string);
|
||||
if (NIL_P(ptr->string)) {
|
||||
offset = 0;
|
||||
} else {
|
||||
offset = RSTRING_LEN(ptr->string);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error_inval("invalid whence");
|
||||
|
@ -906,7 +921,7 @@ strio_getc(VALUE self)
|
|||
int len;
|
||||
char *p;
|
||||
|
||||
if (NIL_P(str) || pos >= RSTRING_LEN(str)) {
|
||||
if (eos_p(ptr)) {
|
||||
return Qnil;
|
||||
}
|
||||
p = RSTRING_PTR(str)+pos;
|
||||
|
@ -927,7 +942,7 @@ strio_getbyte(VALUE self)
|
|||
{
|
||||
struct StringIO *ptr = readable(self);
|
||||
int c;
|
||||
if (NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string)) {
|
||||
if (eos_p(ptr)) {
|
||||
return Qnil;
|
||||
}
|
||||
c = RSTRING_PTR(ptr->string)[ptr->pos++];
|
||||
|
@ -1605,10 +1620,9 @@ strio_read(int argc, VALUE *argv, VALUE self)
|
|||
if (len < 0) {
|
||||
rb_raise(rb_eArgError, "negative length %ld given", len);
|
||||
}
|
||||
if (len > 0 &&
|
||||
(NIL_P(ptr->string) || ptr->pos >= RSTRING_LEN(ptr->string))) {
|
||||
if (eos_p(ptr)) {
|
||||
if (!NIL_P(str)) rb_str_resize(str, 0);
|
||||
return Qnil;
|
||||
return len > 0 ? Qnil : rb_str_new(0, 0);
|
||||
}
|
||||
binary = 1;
|
||||
break;
|
||||
|
@ -1684,7 +1698,7 @@ strio_pread(int argc, VALUE *argv, VALUE self)
|
|||
|
||||
struct StringIO *ptr = readable(self);
|
||||
|
||||
if (offset >= RSTRING_LEN(ptr->string)) {
|
||||
if (outside_p(ptr, offset)) {
|
||||
rb_eof_error();
|
||||
}
|
||||
|
||||
|
@ -1921,7 +1935,7 @@ Init_stringio(void)
|
|||
#undef rb_intern
|
||||
|
||||
#ifdef HAVE_RB_EXT_RACTOR_SAFE
|
||||
rb_ext_ractor_safe(true);
|
||||
rb_ext_ractor_safe(true);
|
||||
#endif
|
||||
|
||||
VALUE StringIO = rb_define_class("StringIO", rb_cObject);
|
||||
|
|
63
gc.c
63
gc.c
|
@ -1047,7 +1047,7 @@ rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_DATA_FU
|
|||
{
|
||||
RUBY_ASSERT_ALWAYS(dfree != (RUBY_DATA_FUNC)1);
|
||||
if (klass) rb_data_object_check(klass);
|
||||
return newobj_of(GET_RACTOR(), klass, T_DATA, (VALUE)dmark, (VALUE)datap, (VALUE)dfree, !dmark, sizeof(struct RTypedData));
|
||||
return newobj_of(GET_RACTOR(), klass, T_DATA, (VALUE)dmark, (VALUE)dfree, (VALUE)datap, !dmark, sizeof(struct RTypedData));
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -1064,7 +1064,7 @@ typed_data_alloc(VALUE klass, VALUE typed_flag, void *datap, const rb_data_type_
|
|||
RBIMPL_NONNULL_ARG(type);
|
||||
if (klass) rb_data_object_check(klass);
|
||||
bool wb_protected = (type->flags & RUBY_FL_WB_PROTECTED) || !type->function.dmark;
|
||||
return newobj_of(GET_RACTOR(), klass, T_DATA, ((VALUE)type) | IS_TYPED_DATA | typed_flag, (VALUE)datap, 0, wb_protected, size);
|
||||
return newobj_of(GET_RACTOR(), klass, T_DATA, 0, ((VALUE)type) | IS_TYPED_DATA | typed_flag, (VALUE)datap, wb_protected, size);
|
||||
}
|
||||
|
||||
VALUE
|
||||
|
@ -1755,7 +1755,6 @@ rb_gc_pointer_to_heap_p(VALUE obj)
|
|||
#define LAST_OBJECT_ID() (object_id_counter * OBJ_ID_INCREMENT)
|
||||
static VALUE id2ref_value = 0;
|
||||
static st_table *id2ref_tbl = NULL;
|
||||
static bool id2ref_tbl_built = false;
|
||||
|
||||
#if SIZEOF_SIZE_T == SIZEOF_LONG_LONG
|
||||
static size_t object_id_counter = 1;
|
||||
|
@ -1947,6 +1946,7 @@ build_id2ref_i(VALUE obj, void *data)
|
|||
case T_CLASS:
|
||||
case T_MODULE:
|
||||
if (RCLASS(obj)->object_id) {
|
||||
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
|
||||
st_insert(id2ref_tbl, RCLASS(obj)->object_id, obj);
|
||||
}
|
||||
break;
|
||||
|
@ -1955,6 +1955,7 @@ build_id2ref_i(VALUE obj, void *data)
|
|||
break;
|
||||
default:
|
||||
if (rb_shape_obj_has_id(obj)) {
|
||||
RUBY_ASSERT(!rb_objspace_garbage_object_p(obj));
|
||||
st_insert(id2ref_tbl, rb_obj_id(obj), obj);
|
||||
}
|
||||
break;
|
||||
|
@ -1974,17 +1975,20 @@ object_id_to_ref(void *objspace_ptr, VALUE object_id)
|
|||
// GC Must not trigger while we build the table, otherwise if we end
|
||||
// up freeing an object that had an ID, we might try to delete it from
|
||||
// the table even though it wasn't inserted yet.
|
||||
id2ref_tbl = st_init_table(&object_id_hash_type);
|
||||
id2ref_value = TypedData_Wrap_Struct(0, &id2ref_tbl_type, id2ref_tbl);
|
||||
st_table *tmp_id2ref_tbl = st_init_table(&object_id_hash_type);
|
||||
VALUE tmp_id2ref_value = TypedData_Wrap_Struct(0, &id2ref_tbl_type, tmp_id2ref_tbl);
|
||||
|
||||
// build_id2ref_i will most certainly malloc, which could trigger GC and sweep
|
||||
// objects we just added to the table.
|
||||
bool gc_disabled = RTEST(rb_gc_disable_no_rest());
|
||||
// By calling rb_gc_disable() we also save having to handle potentially garbage objects.
|
||||
bool gc_disabled = RTEST(rb_gc_disable());
|
||||
{
|
||||
id2ref_tbl = tmp_id2ref_tbl;
|
||||
id2ref_value = tmp_id2ref_value;
|
||||
|
||||
rb_gc_impl_each_object(objspace, build_id2ref_i, (void *)id2ref_tbl);
|
||||
}
|
||||
if (!gc_disabled) rb_gc_enable();
|
||||
id2ref_tbl_built = true;
|
||||
}
|
||||
|
||||
VALUE obj;
|
||||
|
@ -2036,10 +2040,9 @@ obj_free_object_id(VALUE obj)
|
|||
RUBY_ASSERT(FIXNUM_P(obj_id) || RB_TYPE_P(obj_id, T_BIGNUM));
|
||||
|
||||
if (!st_delete(id2ref_tbl, (st_data_t *)&obj_id, NULL)) {
|
||||
// If we're currently building the table then it's not a bug.
|
||||
// The the object is a T_IMEMO/fields, then it's possible the actual object
|
||||
// has been garbage collected already.
|
||||
if (id2ref_tbl_built && !RB_TYPE_P(obj, T_IMEMO)) {
|
||||
if (!RB_TYPE_P(obj, T_IMEMO)) {
|
||||
rb_bug("Object ID seen, but not in _id2ref table: object_id=%llu object=%s", NUM2ULL(obj_id), rb_obj_info(obj));
|
||||
}
|
||||
}
|
||||
|
@ -3028,7 +3031,7 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
|
|||
mark_current_machine_context(ec);
|
||||
|
||||
MARK_CHECKPOINT("global_symbols");
|
||||
rb_sym_global_symbols_mark();
|
||||
rb_sym_global_symbols_mark_and_move();
|
||||
|
||||
MARK_CHECKPOINT("finish");
|
||||
|
||||
|
@ -3170,10 +3173,15 @@ rb_gc_mark_children(void *objspace, VALUE obj)
|
|||
break;
|
||||
|
||||
case T_DATA: {
|
||||
void *const ptr = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
|
||||
bool typed_data = RTYPEDDATA_P(obj);
|
||||
void *const ptr = typed_data ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
|
||||
|
||||
if (typed_data) {
|
||||
gc_mark_internal(RTYPEDDATA(obj)->fields_obj);
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
|
||||
if (typed_data && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
|
||||
size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj);
|
||||
|
||||
for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
|
||||
|
@ -3181,7 +3189,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
|
|||
}
|
||||
}
|
||||
else {
|
||||
RUBY_DATA_FUNC mark_func = RTYPEDDATA_P(obj) ?
|
||||
RUBY_DATA_FUNC mark_func = typed_data ?
|
||||
RTYPEDDATA_TYPE(obj)->function.dmark :
|
||||
RDATA(obj)->dmark;
|
||||
if (mark_func) (*mark_func)(ptr);
|
||||
|
@ -3260,6 +3268,10 @@ rb_gc_mark_children(void *objspace, VALUE obj)
|
|||
gc_mark_internal(ptr[i]);
|
||||
}
|
||||
|
||||
if (!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) {
|
||||
gc_mark_internal(RSTRUCT_FIELDS_OBJ(obj));
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4041,7 +4053,7 @@ rb_gc_update_vm_references(void *objspace)
|
|||
|
||||
rb_vm_update_references(vm);
|
||||
rb_gc_update_global_tbl();
|
||||
rb_sym_global_symbols_update_references();
|
||||
rb_sym_global_symbols_mark_and_move();
|
||||
|
||||
#if USE_YJIT
|
||||
void rb_yjit_root_update_references(void); // in Rust
|
||||
|
@ -4114,9 +4126,15 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
|
|||
case T_DATA:
|
||||
/* Call the compaction callback, if it exists */
|
||||
{
|
||||
void *const ptr = RTYPEDDATA_P(obj) ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
|
||||
bool typed_data = RTYPEDDATA_P(obj);
|
||||
void *const ptr = typed_data ? RTYPEDDATA_GET_DATA(obj) : DATA_PTR(obj);
|
||||
|
||||
if (typed_data) {
|
||||
UPDATE_IF_MOVED(objspace, RTYPEDDATA(obj)->fields_obj);
|
||||
}
|
||||
|
||||
if (ptr) {
|
||||
if (RTYPEDDATA_P(obj) && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
|
||||
if (typed_data && gc_declarative_marking_p(RTYPEDDATA_TYPE(obj))) {
|
||||
size_t *offset_list = TYPED_DATA_REFS_OFFSET_LIST(obj);
|
||||
|
||||
for (size_t offset = *offset_list; offset != RUBY_REF_END; offset = *offset_list++) {
|
||||
|
@ -4124,7 +4142,7 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
|
|||
*ref = gc_location_internal(objspace, *ref);
|
||||
}
|
||||
}
|
||||
else if (RTYPEDDATA_P(obj)) {
|
||||
else if (typed_data) {
|
||||
RUBY_DATA_FUNC compact_func = RTYPEDDATA_TYPE(obj)->function.dcompact;
|
||||
if (compact_func) (*compact_func)(ptr);
|
||||
}
|
||||
|
@ -4188,6 +4206,15 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
|
|||
for (i = 0; i < len; i++) {
|
||||
UPDATE_IF_MOVED(objspace, ptr[i]);
|
||||
}
|
||||
|
||||
if (RSTRUCT_EMBED_LEN(obj)) {
|
||||
if (!FL_TEST_RAW(obj, RSTRUCT_GEN_FIELDS)) {
|
||||
UPDATE_IF_MOVED(objspace, ptr[len]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
UPDATE_IF_MOVED(objspace, RSTRUCT(obj)->as.heap.fields_obj);
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
|
@ -4341,7 +4368,7 @@ gc_config_set(rb_execution_context_t *ec, VALUE self, VALUE hash)
|
|||
|
||||
rb_gc_impl_config_set(objspace, hash);
|
||||
|
||||
return rb_gc_impl_config_get(objspace);
|
||||
return Qnil;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
|
|
210
gc.rb
210
gc.rb
|
@ -7,31 +7,39 @@
|
|||
# You may obtain information about the operation of the \GC through GC::Profiler.
|
||||
module GC
|
||||
|
||||
# Initiates garbage collection, even if manually disabled.
|
||||
# Initiates garbage collection, even if explicitly disabled by GC.disable.
|
||||
#
|
||||
# The +full_mark+ keyword argument determines whether or not to perform a
|
||||
# major garbage collection cycle. When set to +true+, a major garbage
|
||||
# collection cycle is run, meaning all objects are marked. When set to
|
||||
# +false+, a minor garbage collection cycle is run, meaning only young
|
||||
# objects are marked.
|
||||
# Keyword arguments:
|
||||
#
|
||||
# The +immediate_mark+ keyword argument determines whether or not to perform
|
||||
# incremental marking. When set to +true+, marking is completed during the
|
||||
# call to this method. When set to +false+, marking is performed in steps
|
||||
# that are interleaved with future Ruby code execution, so marking might not
|
||||
# be completed during this method call. Note that if +full_mark+ is +false+,
|
||||
# then marking will always be immediate, regardless of the value of
|
||||
# +immediate_mark+.
|
||||
# - +full_mark+:
|
||||
# its boolean value determines whether to perform a major garbage collection cycle:
|
||||
#
|
||||
# The +immediate_sweep+ keyword argument determines whether or not to defer
|
||||
# sweeping (using lazy sweep). When set to +false+, sweeping is performed in
|
||||
# steps that are interleaved with future Ruby code execution, so sweeping might
|
||||
# not be completed during this method call. When set to +true+, sweeping is
|
||||
# completed during the call to this method.
|
||||
# - +true+: initiates a major garbage collection cycle,
|
||||
# meaning all objects (old and new) are marked.
|
||||
# - +false+: initiates a minor garbage collection cycle,
|
||||
# meaning only young objects are marked.
|
||||
#
|
||||
# Note: These keyword arguments are implementation and version-dependent. They
|
||||
# are not guaranteed to be future-compatible and may be ignored if the
|
||||
# underlying implementation does not support them.
|
||||
# - +immediate_mark+:
|
||||
# its boolean value determines whether to perform incremental marking:
|
||||
#
|
||||
# - +true+: marking is completed before the method returns.
|
||||
# - +false+: marking is performed by parts,
|
||||
# interleaved with program execution both before the method returns and afterward;
|
||||
# therefore marking may not be completed before the return.
|
||||
# Note that if +full_mark+ is +false+, marking will always be immediate,
|
||||
# regardless of the value of +immediate_mark+.
|
||||
#
|
||||
# - +immediate_sweep+:
|
||||
# its boolean value determines whether to defer sweeping (using lazy sweep):
|
||||
#
|
||||
# - +true+: sweeping is completed before the method returns.
|
||||
# - +false+: sweeping is performed by parts,
|
||||
# interleaved with program execution both before the method returns and afterward;
|
||||
# therefore sweeping may not be completed before the return.
|
||||
#
|
||||
# Note that these keword arguments are implementation- and version-dependent,
|
||||
# are not guaranteed to be future-compatible,
|
||||
# and may be ignored in some implementations.
|
||||
def self.start full_mark: true, immediate_mark: true, immediate_sweep: true
|
||||
Primitive.gc_start_internal full_mark, immediate_mark, immediate_sweep, false
|
||||
end
|
||||
|
@ -42,14 +50,14 @@ module GC
|
|||
end
|
||||
|
||||
# call-seq:
|
||||
# GC.enable -> true or false
|
||||
# GC.enable -> true or false
|
||||
#
|
||||
# Enables garbage collection, returning +true+ if garbage
|
||||
# collection was previously disabled.
|
||||
# Enables garbage collection;
|
||||
# returns whether garbage collection was disabled:
|
||||
#
|
||||
# GC.disable #=> false
|
||||
# GC.enable #=> true
|
||||
# GC.enable #=> false
|
||||
# GC.disable
|
||||
# GC.enable # => true
|
||||
# GC.enable # => false
|
||||
#
|
||||
def self.enable
|
||||
Primitive.gc_enable
|
||||
|
@ -58,11 +66,13 @@ module GC
|
|||
# call-seq:
|
||||
# GC.disable -> true or false
|
||||
#
|
||||
# Disables garbage collection, returning +true+ if garbage
|
||||
# collection was already disabled.
|
||||
# Disables garbage collection (but GC.start remains potent):
|
||||
# returns whether garbage collection was already disabled.
|
||||
#
|
||||
# GC.enable
|
||||
# GC.disable # => false
|
||||
# GC.disable # => true
|
||||
#
|
||||
# GC.disable #=> false
|
||||
# GC.disable #=> true
|
||||
def self.disable
|
||||
Primitive.gc_disable
|
||||
end
|
||||
|
@ -250,99 +260,111 @@ module GC
|
|||
|
||||
# call-seq:
|
||||
# GC.config -> hash
|
||||
# GC.config(hash) -> hash
|
||||
# GC.config(hash_to_merge) -> hash
|
||||
#
|
||||
# Sets or gets information about the current \GC config.
|
||||
# This method is implementation-specific to CRuby.
|
||||
#
|
||||
# Configuration parameters are \GC implementation-specific and may change
|
||||
# without notice.
|
||||
# Sets or gets information about the current \GC configuration.
|
||||
#
|
||||
# This method can be called without parameters to retrieve the current config
|
||||
# as a +Hash+ with +Symbol+ keys.
|
||||
# Configuration parameters are \GC implementation-specific and may change without notice.
|
||||
#
|
||||
# This method can also be called with a +Hash+ argument to assign values to
|
||||
# valid config keys. Config keys missing from the passed +Hash+ will be left
|
||||
# unmodified.
|
||||
# With no argument given, returns a hash containing the configuration:
|
||||
#
|
||||
# If a key/value pair is passed to this function that does not correspond to
|
||||
# a valid config key for the \GC implementation being used, no config will be
|
||||
# updated, the key will be present in the returned Hash, and its value will
|
||||
# be +nil+. This is to facilitate easy migration between \GC implementations.
|
||||
# GC.config
|
||||
# # => {rgengc_allow_full_mark: true, implementation: "default"}
|
||||
#
|
||||
# In both call-seqs, the return value of <code>GC.config</code> will be a +Hash+
|
||||
# containing the most recent full configuration, i.e., all keys and values
|
||||
# defined by the specific \GC implementation being used. In the case of a
|
||||
# config update, the return value will include the new values being updated.
|
||||
# With argument +hash_to_merge+ given,
|
||||
# merges that hash into the stored configuration hash;
|
||||
# ignores unknown hash keys;
|
||||
# returns the configuration hash:
|
||||
#
|
||||
# This method is only expected to work on CRuby.
|
||||
# GC.config(rgengc_allow_full_mark: false)
|
||||
# # => {rgengc_allow_full_mark: false, implementation: "default"}
|
||||
# GC.config(foo: 'bar')
|
||||
# # => {rgengc_allow_full_mark: false, implementation: "default"}
|
||||
#
|
||||
# === \GC Implementation independent values
|
||||
# <b>All-Implementations Configuration</b>
|
||||
#
|
||||
# The <code>GC.config</code> hash can also contain keys that are global and
|
||||
# read-only. These keys are not specific to any one \GC library implementation
|
||||
# and attempting to write to them will raise +ArgumentError+.
|
||||
# The single read-only entry for all implementations is:
|
||||
#
|
||||
# There is currently only one global, read-only key:
|
||||
# - +implementation+:
|
||||
# the string name of the implementation;
|
||||
# for the Ruby default implementation, <tt>'default'</tt>.
|
||||
#
|
||||
# [implementation]
|
||||
# Returns a +String+ containing the name of the currently loaded \GC library,
|
||||
# if one has been loaded using +RUBY_GC_LIBRARY+, and "default" in all other
|
||||
# cases
|
||||
# <b>Implementation-Specific Configuration</b>
|
||||
#
|
||||
# === \GC Implementation specific values
|
||||
# A \GC implementation maintains its own implementation-specific configuration.
|
||||
#
|
||||
# \GC libraries are expected to document their own configuration. Valid keys
|
||||
# for Ruby's default \GC implementation are:
|
||||
# For Ruby's default implementation the single entry is:
|
||||
#
|
||||
# [rgengc_allow_full_mark]
|
||||
# Controls whether the \GC is allowed to run a full mark (young & old objects).
|
||||
# - +rgengc_allow_full_mark+:
|
||||
# Controls whether the \GC is allowed to run a full mark (young & old objects):
|
||||
#
|
||||
# When +true+, \GC interleaves major and minor collections. This is the default. \GC
|
||||
# will function as intended.
|
||||
# - +true+ (default): \GC interleaves major and minor collections.
|
||||
# A flag is set to notify GC that a full mark has been requested.
|
||||
# This flag is accessible via GC.latest_gc_info(:need_major_by).
|
||||
# - +false+: \GC does not initiate a full marking cycle unless explicitly directed by user code;
|
||||
# see GC.start.
|
||||
# Setting this parameter to +false+ disables young-to-old promotion.
|
||||
# For performance reasons, we recommended warming up the application using Process.warmup
|
||||
# before setting this parameter to +false+.
|
||||
#
|
||||
# When +false+, the \GC will never trigger a full marking cycle unless
|
||||
# explicitly requested by user code. Instead, only a minor mark will run—
|
||||
# only young objects will be marked. When the heap space is exhausted, new
|
||||
# pages will be allocated immediately instead of running a full mark.
|
||||
#
|
||||
# A flag will be set to notify that a full mark has been
|
||||
# requested. This flag is accessible using
|
||||
# <code>GC.latest_gc_info(:need_major_by)</code>
|
||||
#
|
||||
# The user can trigger a major collection at any time using
|
||||
# <code>GC.start(full_mark: true)</code>
|
||||
#
|
||||
# When +false+, Young to Old object promotion is disabled. For performance
|
||||
# reasons, it is recommended to warm up an application using +Process.warmup+
|
||||
# before setting this parameter to +false+.
|
||||
def self.config hash = nil
|
||||
return Primitive.gc_config_get unless hash
|
||||
|
||||
if(Primitive.cexpr!("RBOOL(RB_TYPE_P(hash, T_HASH))"))
|
||||
if Primitive.cexpr!("RBOOL(RB_TYPE_P(hash, T_HASH))")
|
||||
if hash.include?(:implementation)
|
||||
raise ArgumentError, 'Attempting to set read-only key "Implementation"'
|
||||
end
|
||||
|
||||
Primitive.gc_config_set hash
|
||||
else
|
||||
elsif hash != nil
|
||||
raise ArgumentError
|
||||
end
|
||||
|
||||
Primitive.gc_config_get
|
||||
end
|
||||
|
||||
# call-seq:
|
||||
# GC.latest_gc_info -> hash
|
||||
# GC.latest_gc_info(hash) -> hash
|
||||
# GC.latest_gc_info(key) -> value
|
||||
# GC.latest_gc_info -> new_hash
|
||||
# GC.latest_gc_info(key) -> value
|
||||
# GC.latest_gc_info(hash) -> hash
|
||||
#
|
||||
# Returns information about the most recent garbage collection.
|
||||
# With no argument given,
|
||||
# returns information about the most recent garbage collection:
|
||||
#
|
||||
# If the argument +hash+ is given and is a Hash object,
|
||||
# it is overwritten and returned.
|
||||
# This is intended to avoid the probe effect.
|
||||
# GC.latest_gc_info
|
||||
# # =>
|
||||
# {major_by: :force,
|
||||
# need_major_by: nil,
|
||||
# gc_by: :method,
|
||||
# have_finalizer: false,
|
||||
# immediate_sweep: true,
|
||||
# state: :none,
|
||||
# weak_references_count: 0,
|
||||
# retained_weak_references_count: 0}
|
||||
#
|
||||
# With symbol argument +key+ given,
|
||||
# returns the value for that key:
|
||||
#
|
||||
# GC.latest_gc_info(:gc_by) # => :newobj
|
||||
#
|
||||
# With hash argument +hash+ given,
|
||||
# returns that hash with GC information merged into its content;
|
||||
# this form may be useful in minimizing {probe effects}[https://en.wikipedia.org/wiki/Probe_effect]:
|
||||
#
|
||||
# h = {foo: 0, bar: 1}
|
||||
# GC.latest_gc_info(h)
|
||||
# # =>
|
||||
# {foo: 0,
|
||||
# bar: 1,
|
||||
# major_by: nil,
|
||||
# need_major_by: nil,
|
||||
# gc_by: :newobj,
|
||||
# have_finalizer: false,
|
||||
# immediate_sweep: false,
|
||||
# state: :sweeping,
|
||||
# weak_references_count: 0,
|
||||
# retained_weak_references_count: 0}
|
||||
#
|
||||
# If the argument +key+ is given and is a Symbol object,
|
||||
# it returns the value associated with the key.
|
||||
# This is equivalent to <tt>GC.latest_gc_info[key]</tt>.
|
||||
def self.latest_gc_info hash_or_key = nil
|
||||
if hash_or_key == nil
|
||||
hash_or_key = {}
|
||||
|
|
|
@ -4420,7 +4420,10 @@ rb_gc_impl_mark_and_move(void *objspace_ptr, VALUE *ptr)
|
|||
GC_ASSERT(objspace->flags.during_compacting);
|
||||
GC_ASSERT(during_gc);
|
||||
|
||||
*ptr = rb_gc_impl_location(objspace, *ptr);
|
||||
VALUE destination = rb_gc_impl_location(objspace, *ptr);
|
||||
if (destination != *ptr) {
|
||||
*ptr = destination;
|
||||
}
|
||||
}
|
||||
else {
|
||||
gc_mark(objspace, *ptr);
|
||||
|
@ -6107,15 +6110,19 @@ rb_gc_impl_writebarrier_remember(void *objspace_ptr, VALUE obj)
|
|||
|
||||
gc_report(1, objspace, "rb_gc_writebarrier_remember: %s\n", rb_obj_info(obj));
|
||||
|
||||
if (is_incremental_marking(objspace)) {
|
||||
if (RVALUE_BLACK_P(objspace, obj)) {
|
||||
gc_grey(objspace, obj);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (RVALUE_OLD_P(objspace, obj)) {
|
||||
rgengc_remember(objspace, obj);
|
||||
if (is_incremental_marking(objspace) || RVALUE_OLD_P(objspace, obj)) {
|
||||
int lev = RB_GC_VM_LOCK_NO_BARRIER();
|
||||
{
|
||||
if (is_incremental_marking(objspace)) {
|
||||
if (RVALUE_BLACK_P(objspace, obj)) {
|
||||
gc_grey(objspace, obj);
|
||||
}
|
||||
}
|
||||
else if (RVALUE_OLD_P(objspace, obj)) {
|
||||
rgengc_remember(objspace, obj);
|
||||
}
|
||||
}
|
||||
RB_GC_VM_UNLOCK_NO_BARRIER(lev);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,7 +39,7 @@ ostruct 0.6.3 https://github.com/ruby/ostruct
|
|||
pstore 0.2.0 https://github.com/ruby/pstore
|
||||
benchmark 0.4.1 https://github.com/ruby/benchmark
|
||||
logger 1.7.0 https://github.com/ruby/logger
|
||||
rdoc 6.14.2 https://github.com/ruby/rdoc
|
||||
rdoc 6.14.2 https://github.com/ruby/rdoc f4a90c6010b2346cb5426d4496f5a37a136a82fb # for markdown
|
||||
win32ole 1.9.2 https://github.com/ruby/win32ole
|
||||
irb 1.15.2 https://github.com/ruby/irb 331c4e851296b115db766c291e8cf54a2492fb36
|
||||
reline 0.6.2 https://github.com/ruby/reline
|
||||
|
|
37
hash.c
37
hash.c
|
@ -5192,25 +5192,26 @@ env_enc_str_new(const char *ptr, long len, rb_encoding *enc)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
env_str_new(const char *ptr, long len)
|
||||
env_str_new(const char *ptr, long len, rb_encoding *enc)
|
||||
{
|
||||
return env_enc_str_new(ptr, len, env_encoding());
|
||||
return env_enc_str_new(ptr, len, enc);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
env_str_new2(const char *ptr)
|
||||
env_str_new2(const char *ptr, rb_encoding *enc)
|
||||
{
|
||||
if (!ptr) return Qnil;
|
||||
return env_str_new(ptr, strlen(ptr));
|
||||
return env_str_new(ptr, strlen(ptr), enc);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
getenv_with_lock(const char *name)
|
||||
{
|
||||
VALUE ret;
|
||||
rb_encoding *enc = env_encoding();
|
||||
ENV_LOCKING() {
|
||||
const char *val = getenv(name);
|
||||
ret = env_str_new2(val);
|
||||
ret = env_str_new2(val, enc);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
@ -5773,13 +5774,14 @@ env_values(void)
|
|||
{
|
||||
VALUE ary = rb_ary_new();
|
||||
|
||||
rb_encoding *enc = env_encoding();
|
||||
ENV_LOCKING() {
|
||||
char **env = GET_ENVIRON(environ);
|
||||
|
||||
while (*env) {
|
||||
char *s = strchr(*env, '=');
|
||||
if (s) {
|
||||
rb_ary_push(ary, env_str_new2(s+1));
|
||||
rb_ary_push(ary, env_str_new2(s+1, enc));
|
||||
}
|
||||
env++;
|
||||
}
|
||||
|
@ -5865,14 +5867,15 @@ env_each_pair(VALUE ehash)
|
|||
|
||||
VALUE ary = rb_ary_new();
|
||||
|
||||
rb_encoding *enc = env_encoding();
|
||||
ENV_LOCKING() {
|
||||
char **env = GET_ENVIRON(environ);
|
||||
|
||||
while (*env) {
|
||||
char *s = strchr(*env, '=');
|
||||
if (s) {
|
||||
rb_ary_push(ary, env_str_new(*env, s-*env));
|
||||
rb_ary_push(ary, env_str_new2(s+1));
|
||||
rb_ary_push(ary, env_str_new(*env, s-*env, enc));
|
||||
rb_ary_push(ary, env_str_new2(s+1, enc));
|
||||
}
|
||||
env++;
|
||||
}
|
||||
|
@ -6255,13 +6258,14 @@ env_to_a(VALUE _)
|
|||
{
|
||||
VALUE ary = rb_ary_new();
|
||||
|
||||
rb_encoding *enc = env_encoding();
|
||||
ENV_LOCKING() {
|
||||
char **env = GET_ENVIRON(environ);
|
||||
while (*env) {
|
||||
char *s = strchr(*env, '=');
|
||||
if (s) {
|
||||
rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env),
|
||||
env_str_new2(s+1)));
|
||||
rb_ary_push(ary, rb_assoc_new(env_str_new(*env, s-*env, enc),
|
||||
env_str_new2(s+1, enc)));
|
||||
}
|
||||
env++;
|
||||
}
|
||||
|
@ -6509,6 +6513,7 @@ env_key(VALUE dmy, VALUE value)
|
|||
StringValue(value);
|
||||
VALUE str = Qnil;
|
||||
|
||||
rb_encoding *enc = env_encoding();
|
||||
ENV_LOCKING() {
|
||||
char **env = GET_ENVIRON(environ);
|
||||
while (*env) {
|
||||
|
@ -6516,7 +6521,7 @@ env_key(VALUE dmy, VALUE value)
|
|||
if (s++) {
|
||||
long len = strlen(s);
|
||||
if (RSTRING_LEN(value) == len && strncmp(s, RSTRING_PTR(value), len) == 0) {
|
||||
str = env_str_new(*env, s-*env-1);
|
||||
str = env_str_new(*env, s-*env-1, enc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -6533,13 +6538,14 @@ env_to_hash(void)
|
|||
{
|
||||
VALUE hash = rb_hash_new();
|
||||
|
||||
rb_encoding *enc = env_encoding();
|
||||
ENV_LOCKING() {
|
||||
char **env = GET_ENVIRON(environ);
|
||||
while (*env) {
|
||||
char *s = strchr(*env, '=');
|
||||
if (s) {
|
||||
rb_hash_aset(hash, env_str_new(*env, s-*env),
|
||||
env_str_new2(s+1));
|
||||
rb_hash_aset(hash, env_str_new(*env, s-*env, enc),
|
||||
env_str_new2(s+1, enc));
|
||||
}
|
||||
env++;
|
||||
}
|
||||
|
@ -6684,14 +6690,15 @@ env_shift(VALUE _)
|
|||
VALUE result = Qnil;
|
||||
VALUE key = Qnil;
|
||||
|
||||
rb_encoding *enc = env_encoding();
|
||||
ENV_LOCKING() {
|
||||
char **env = GET_ENVIRON(environ);
|
||||
if (*env) {
|
||||
const char *p = *env;
|
||||
char *s = strchr(p, '=');
|
||||
if (s) {
|
||||
key = env_str_new(p, s-p);
|
||||
VALUE val = env_str_new2(getenv(RSTRING_PTR(key)));
|
||||
key = env_str_new(p, s-p, enc);
|
||||
VALUE val = env_str_new2(getenv(RSTRING_PTR(key)), enc);
|
||||
result = rb_assoc_new(key, val);
|
||||
}
|
||||
}
|
||||
|
|
36
imemo.c
36
imemo.c
|
@ -337,32 +337,44 @@ rb_imemo_mark_and_move(VALUE obj, bool reference_updating)
|
|||
* cc->klass (klass) should not be marked because if the klass is
|
||||
* free'ed, the cc->klass will be cleared by `vm_cc_invalidate()`.
|
||||
*
|
||||
* cc->cme (cme) should not be marked because if cc is invalidated
|
||||
* when cme is free'ed.
|
||||
* For "normal" CCs cc->cme (cme) should not be marked because the cc is
|
||||
* invalidated through the klass when the cme is free'd.
|
||||
* - klass marks cme if klass uses cme.
|
||||
* - caller classe's ccs->cme marks cc->cme.
|
||||
* - if cc is invalidated (klass doesn't refer the cc),
|
||||
* cc is invalidated by `vm_cc_invalidate()` and cc->cme is
|
||||
* not be accessed.
|
||||
* - On the multi-Ractors, cme will be collected with global GC
|
||||
* - caller class's ccs->cme marks cc->cme.
|
||||
* - if cc is invalidated (klass doesn't refer the cc), cc is
|
||||
* invalidated by `vm_cc_invalidate()` after which cc->cme must not
|
||||
* be accessed.
|
||||
* - With multi-Ractors, cme will be collected with global GC
|
||||
* so that it is safe if GC is not interleaving while accessing
|
||||
* cc and cme.
|
||||
* - However, cc_type_super and cc_type_refinement are not chained
|
||||
* from ccs so cc->cme should be marked; the cme might be
|
||||
* reachable only through cc in these cases.
|
||||
*
|
||||
* However cc_type_super and cc_type_refinement are not chained
|
||||
* from ccs so cc->cme should be marked as long as the cc is valid;
|
||||
* the cme might be reachable only through cc in these cases.
|
||||
*/
|
||||
struct rb_callcache *cc = (struct rb_callcache *)obj;
|
||||
if (reference_updating) {
|
||||
if (UNDEF_P(cc->klass)) {
|
||||
/* If it's invalidated, we must not mark anything.
|
||||
* All fields should are considered invalid
|
||||
*/
|
||||
}
|
||||
else if (reference_updating) {
|
||||
if (moved_or_living_object_strictly_p((VALUE)cc->cme_)) {
|
||||
*((VALUE *)&cc->klass) = rb_gc_location(cc->klass);
|
||||
*((struct rb_callable_method_entry_struct **)&cc->cme_) =
|
||||
(struct rb_callable_method_entry_struct *)rb_gc_location((VALUE)cc->cme_);
|
||||
|
||||
RUBY_ASSERT(RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
|
||||
RUBY_ASSERT(IMEMO_TYPE_P((VALUE)cc->cme_, imemo_ment));
|
||||
}
|
||||
else if (vm_cc_valid(cc)) {
|
||||
else {
|
||||
vm_cc_invalidate(cc);
|
||||
}
|
||||
}
|
||||
else {
|
||||
RUBY_ASSERT(RB_TYPE_P(cc->klass, T_CLASS) || RB_TYPE_P(cc->klass, T_ICLASS));
|
||||
RUBY_ASSERT(IMEMO_TYPE_P((VALUE)cc->cme_, imemo_ment));
|
||||
|
||||
rb_gc_mark_weak((VALUE *)&cc->klass);
|
||||
if ((vm_cc_super_p(cc) || vm_cc_refinement_p(cc))) {
|
||||
rb_gc_mark_movable((VALUE)cc->cme_);
|
||||
|
|
|
@ -84,6 +84,28 @@ typedef unsigned int rb_atomic_t;
|
|||
# error No atomic operation found
|
||||
#endif
|
||||
|
||||
/* Memory ordering constants */
|
||||
#if defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
# define RBIMPL_ATOMIC_RELAXED __ATOMIC_RELAXED
|
||||
# define RBIMPL_ATOMIC_ACQUIRE __ATOMIC_ACQUIRE
|
||||
# define RBIMPL_ATOMIC_RELEASE __ATOMIC_RELEASE
|
||||
# define RBIMPL_ATOMIC_ACQ_REL __ATOMIC_ACQ_REL
|
||||
# define RBIMPL_ATOMIC_SEQ_CST __ATOMIC_SEQ_CST
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
# define RBIMPL_ATOMIC_RELAXED memory_order_relaxed
|
||||
# define RBIMPL_ATOMIC_ACQUIRE memory_order_acquire
|
||||
# define RBIMPL_ATOMIC_RELEASE memory_order_release
|
||||
# define RBIMPL_ATOMIC_ACQ_REL memory_order_acq_rel
|
||||
# define RBIMPL_ATOMIC_SEQ_CST memory_order_seq_cst
|
||||
#else
|
||||
/* Dummy values for unsupported platforms */
|
||||
# define RBIMPL_ATOMIC_RELAXED 0
|
||||
# define RBIMPL_ATOMIC_ACQUIRE 1
|
||||
# define RBIMPL_ATOMIC_RELEASE 2
|
||||
# define RBIMPL_ATOMIC_ACQ_REL 3
|
||||
# define RBIMPL_ATOMIC_SEQ_CST 4
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Atomically replaces the value pointed by `var` with the result of addition
|
||||
* of `val` to the old value of `var`.
|
||||
|
@ -93,7 +115,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return What was stored in `var` before the addition.
|
||||
* @post `var` holds `var + val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val))
|
||||
#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Atomically replaces the value pointed by `var` with the result of
|
||||
|
@ -104,7 +126,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return What was stored in `var` before the subtraction.
|
||||
* @post `var` holds `var - val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_FETCH_SUB(var, val) rbimpl_atomic_fetch_sub(&(var), (val))
|
||||
#define RUBY_ATOMIC_FETCH_SUB(var, val) rbimpl_atomic_fetch_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Atomically replaces the value pointed by `var` with the result of
|
||||
|
@ -116,7 +138,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @post `var` holds `var | val`.
|
||||
* @note For portability, this macro can return void.
|
||||
*/
|
||||
#define RUBY_ATOMIC_OR(var, val) rbimpl_atomic_or(&(var), (val))
|
||||
#define RUBY_ATOMIC_OR(var, val) rbimpl_atomic_or(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Atomically replaces the value pointed by `var` with `val`. This is just an
|
||||
|
@ -127,7 +149,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return What was stored in `var` before the assignment.
|
||||
* @post `var` holds `val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_EXCHANGE(var, val) rbimpl_atomic_exchange(&(var), (val))
|
||||
#define RUBY_ATOMIC_EXCHANGE(var, val) rbimpl_atomic_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Atomic compare-and-swap. This stores `val` to `var` if and only if the
|
||||
|
@ -141,7 +163,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @retval otherwise Something else is at `var`; not updated.
|
||||
*/
|
||||
#define RUBY_ATOMIC_CAS(var, oldval, newval) \
|
||||
rbimpl_atomic_cas(&(var), (oldval), (newval))
|
||||
rbimpl_atomic_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Atomic load. This loads `var` with an atomic intrinsic and returns
|
||||
|
@ -150,7 +172,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @param var A variable of ::rb_atomic_t
|
||||
* @return What was stored in `var`j
|
||||
*/
|
||||
#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var))
|
||||
#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_EXCHANGE, except for the return type.
|
||||
|
@ -160,7 +182,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return void
|
||||
* @post `var` holds `val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_set(&(var), (val))
|
||||
#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_store(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_FETCH_ADD, except for the return type.
|
||||
|
@ -170,7 +192,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return void
|
||||
* @post `var` holds `var + val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_ADD(var, val) rbimpl_atomic_add(&(var), (val))
|
||||
#define RUBY_ATOMIC_ADD(var, val) rbimpl_atomic_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_FETCH_SUB, except for the return type.
|
||||
|
@ -180,7 +202,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return void
|
||||
* @post `var` holds `var - val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_SUB(var, val) rbimpl_atomic_sub(&(var), (val))
|
||||
#define RUBY_ATOMIC_SUB(var, val) rbimpl_atomic_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Atomically increments the value pointed by `var`.
|
||||
|
@ -189,7 +211,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return void
|
||||
* @post `var` holds `var + 1`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_INC(var) rbimpl_atomic_inc(&(var))
|
||||
#define RUBY_ATOMIC_INC(var) rbimpl_atomic_inc(&(var), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Atomically decrements the value pointed by `var`.
|
||||
|
@ -198,7 +220,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return void
|
||||
* @post `var` holds `var - 1`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_DEC(var) rbimpl_atomic_dec(&(var))
|
||||
#define RUBY_ATOMIC_DEC(var) rbimpl_atomic_dec(&(var), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_FETCH_ADD, except it expects its arguments to be `size_t`.
|
||||
|
@ -210,7 +232,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return What was stored in `var` before the addition.
|
||||
* @post `var` holds `var + val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_SIZE_FETCH_ADD(var, val) rbimpl_atomic_size_fetch_add(&(var), (val))
|
||||
#define RUBY_ATOMIC_SIZE_FETCH_ADD(var, val) rbimpl_atomic_size_fetch_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_INC, except it expects its argument is `size_t`.
|
||||
|
@ -221,7 +243,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return void
|
||||
* @post `var` holds `var + 1`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_SIZE_INC(var) rbimpl_atomic_size_inc(&(var))
|
||||
#define RUBY_ATOMIC_SIZE_INC(var) rbimpl_atomic_size_inc(&(var), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_DEC, except it expects its argument is `size_t`.
|
||||
|
@ -232,7 +254,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return void
|
||||
* @post `var` holds `var - 1`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_SIZE_DEC(var) rbimpl_atomic_size_dec(&(var))
|
||||
#define RUBY_ATOMIC_SIZE_DEC(var) rbimpl_atomic_size_dec(&(var), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
|
||||
|
@ -246,7 +268,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @post `var` holds `val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) \
|
||||
rbimpl_atomic_size_exchange(&(var), (val))
|
||||
rbimpl_atomic_size_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `size_t`.
|
||||
|
@ -260,7 +282,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @retval otherwise Something else is at `var`; not updated.
|
||||
*/
|
||||
#define RUBY_ATOMIC_SIZE_CAS(var, oldval, newval) \
|
||||
rbimpl_atomic_size_cas(&(var), (oldval), (newval))
|
||||
rbimpl_atomic_size_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_ADD, except it expects its arguments are `size_t`.
|
||||
|
@ -272,7 +294,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return void
|
||||
* @post `var` holds `var + val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_SIZE_ADD(var, val) rbimpl_atomic_size_add(&(var), (val))
|
||||
#define RUBY_ATOMIC_SIZE_ADD(var, val) rbimpl_atomic_size_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_SUB, except it expects its arguments are `size_t`.
|
||||
|
@ -284,7 +306,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return void
|
||||
* @post `var` holds `var - val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_SIZE_SUB(var, val) rbimpl_atomic_size_sub(&(var), (val))
|
||||
#define RUBY_ATOMIC_SIZE_SUB(var, val) rbimpl_atomic_size_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
|
||||
|
@ -303,7 +325,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* some pointers, most notably function pointers.
|
||||
*/
|
||||
#define RUBY_ATOMIC_PTR_EXCHANGE(var, val) \
|
||||
RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val))
|
||||
RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val, RBIMPL_ATOMIC_SEQ_CST))
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_LOAD, except it expects its arguments are `void*`.
|
||||
|
@ -314,7 +336,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @return The value of `var` (without tearing)
|
||||
*/
|
||||
#define RUBY_ATOMIC_PTR_LOAD(var) \
|
||||
RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var))
|
||||
RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var, RBIMPL_ATOMIC_SEQ_CST))
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_SET, except it expects its arguments are
|
||||
|
@ -327,7 +349,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @post `var` holds `val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_PTR_SET(var, val) \
|
||||
rbimpl_atomic_ptr_set((volatile void **)&(var), (val))
|
||||
rbimpl_atomic_ptr_store((volatile void **)&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `void*`.
|
||||
|
@ -341,7 +363,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @retval otherwise Something else is at `var`; not updated.
|
||||
*/
|
||||
#define RUBY_ATOMIC_PTR_CAS(var, oldval, newval) \
|
||||
RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (void *)(oldval), (void *)(newval)))
|
||||
RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (void *)(oldval), (void *)(newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST))
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_SET, except it expects its arguments are
|
||||
|
@ -354,7 +376,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @post `var` holds `val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_VALUE_SET(var, val) \
|
||||
rbimpl_atomic_value_set(&(var), (val))
|
||||
rbimpl_atomic_value_store(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
|
||||
|
@ -368,7 +390,7 @@ typedef unsigned int rb_atomic_t;
|
|||
* @post `var` holds `val`.
|
||||
*/
|
||||
#define RUBY_ATOMIC_VALUE_EXCHANGE(var, val) \
|
||||
rbimpl_atomic_value_exchange(&(var), (val))
|
||||
rbimpl_atomic_value_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/**
|
||||
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are ::VALUE.
|
||||
|
@ -382,19 +404,20 @@ typedef unsigned int rb_atomic_t;
|
|||
* @retval otherwise Something else is at `var`; not updated.
|
||||
*/
|
||||
#define RUBY_ATOMIC_VALUE_CAS(var, oldval, newval) \
|
||||
rbimpl_atomic_value_cas(&(var), (oldval), (newval))
|
||||
rbimpl_atomic_value_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/** @cond INTERNAL_MACRO */
|
||||
RBIMPL_ATTR_ARTIFICIAL()
|
||||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline rb_atomic_t
|
||||
rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
||||
rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST);
|
||||
return __atomic_fetch_add(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
return __sync_fetch_and_add(ptr, val);
|
||||
|
@ -412,7 +435,7 @@ rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
|||
return atomic_add_int_nv(ptr, val) - val;
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
return atomic_fetch_add((_Atomic volatile rb_atomic_t *)ptr, val);
|
||||
return atomic_fetch_add_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -424,12 +447,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline size_t
|
||||
rbimpl_atomic_size_fetch_add(volatile size_t *ptr, size_t val)
|
||||
rbimpl_atomic_size_fetch_add(volatile size_t *ptr, size_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST);
|
||||
return __atomic_fetch_add(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
return __sync_fetch_and_add(ptr, val);
|
||||
|
@ -446,10 +470,10 @@ rbimpl_atomic_size_fetch_add(volatile size_t *ptr, size_t val)
|
|||
RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
|
||||
|
||||
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
|
||||
rbimpl_atomic_fetch_add(tmp, val);
|
||||
rbimpl_atomic_fetch_add(tmp, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
return atomic_fetch_add((_Atomic volatile size_t *)ptr, val);
|
||||
return atomic_fetch_add_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -460,8 +484,9 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
||||
rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
|
@ -470,7 +495,7 @@ rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
|||
* return value is not used, then compiles it into single `LOCK ADD`
|
||||
* instruction.
|
||||
*/
|
||||
__atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST);
|
||||
__atomic_add_fetch(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
__sync_add_and_fetch(ptr, val);
|
||||
|
@ -489,7 +514,7 @@ rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
|||
atomic_add_int(ptr, val);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
*(_Atomic volatile rb_atomic_t *)ptr += val;
|
||||
atomic_fetch_add_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -500,12 +525,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_size_add(volatile size_t *ptr, size_t val)
|
||||
rbimpl_atomic_size_add(volatile size_t *ptr, size_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
__atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST);
|
||||
__atomic_add_fetch(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
__sync_add_and_fetch(ptr, val);
|
||||
|
@ -523,10 +549,10 @@ rbimpl_atomic_size_add(volatile size_t *ptr, size_t val)
|
|||
RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
|
||||
|
||||
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
|
||||
rbimpl_atomic_add(tmp, val);
|
||||
rbimpl_atomic_add(tmp, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
*(_Atomic volatile size_t *)ptr += val;
|
||||
atomic_fetch_add_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -537,12 +563,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_inc(volatile rb_atomic_t *ptr)
|
||||
rbimpl_atomic_inc(volatile rb_atomic_t *ptr, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
rbimpl_atomic_add(ptr, 1);
|
||||
rbimpl_atomic_add(ptr, 1, memory_order);
|
||||
|
||||
#elif defined(_WIN32)
|
||||
InterlockedIncrement(ptr);
|
||||
|
@ -551,7 +578,7 @@ rbimpl_atomic_inc(volatile rb_atomic_t *ptr)
|
|||
atomic_inc_uint(ptr);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
rbimpl_atomic_add(ptr, 1);
|
||||
rbimpl_atomic_add(ptr, 1, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -562,12 +589,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_size_inc(volatile size_t *ptr)
|
||||
rbimpl_atomic_size_inc(volatile size_t *ptr, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
rbimpl_atomic_size_add(ptr, 1);
|
||||
rbimpl_atomic_size_add(ptr, 1, memory_order);
|
||||
|
||||
#elif defined(_WIN64)
|
||||
InterlockedIncrement64(ptr);
|
||||
|
@ -578,10 +606,10 @@ rbimpl_atomic_size_inc(volatile size_t *ptr)
|
|||
#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
|
||||
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
|
||||
|
||||
rbimpl_atomic_size_add(ptr, 1);
|
||||
rbimpl_atomic_size_add(ptr, 1, memory_order);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
rbimpl_atomic_size_add(ptr, 1);
|
||||
rbimpl_atomic_size_add(ptr, 1, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -592,12 +620,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline rb_atomic_t
|
||||
rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
||||
rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
return __atomic_fetch_sub(ptr, val, __ATOMIC_SEQ_CST);
|
||||
return __atomic_fetch_sub(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
return __sync_fetch_and_sub(ptr, val);
|
||||
|
@ -613,7 +642,7 @@ rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
|||
return atomic_add_int_nv(ptr, neg * val) + val;
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
return atomic_fetch_sub((_Atomic volatile rb_atomic_t *)ptr, val);
|
||||
return atomic_fetch_sub_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -624,12 +653,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
||||
rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
__atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST);
|
||||
__atomic_sub_fetch(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
__sync_sub_and_fetch(ptr, val);
|
||||
|
@ -643,7 +673,7 @@ rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
|||
atomic_add_int(ptr, neg * val);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
*(_Atomic volatile rb_atomic_t *)ptr -= val;
|
||||
atomic_fetch_sub_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -654,12 +684,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val)
|
||||
rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
__atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST);
|
||||
__atomic_sub_fetch(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
__sync_sub_and_fetch(ptr, val);
|
||||
|
@ -677,10 +708,10 @@ rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val)
|
|||
RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
|
||||
|
||||
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
|
||||
rbimpl_atomic_sub(tmp, val);
|
||||
rbimpl_atomic_sub(tmp, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
*(_Atomic volatile size_t *)ptr -= val;
|
||||
atomic_fetch_sub_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -691,12 +722,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_dec(volatile rb_atomic_t *ptr)
|
||||
rbimpl_atomic_dec(volatile rb_atomic_t *ptr, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
rbimpl_atomic_sub(ptr, 1);
|
||||
rbimpl_atomic_sub(ptr, 1, memory_order);
|
||||
|
||||
#elif defined(_WIN32)
|
||||
InterlockedDecrement(ptr);
|
||||
|
@ -705,7 +737,7 @@ rbimpl_atomic_dec(volatile rb_atomic_t *ptr)
|
|||
atomic_dec_uint(ptr);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
rbimpl_atomic_sub(ptr, 1);
|
||||
rbimpl_atomic_sub(ptr, 1, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -716,12 +748,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_size_dec(volatile size_t *ptr)
|
||||
rbimpl_atomic_size_dec(volatile size_t *ptr, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
rbimpl_atomic_size_sub(ptr, 1);
|
||||
rbimpl_atomic_size_sub(ptr, 1, memory_order);
|
||||
|
||||
#elif defined(_WIN64)
|
||||
InterlockedDecrement64(ptr);
|
||||
|
@ -732,10 +765,10 @@ rbimpl_atomic_size_dec(volatile size_t *ptr)
|
|||
#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
|
||||
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
|
||||
|
||||
rbimpl_atomic_size_sub(ptr, 1);
|
||||
rbimpl_atomic_size_sub(ptr, 1, memory_order);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
rbimpl_atomic_size_sub(ptr, 1);
|
||||
rbimpl_atomic_size_sub(ptr, 1, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -746,12 +779,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
||||
rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
__atomic_or_fetch(ptr, val, __ATOMIC_SEQ_CST);
|
||||
__atomic_or_fetch(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
__sync_or_and_fetch(ptr, val);
|
||||
|
@ -776,7 +810,7 @@ rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
|||
atomic_or_uint(ptr, val);
|
||||
|
||||
#elif !defined(_WIN32) && defined(HAVE_STDATOMIC_H)
|
||||
*(_Atomic volatile rb_atomic_t *)ptr |= val;
|
||||
atomic_fetch_or_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -796,12 +830,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline rb_atomic_t
|
||||
rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
||||
rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST);
|
||||
return __atomic_exchange_n(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
return __sync_lock_test_and_set(ptr, val);
|
||||
|
@ -813,7 +848,7 @@ rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
|||
return atomic_swap_uint(ptr, val);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
return atomic_exchange((_Atomic volatile rb_atomic_t *)ptr, val);
|
||||
return atomic_exchange_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -824,12 +859,13 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline size_t
|
||||
rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val)
|
||||
rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST);
|
||||
return __atomic_exchange_n(ptr, val, memory_order);
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
return __sync_lock_test_and_set(ptr, val);
|
||||
|
@ -844,11 +880,11 @@ rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val)
|
|||
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
|
||||
|
||||
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
|
||||
const rb_atomic_t ret = rbimpl_atomic_exchange(tmp, val);
|
||||
const rb_atomic_t ret = rbimpl_atomic_exchange(tmp, val, memory_order);
|
||||
return RBIMPL_CAST((size_t)ret);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
return atomic_exchange((_Atomic volatile size_t *)ptr, val);
|
||||
return atomic_exchange_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
# error Unsupported platform.
|
||||
|
@ -859,15 +895,16 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_size_set(volatile size_t *ptr, size_t val)
|
||||
rbimpl_atomic_size_store(volatile size_t *ptr, size_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
__atomic_store_n(ptr, val, __ATOMIC_SEQ_CST);
|
||||
__atomic_store_n(ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
rbimpl_atomic_size_exchange(ptr, val);
|
||||
rbimpl_atomic_size_exchange(ptr, val, memory_order);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
@ -876,8 +913,9 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void *
|
||||
rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val)
|
||||
rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(InterlockedExchangePointer)
|
||||
|
@ -894,7 +932,7 @@ rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val)
|
|||
|
||||
const size_t sval = RBIMPL_CAST((size_t)val);
|
||||
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
|
||||
const size_t sret = rbimpl_atomic_size_exchange(sptr, sval);
|
||||
const size_t sret = rbimpl_atomic_size_exchange(sptr, sval, memory_order);
|
||||
return RBIMPL_CAST((void *)sret);
|
||||
|
||||
#endif
|
||||
|
@ -904,26 +942,26 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_ptr_set(volatile void **ptr, void *val)
|
||||
rbimpl_atomic_ptr_store(volatile void **ptr, void *val, int memory_order)
|
||||
{
|
||||
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
|
||||
|
||||
const size_t sval = RBIMPL_CAST((size_t)val);
|
||||
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
|
||||
rbimpl_atomic_size_set(sptr, sval);
|
||||
rbimpl_atomic_size_store(sptr, sval, memory_order);
|
||||
}
|
||||
|
||||
RBIMPL_ATTR_ARTIFICIAL()
|
||||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline VALUE
|
||||
rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val)
|
||||
rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val, int memory_order)
|
||||
{
|
||||
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
|
||||
|
||||
const size_t sval = RBIMPL_CAST((size_t)val);
|
||||
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
|
||||
const size_t sret = rbimpl_atomic_size_exchange(sptr, sval);
|
||||
const size_t sret = rbimpl_atomic_size_exchange(sptr, sval, memory_order);
|
||||
return RBIMPL_CAST((VALUE)sret);
|
||||
}
|
||||
|
||||
|
@ -931,27 +969,28 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_value_set(volatile VALUE *ptr, VALUE val)
|
||||
rbimpl_atomic_value_store(volatile VALUE *ptr, VALUE val, int memory_order)
|
||||
{
|
||||
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
|
||||
|
||||
const size_t sval = RBIMPL_CAST((size_t)val);
|
||||
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
|
||||
rbimpl_atomic_size_set(sptr, sval);
|
||||
rbimpl_atomic_size_store(sptr, sval, memory_order);
|
||||
}
|
||||
|
||||
RBIMPL_ATTR_ARTIFICIAL()
|
||||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline rb_atomic_t
|
||||
rbimpl_atomic_load(volatile rb_atomic_t *ptr)
|
||||
rbimpl_atomic_load(volatile rb_atomic_t *ptr, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
|
||||
return __atomic_load_n(ptr, memory_order);
|
||||
#else
|
||||
return rbimpl_atomic_fetch_add(ptr, 0);
|
||||
return rbimpl_atomic_fetch_add(ptr, 0, memory_order);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -959,16 +998,17 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void
|
||||
rbimpl_atomic_set(volatile rb_atomic_t *ptr, rb_atomic_t val)
|
||||
rbimpl_atomic_store(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
__atomic_store_n(ptr, val, __ATOMIC_SEQ_CST);
|
||||
__atomic_store_n(ptr, val, memory_order);
|
||||
|
||||
#else
|
||||
/* Maybe std::atomic<rb_atomic_t>::store can be faster? */
|
||||
rbimpl_atomic_exchange(ptr, val);
|
||||
rbimpl_atomic_exchange(ptr, val, memory_order);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
@ -977,13 +1017,15 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline rb_atomic_t
|
||||
rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t newval)
|
||||
rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t newval, int success_memorder, int failure_memorder)
|
||||
{
|
||||
(void)success_memorder;
|
||||
(void)failure_memorder;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
__atomic_compare_exchange_n(
|
||||
ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
ptr, &oldval, newval, 0, success_memorder, failure_memorder);
|
||||
return oldval;
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
|
@ -1003,8 +1045,8 @@ rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t new
|
|||
return atomic_cas_uint(ptr, oldval, newval);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
atomic_compare_exchange_strong(
|
||||
(_Atomic volatile rb_atomic_t *)ptr, &oldval, newval);
|
||||
atomic_compare_exchange_strong_explicit(
|
||||
(_Atomic volatile rb_atomic_t *)ptr, &oldval, newval, success_memorder, failure_memorder);
|
||||
return oldval;
|
||||
|
||||
#else
|
||||
|
@ -1025,13 +1067,15 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline size_t
|
||||
rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval)
|
||||
rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval, int success_memorder, int failure_memorder)
|
||||
{
|
||||
(void)success_memorder;
|
||||
(void)failure_memorder;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
__atomic_compare_exchange_n(
|
||||
ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
|
||||
ptr, &oldval, newval, 0, success_memorder, failure_memorder);
|
||||
return oldval;
|
||||
|
||||
#elif defined(HAVE_GCC_SYNC_BUILTINS)
|
||||
|
@ -1047,11 +1091,11 @@ rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval)
|
|||
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
|
||||
|
||||
volatile rb_atomic_t *tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
|
||||
return rbimpl_atomic_cas(tmp, oldval, newval);
|
||||
return rbimpl_atomic_cas(tmp, oldval, newval, success_memorder, failure_memorder);
|
||||
|
||||
#elif defined(HAVE_STDATOMIC_H)
|
||||
atomic_compare_exchange_strong(
|
||||
(_Atomic volatile size_t *)ptr, &oldval, newval);
|
||||
atomic_compare_exchange_strong_explicit(
|
||||
(_Atomic volatile size_t *)ptr, &oldval, newval, success_memorder, failure_memorder);
|
||||
return oldval;
|
||||
|
||||
#else
|
||||
|
@ -1063,8 +1107,10 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void *
|
||||
rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
|
||||
rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval, int success_memorder, int failure_memorder)
|
||||
{
|
||||
(void)success_memorder;
|
||||
(void)failure_memorder;
|
||||
#if 0
|
||||
|
||||
#elif defined(InterlockedExchangePointer)
|
||||
|
@ -1087,7 +1133,7 @@ rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
|
|||
const size_t snew = RBIMPL_CAST((size_t)newval);
|
||||
const size_t sold = RBIMPL_CAST((size_t)oldval);
|
||||
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
|
||||
const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew);
|
||||
const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew, success_memorder, failure_memorder);
|
||||
return RBIMPL_CAST((void *)sret);
|
||||
|
||||
#endif
|
||||
|
@ -1097,15 +1143,16 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline void *
|
||||
rbimpl_atomic_ptr_load(void **ptr)
|
||||
rbimpl_atomic_ptr_load(void **ptr, int memory_order)
|
||||
{
|
||||
(void)memory_order;
|
||||
#if 0
|
||||
|
||||
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
return __atomic_load_n(ptr, __ATOMIC_SEQ_CST);
|
||||
return __atomic_load_n(ptr, memory_order);
|
||||
#else
|
||||
void *val = *ptr;
|
||||
return rbimpl_atomic_ptr_cas(ptr, val, val);
|
||||
return rbimpl_atomic_ptr_cas(ptr, val, val, memory_order, memory_order);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -1113,14 +1160,23 @@ RBIMPL_ATTR_ARTIFICIAL()
|
|||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline VALUE
|
||||
rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval)
|
||||
rbimpl_atomic_value_load(volatile VALUE *ptr, int memory_order)
|
||||
{
|
||||
return RBIMPL_CAST((VALUE)rbimpl_atomic_ptr_load((void **)ptr, memory_order));
|
||||
}
|
||||
|
||||
RBIMPL_ATTR_ARTIFICIAL()
|
||||
RBIMPL_ATTR_NOALIAS()
|
||||
RBIMPL_ATTR_NONNULL((1))
|
||||
static inline VALUE
|
||||
rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval, int success_memorder, int failure_memorder)
|
||||
{
|
||||
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
|
||||
|
||||
const size_t snew = RBIMPL_CAST((size_t)newval);
|
||||
const size_t sold = RBIMPL_CAST((size_t)oldval);
|
||||
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
|
||||
const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew);
|
||||
const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew, success_memorder, failure_memorder);
|
||||
return RBIMPL_CAST((VALUE)sret);
|
||||
}
|
||||
/** @endcond */
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
* In released versions of Ruby, this number is not defined since teeny
|
||||
* versions of Ruby should guarantee ABI compatibility.
|
||||
*/
|
||||
#define RUBY_ABI_VERSION 2
|
||||
#define RUBY_ABI_VERSION 3
|
||||
|
||||
/* Windows does not support weak symbols so ruby_abi_version will not exist
|
||||
* in the shared library. */
|
||||
|
|
|
@ -133,12 +133,6 @@ struct RData {
|
|||
*/
|
||||
RUBY_DATA_FUNC dmark;
|
||||
|
||||
/** Pointer to the actual C level struct that you want to wrap.
|
||||
* This is in between dmark and dfree to allow DATA_PTR to continue
|
||||
* to work for both RData and non-embedded RTypedData.
|
||||
*/
|
||||
void *data;
|
||||
|
||||
/**
|
||||
* This function is called when the object is no longer used. You need to
|
||||
* do whatever necessary to avoid memory leaks.
|
||||
|
@ -147,6 +141,12 @@ struct RData {
|
|||
* impossible at that moment (that is why GC runs).
|
||||
*/
|
||||
RUBY_DATA_FUNC dfree;
|
||||
|
||||
/** Pointer to the actual C level struct that you want to wrap.
|
||||
* This is in between dmark and dfree to allow DATA_PTR to continue
|
||||
* to work for both RData and non-embedded RTypedData.
|
||||
*/
|
||||
void *data;
|
||||
};
|
||||
|
||||
RBIMPL_SYMBOL_EXPORT_BEGIN()
|
||||
|
|
|
@ -355,6 +355,9 @@ struct RTypedData {
|
|||
/** The part that all ruby objects have in common. */
|
||||
struct RBasic basic;
|
||||
|
||||
/** Direct reference to the slots that holds instance variables, if any **/
|
||||
VALUE fields_obj;
|
||||
|
||||
/**
|
||||
* This is a `const rb_data_type_t *const` value, with the low bits set:
|
||||
*
|
||||
|
|
|
@ -15,13 +15,16 @@ struct set_table {
|
|||
const struct st_hash_type *type;
|
||||
/* Number of entries currently in the table. */
|
||||
st_index_t num_entries;
|
||||
/* Array of bins used for access by keys. */
|
||||
st_index_t *bins;
|
||||
|
||||
/* Start and bound index of entries in array entries.
|
||||
entries_starts and entries_bound are in interval
|
||||
[0,allocated_entries]. */
|
||||
st_index_t entries_start, entries_bound;
|
||||
/* Array of size 2^entry_power. */
|
||||
|
||||
/**
|
||||
* Array of size 2^entry_power.
|
||||
* Followed by st_index_t *bins, Array of bins used for access by keys.
|
||||
*/
|
||||
set_table_entry *entries;
|
||||
};
|
||||
|
||||
|
|
|
@ -11,10 +11,23 @@
|
|||
#include "ruby/internal/stdbool.h" /* for bool */
|
||||
#include "ruby/ruby.h" /* for struct RBasic */
|
||||
|
||||
/* Flags of RStruct
|
||||
*
|
||||
* 1-7: RSTRUCT_EMBED_LEN
|
||||
* If non-zero, the struct is embedded (its contents follow the
|
||||
* header, rather than being on a separately allocated buffer) and
|
||||
* these bits are the length of the Struct.
|
||||
* 8: RSTRUCT_GEN_FIELDS
|
||||
* The struct is embedded and has no space left to store the
|
||||
* IMEMO/fields reference. Any ivar this struct may have will be in
|
||||
* the generic_fields_tbl. This flag doesn't imply the struct has
|
||||
* ivars.
|
||||
*/
|
||||
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_GEN_FIELDS = RUBY_FL_USER8,
|
||||
};
|
||||
|
||||
struct RStruct {
|
||||
|
@ -23,6 +36,7 @@ struct RStruct {
|
|||
struct {
|
||||
long len;
|
||||
const VALUE *ptr;
|
||||
VALUE fields_obj;
|
||||
} heap;
|
||||
/* This is a length 1 array because:
|
||||
* 1. GCC has a bug that does not optimize C flexible array members
|
||||
|
@ -116,4 +130,31 @@ RSTRUCT_GET(VALUE st, long k)
|
|||
return RSTRUCT_CONST_PTR(st)[k];
|
||||
}
|
||||
|
||||
static inline VALUE
|
||||
RSTRUCT_FIELDS_OBJ(VALUE st)
|
||||
{
|
||||
const long embed_len = RSTRUCT_EMBED_LEN(st);
|
||||
VALUE fields_obj;
|
||||
if (embed_len) {
|
||||
RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
|
||||
fields_obj = RSTRUCT_GET(st, embed_len);
|
||||
}
|
||||
else {
|
||||
fields_obj = RSTRUCT(st)->as.heap.fields_obj;
|
||||
}
|
||||
return fields_obj;
|
||||
}
|
||||
|
||||
static inline void
|
||||
RSTRUCT_SET_FIELDS_OBJ(VALUE st, VALUE fields_obj)
|
||||
{
|
||||
const long embed_len = RSTRUCT_EMBED_LEN(st);
|
||||
if (embed_len) {
|
||||
RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
|
||||
RSTRUCT_SET(st, embed_len, fields_obj);
|
||||
}
|
||||
else {
|
||||
RB_OBJ_WRITE(st, &RSTRUCT(st)->as.heap.fields_obj, fields_obj);
|
||||
}
|
||||
}
|
||||
#endif /* INTERNAL_STRUCT_H */
|
||||
|
|
|
@ -17,8 +17,7 @@
|
|||
#endif
|
||||
|
||||
/* symbol.c */
|
||||
void rb_sym_global_symbols_mark(void);
|
||||
void rb_sym_global_symbols_update_references(void);
|
||||
void rb_sym_global_symbols_mark_and_move(void);
|
||||
VALUE rb_to_symbol_type(VALUE obj);
|
||||
VALUE rb_sym_intern(const char *ptr, long len, rb_encoding *enc);
|
||||
VALUE rb_sym_intern_ascii(const char *ptr, long len);
|
||||
|
@ -35,6 +34,7 @@ bool rb_obj_is_symbol_table(VALUE obj);
|
|||
void rb_sym_global_symbol_table_foreach_weak_reference(int (*callback)(VALUE *key, void *data), void *data);
|
||||
void rb_gc_free_dsymbol(VALUE);
|
||||
int rb_static_id_valid_p(ID id);
|
||||
void rb_free_global_symbol_table(void);
|
||||
|
||||
#if __has_builtin(__builtin_constant_p)
|
||||
#define rb_sym_intern_ascii_cstr(ptr) \
|
||||
|
|
|
@ -46,7 +46,6 @@ void rb_gvar_namespace_ready(const char *name);
|
|||
*/
|
||||
VALUE rb_mod_set_temporary_name(VALUE, VALUE);
|
||||
|
||||
int rb_gen_fields_tbl_get(VALUE obj, ID id, VALUE *fields_obj);
|
||||
void rb_obj_copy_ivs_to_hash_table(VALUE obj, st_table *table);
|
||||
void rb_obj_init_too_complex(VALUE obj, st_table *table);
|
||||
void rb_evict_ivars_to_hash(VALUE obj);
|
||||
|
|
|
@ -2049,10 +2049,16 @@ XXX
|
|||
basename = File.basename($0, '.*')
|
||||
return true if load(File.expand_path("~/.options/#{basename}"), **keywords) rescue nil
|
||||
basename << ".options"
|
||||
if !(xdg = ENV['XDG_CONFIG_HOME']) or xdg.empty?
|
||||
# https://specifications.freedesktop.org/basedir-spec/latest/#variables
|
||||
#
|
||||
# If $XDG_CONFIG_HOME is either not set or empty, a default
|
||||
# equal to $HOME/.config should be used.
|
||||
xdg = ['~/.config', true]
|
||||
end
|
||||
return [
|
||||
# XDG
|
||||
ENV['XDG_CONFIG_HOME'],
|
||||
['~/.config', true],
|
||||
xdg,
|
||||
|
||||
*ENV['XDG_CONFIG_DIRS']&.split(File::PATH_SEPARATOR),
|
||||
|
||||
# Haiku
|
||||
|
|
|
@ -12,9 +12,6 @@ module Gem
|
|||
VERSION = "3.8.0.dev"
|
||||
end
|
||||
|
||||
# Must be first since it unloads the prelude from 1.9.2
|
||||
require_relative "rubygems/compatibility"
|
||||
|
||||
require_relative "rubygems/defaults"
|
||||
require_relative "rubygems/deprecate"
|
||||
require_relative "rubygems/errors"
|
||||
|
|
|
@ -199,6 +199,9 @@ class Gem::BasicSpecification
|
|||
File.expand_path(File.join(gems_dir, full_name, "data", name))
|
||||
end
|
||||
|
||||
extend Gem::Deprecate
|
||||
rubygems_deprecate :datadir, :none, "4.1"
|
||||
|
||||
##
|
||||
# Full path of the target library file.
|
||||
# If the file is not in this gem, return nil.
|
||||
|
|
|
@ -1,41 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
#--
|
||||
# This file contains all sorts of little compatibility hacks that we've
|
||||
# had to introduce over the years. Quarantining them into one file helps
|
||||
# us know when we can get rid of them.
|
||||
#
|
||||
# Ruby 1.9.x has introduced some things that are awkward, and we need to
|
||||
# support them, so we define some constants to use later.
|
||||
#
|
||||
# TODO remove at RubyGems 4
|
||||
#++
|
||||
|
||||
module Gem
|
||||
# :stopdoc:
|
||||
|
||||
RubyGemsVersion = VERSION
|
||||
deprecate_constant(:RubyGemsVersion)
|
||||
|
||||
RbConfigPriorities = %w[
|
||||
MAJOR
|
||||
MINOR
|
||||
TEENY
|
||||
EXEEXT RUBY_SO_NAME arch bindir datadir libdir ruby_install_name
|
||||
ruby_version rubylibprefix sitedir sitelibdir vendordir vendorlibdir
|
||||
rubylibdir
|
||||
].freeze
|
||||
|
||||
if defined?(ConfigMap)
|
||||
RbConfigPriorities.each do |key|
|
||||
ConfigMap[key.to_sym] = RbConfig::CONFIG[key]
|
||||
end
|
||||
else
|
||||
##
|
||||
# Configuration settings from ::RbConfig
|
||||
ConfigMap = Hash.new do |cm, key|
|
||||
cm[key] = RbConfig::CONFIG[key.to_s]
|
||||
end
|
||||
deprecate_constant(:ConfigMap)
|
||||
end
|
||||
end
|
|
@ -126,17 +126,18 @@ module Gem
|
|||
# telling the user of +repl+ (unless +repl+ is :none) and the
|
||||
# Rubygems version that it is planned to go away.
|
||||
|
||||
def rubygems_deprecate(name, replacement=:none)
|
||||
def rubygems_deprecate(name, replacement=:none, version=nil)
|
||||
class_eval do
|
||||
old = "_deprecated_#{name}"
|
||||
alias_method old, name
|
||||
define_method name do |*args, &block|
|
||||
klass = is_a? Module
|
||||
target = klass ? "#{self}." : "#{self.class}#"
|
||||
version ||= Gem::Deprecate.next_rubygems_major_version
|
||||
msg = [
|
||||
"NOTE: #{target}#{name} is deprecated",
|
||||
replacement == :none ? " with no replacement" : "; use #{replacement} instead",
|
||||
". It will be removed in Rubygems #{Gem::Deprecate.next_rubygems_major_version}",
|
||||
". It will be removed in Rubygems #{version}",
|
||||
"\n#{target}#{name} called from #{Gem.location_of_caller.join(":")}",
|
||||
]
|
||||
warn "#{msg.join}." unless Gem::Deprecate.skip
|
||||
|
@ -147,13 +148,14 @@ module Gem
|
|||
end
|
||||
|
||||
# Deprecation method to deprecate Rubygems commands
|
||||
def rubygems_deprecate_command(version = Gem::Deprecate.next_rubygems_major_version)
|
||||
def rubygems_deprecate_command(version = nil)
|
||||
class_eval do
|
||||
define_method "deprecated?" do
|
||||
true
|
||||
end
|
||||
|
||||
define_method "deprecation_warning" do
|
||||
version ||= Gem::Deprecate.next_rubygems_major_version
|
||||
msg = [
|
||||
"#{command} command is deprecated",
|
||||
". It will be removed in Rubygems #{version}.\n",
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "openssl"
|
||||
require_relative "user_interaction"
|
||||
|
||||
##
|
||||
# S3URISigner implements AWS SigV4 for S3 Source to avoid a dependency on the aws-sdk-* gems
|
||||
# More on AWS SigV4: https://docs.aws.amazon.com/AmazonS3/latest/API/sig-v4-authenticating-requests.html
|
||||
class Gem::S3URISigner
|
||||
include Gem::UserInteraction
|
||||
|
||||
class ConfigurationError < Gem::Exception
|
||||
def initialize(message)
|
||||
super message
|
||||
|
@ -147,17 +150,40 @@ class Gem::S3URISigner
|
|||
require_relative "request/connection_pools"
|
||||
require "json"
|
||||
|
||||
iam_info = ec2_metadata_request(EC2_IAM_INFO)
|
||||
# Expected format: arn:aws:iam::<id>:instance-profile/<role_name>
|
||||
role_name = iam_info["InstanceProfileArn"].split("/").last
|
||||
ec2_metadata_request(EC2_IAM_SECURITY_CREDENTIALS + role_name)
|
||||
# First try V2 fallback to V1
|
||||
res = nil
|
||||
begin
|
||||
res = ec2_metadata_credentials_imds_v2
|
||||
rescue InstanceProfileError
|
||||
alert_warning "Unable to access ec2 credentials via IMDSv2, falling back to IMDSv1"
|
||||
res = ec2_metadata_credentials_imds_v1
|
||||
end
|
||||
res
|
||||
end
|
||||
|
||||
def ec2_metadata_request(url)
|
||||
uri = Gem::URI(url)
|
||||
@request_pool ||= create_request_pool(uri)
|
||||
request = Gem::Request.new(uri, Gem::Net::HTTP::Get, nil, @request_pool)
|
||||
response = request.fetch
|
||||
def ec2_metadata_credentials_imds_v2
|
||||
token = ec2_metadata_token
|
||||
iam_info = ec2_metadata_request(EC2_IAM_INFO, token:)
|
||||
# Expected format: arn:aws:iam::<id>:instance-profile/<role_name>
|
||||
role_name = iam_info["InstanceProfileArn"].split("/").last
|
||||
ec2_metadata_request(EC2_IAM_SECURITY_CREDENTIALS + role_name, token:)
|
||||
end
|
||||
|
||||
def ec2_metadata_credentials_imds_v1
|
||||
iam_info = ec2_metadata_request(EC2_IAM_INFO, token: nil)
|
||||
# Expected format: arn:aws:iam::<id>:instance-profile/<role_name>
|
||||
role_name = iam_info["InstanceProfileArn"].split("/").last
|
||||
ec2_metadata_request(EC2_IAM_SECURITY_CREDENTIALS + role_name, token: nil)
|
||||
end
|
||||
|
||||
def ec2_metadata_request(url, token:)
|
||||
request = ec2_iam_request(Gem::URI(url), Gem::Net::HTTP::Get)
|
||||
|
||||
response = request.fetch do |req|
|
||||
if token
|
||||
req.add_field "X-aws-ec2-metadata-token", token
|
||||
end
|
||||
end
|
||||
|
||||
case response
|
||||
when Gem::Net::HTTPOK then
|
||||
|
@ -167,6 +193,26 @@ class Gem::S3URISigner
|
|||
end
|
||||
end
|
||||
|
||||
def ec2_metadata_token
|
||||
request = ec2_iam_request(Gem::URI(EC2_IAM_TOKEN), Gem::Net::HTTP::Put)
|
||||
|
||||
response = request.fetch do |req|
|
||||
req.add_field "X-aws-ec2-metadata-token-ttl-seconds", 60
|
||||
end
|
||||
|
||||
case response
|
||||
when Gem::Net::HTTPOK then
|
||||
response.body
|
||||
else
|
||||
raise InstanceProfileError.new("Unable to fetch AWS metadata from #{uri}: #{response.message} #{response.code}")
|
||||
end
|
||||
end
|
||||
|
||||
def ec2_iam_request(uri, verb)
|
||||
@request_pool ||= create_request_pool(uri)
|
||||
Gem::Request.new(uri, verb, nil, @request_pool)
|
||||
end
|
||||
|
||||
def create_request_pool(uri)
|
||||
proxy_uri = Gem::Request.proxy_uri(Gem::Request.get_proxy_from_env(uri.scheme))
|
||||
certs = Gem::Request.get_cert_files
|
||||
|
@ -174,6 +220,7 @@ class Gem::S3URISigner
|
|||
end
|
||||
|
||||
BASE64_URI_TRANSLATE = { "+" => "%2B", "/" => "%2F", "=" => "%3D", "\n" => "" }.freeze
|
||||
EC2_IAM_TOKEN = "http://169.254.169.254/latest/api/token"
|
||||
EC2_IAM_INFO = "http://169.254.169.254/latest/meta-data/iam/info"
|
||||
EC2_IAM_SECURITY_CREDENTIALS = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
||||
end
|
||||
|
|
8
load.c
8
load.c
|
@ -1318,7 +1318,7 @@ no_feature_p(vm_ns_t *vm_ns, const char *feature, const char *ext, int rb, int e
|
|||
return 0;
|
||||
}
|
||||
|
||||
// Documented in doc/globals.rdoc
|
||||
// Documented in doc/globals.md
|
||||
VALUE
|
||||
rb_resolve_feature_path(VALUE klass, VALUE fname)
|
||||
{
|
||||
|
@ -1346,14 +1346,14 @@ rb_resolve_feature_path(VALUE klass, VALUE fname)
|
|||
}
|
||||
|
||||
static void
|
||||
ext_config_push(rb_thread_t *th, struct rb_ext_config *prev)
|
||||
ext_config_push(rb_thread_t *th, volatile struct rb_ext_config *prev)
|
||||
{
|
||||
*prev = th->ext_config;
|
||||
th->ext_config = (struct rb_ext_config){0};
|
||||
}
|
||||
|
||||
static void
|
||||
ext_config_pop(rb_thread_t *th, struct rb_ext_config *prev)
|
||||
ext_config_pop(rb_thread_t *th, volatile struct rb_ext_config *prev)
|
||||
{
|
||||
th->ext_config = *prev;
|
||||
}
|
||||
|
@ -1407,7 +1407,7 @@ require_internal(rb_execution_context_t *ec, VALUE fname, int exception, bool wa
|
|||
VALUE realpaths = get_loaded_features_realpaths(vm_ns);
|
||||
VALUE realpath_map = get_loaded_features_realpath_map(vm_ns);
|
||||
volatile bool reset_ext_config = false;
|
||||
struct rb_ext_config prev_ext_config;
|
||||
volatile struct rb_ext_config prev_ext_config;
|
||||
|
||||
path = rb_str_encode_ospath(fname);
|
||||
RUBY_DTRACE_HOOK(REQUIRE_ENTRY, RSTRING_PTR(fname));
|
||||
|
|
30
marshal.c
30
marshal.c
|
@ -2572,19 +2572,19 @@ Init_marshal(void)
|
|||
}
|
||||
|
||||
static int
|
||||
marshal_compat_table_mark_i(st_data_t key, st_data_t value, st_data_t _)
|
||||
marshal_compat_table_mark_and_move_i(st_data_t key, st_data_t value, st_data_t _)
|
||||
{
|
||||
marshal_compat_t *p = (marshal_compat_t *)value;
|
||||
rb_gc_mark_movable(p->newclass);
|
||||
rb_gc_mark_movable(p->oldclass);
|
||||
rb_gc_mark_and_move(&p->newclass);
|
||||
rb_gc_mark_and_move(&p->oldclass);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
marshal_compat_table_mark(void *tbl)
|
||||
marshal_compat_table_mark_and_move(void *tbl)
|
||||
{
|
||||
if (!tbl) return;
|
||||
st_foreach(tbl, marshal_compat_table_mark_i, 0);
|
||||
st_foreach(tbl, marshal_compat_table_mark_and_move_i, 0);
|
||||
}
|
||||
|
||||
static int
|
||||
|
@ -2607,29 +2607,13 @@ marshal_compat_table_memsize(const void *data)
|
|||
return st_memsize(data) + sizeof(marshal_compat_t) * st_table_size(data);
|
||||
}
|
||||
|
||||
static int
|
||||
marshal_compat_table_compact_i(st_data_t key, st_data_t value, st_data_t _)
|
||||
{
|
||||
marshal_compat_t *p = (marshal_compat_t *)value;
|
||||
p->newclass = rb_gc_location(p->newclass);
|
||||
p->oldclass = rb_gc_location(p->oldclass);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
marshal_compat_table_compact(void *tbl)
|
||||
{
|
||||
if (!tbl) return;
|
||||
st_foreach(tbl, marshal_compat_table_compact_i, 0);
|
||||
}
|
||||
|
||||
static const rb_data_type_t marshal_compat_type = {
|
||||
.wrap_struct_name = "marshal_compat_table",
|
||||
.function = {
|
||||
.dmark = marshal_compat_table_mark,
|
||||
.dmark = marshal_compat_table_mark_and_move,
|
||||
.dfree = marshal_compat_table_free,
|
||||
.dsize = marshal_compat_table_memsize,
|
||||
.dcompact = marshal_compat_table_compact,
|
||||
.dcompact = marshal_compat_table_mark_and_move,
|
||||
},
|
||||
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY,
|
||||
};
|
||||
|
|
|
@ -309,8 +309,11 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
|
|||
ANN("example: case x; in 1; foo; in 2; bar; else baz; end");
|
||||
F_NODE(nd_head, RNODE_IN, "in pattern");
|
||||
F_NODE(nd_body, RNODE_IN, "in body");
|
||||
LAST_NODE;
|
||||
F_NODE(nd_next, RNODE_IN, "next in clause");
|
||||
F_LOC(in_keyword_loc, RNODE_IN);
|
||||
F_LOC(then_keyword_loc, RNODE_IN);
|
||||
LAST_NODE;
|
||||
F_LOC(operator_loc, RNODE_IN);
|
||||
return;
|
||||
|
||||
case NODE_WHILE:
|
||||
|
@ -1009,8 +1012,10 @@ dump_node(VALUE buf, VALUE indent, int comment, const NODE * node)
|
|||
ANN("format: module [nd_cpath]; [nd_body]; end");
|
||||
ANN("example: module M; ..; end");
|
||||
F_NODE(nd_cpath, RNODE_MODULE, "module path");
|
||||
LAST_NODE;
|
||||
F_NODE(nd_body, RNODE_MODULE, "module definition");
|
||||
F_LOC(module_keyword_loc, RNODE_MODULE);
|
||||
LAST_NODE;
|
||||
F_LOC(end_keyword_loc, RNODE_MODULE);
|
||||
return;
|
||||
|
||||
case NODE_SCLASS:
|
||||
|
|
25
parse.y
25
parse.y
|
@ -1070,7 +1070,7 @@ static rb_node_case_t *rb_node_case_new(struct parser_params *p, NODE *nd_head,
|
|||
static rb_node_case2_t *rb_node_case2_new(struct parser_params *p, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc);
|
||||
static rb_node_case3_t *rb_node_case3_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *case_keyword_loc, const YYLTYPE *end_keyword_loc);
|
||||
static rb_node_when_t *rb_node_when_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *then_keyword_loc);
|
||||
static rb_node_in_t *rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc);
|
||||
static rb_node_in_t *rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *in_keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *operator_loc);
|
||||
static rb_node_while_t *rb_node_while_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *closing_loc);
|
||||
static rb_node_until_t *rb_node_until_new(struct parser_params *p, NODE *nd_cond, NODE *nd_body, long nd_state, const YYLTYPE *loc, const YYLTYPE *keyword_loc, const YYLTYPE *closing_loc);
|
||||
static rb_node_iter_t *rb_node_iter_new(struct parser_params *p, rb_node_args_t *nd_args, NODE *nd_body, const YYLTYPE *loc);
|
||||
|
@ -1145,7 +1145,7 @@ static rb_node_alias_t *rb_node_alias_new(struct parser_params *p, NODE *nd_1st,
|
|||
static rb_node_valias_t *rb_node_valias_new(struct parser_params *p, ID nd_alias, ID nd_orig, const YYLTYPE *loc, const YYLTYPE *keyword_loc);
|
||||
static rb_node_undef_t *rb_node_undef_new(struct parser_params *p, NODE *nd_undef, const YYLTYPE *loc);
|
||||
static rb_node_class_t *rb_node_class_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, NODE *nd_super, const YYLTYPE *loc, const YYLTYPE *class_keyword_loc, const YYLTYPE *inheritance_operator_loc, const YYLTYPE *end_keyword_loc);
|
||||
static rb_node_module_t *rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc);
|
||||
static rb_node_module_t *rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *module_keyword_loc, const YYLTYPE *end_keyword_loc);
|
||||
static rb_node_sclass_t *rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const YYLTYPE *loc);
|
||||
static rb_node_colon2_t *rb_node_colon2_new(struct parser_params *p, NODE *nd_head, ID nd_mid, const YYLTYPE *loc, const YYLTYPE *delimiter_loc, const YYLTYPE *name_loc);
|
||||
static rb_node_colon3_t *rb_node_colon3_new(struct parser_params *p, ID nd_mid, const YYLTYPE *loc, const YYLTYPE *delimiter_loc, const YYLTYPE *name_loc);
|
||||
|
@ -1178,7 +1178,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
|
|||
#define NEW_CASE2(b,loc,ck_loc,ek_loc) (NODE *)rb_node_case2_new(p,b,loc,ck_loc,ek_loc)
|
||||
#define NEW_CASE3(h,b,loc,ck_loc,ek_loc) (NODE *)rb_node_case3_new(p,h,b,loc,ck_loc,ek_loc)
|
||||
#define NEW_WHEN(c,t,e,loc,k_loc,t_loc) (NODE *)rb_node_when_new(p,c,t,e,loc,k_loc,t_loc)
|
||||
#define NEW_IN(c,t,e,loc) (NODE *)rb_node_in_new(p,c,t,e,loc)
|
||||
#define NEW_IN(c,t,e,loc,ik_loc,tk_loc,o_loc) (NODE *)rb_node_in_new(p,c,t,e,loc,ik_loc,tk_loc,o_loc)
|
||||
#define NEW_WHILE(c,b,n,loc,k_loc,c_loc) (NODE *)rb_node_while_new(p,c,b,n,loc,k_loc,c_loc)
|
||||
#define NEW_UNTIL(c,b,n,loc,k_loc,c_loc) (NODE *)rb_node_until_new(p,c,b,n,loc,k_loc,c_loc)
|
||||
#define NEW_ITER(a,b,loc) (NODE *)rb_node_iter_new(p,a,b,loc)
|
||||
|
@ -1253,7 +1253,7 @@ static rb_node_error_t *rb_node_error_new(struct parser_params *p, const YYLTYPE
|
|||
#define NEW_VALIAS(n,o,loc,k_loc) (NODE *)rb_node_valias_new(p,n,o,loc,k_loc)
|
||||
#define NEW_UNDEF(i,loc) (NODE *)rb_node_undef_new(p,i,loc)
|
||||
#define NEW_CLASS(n,b,s,loc,ck_loc,io_loc,ek_loc) (NODE *)rb_node_class_new(p,n,b,s,loc,ck_loc,io_loc,ek_loc)
|
||||
#define NEW_MODULE(n,b,loc) (NODE *)rb_node_module_new(p,n,b,loc)
|
||||
#define NEW_MODULE(n,b,loc,mk_loc,ek_loc) (NODE *)rb_node_module_new(p,n,b,loc,mk_loc,ek_loc)
|
||||
#define NEW_SCLASS(r,b,loc) (NODE *)rb_node_sclass_new(p,r,b,loc)
|
||||
#define NEW_COLON2(c,i,loc,d_loc,n_loc) (NODE *)rb_node_colon2_new(p,c,i,loc,d_loc,n_loc)
|
||||
#define NEW_COLON3(i,loc,d_loc,n_loc) (NODE *)rb_node_colon3_new(p,i,loc,d_loc,n_loc)
|
||||
|
@ -3472,7 +3472,7 @@ expr : command_call
|
|||
pop_pktbl(p, $p_pktbl);
|
||||
pop_pvtbl(p, $p_pvtbl);
|
||||
p->ctxt.in_kwarg = $ctxt.in_kwarg;
|
||||
$$ = NEW_CASE3($arg, NEW_IN($body, 0, 0, &@body), &@$, &NULL_LOC, &NULL_LOC);
|
||||
$$ = NEW_CASE3($arg, NEW_IN($body, 0, 0, &@body, &NULL_LOC, &NULL_LOC, &@2), &@$, &NULL_LOC, &NULL_LOC);
|
||||
/*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
|
||||
}
|
||||
| arg keyword_in
|
||||
|
@ -3485,7 +3485,7 @@ expr : command_call
|
|||
pop_pktbl(p, $p_pktbl);
|
||||
pop_pvtbl(p, $p_pvtbl);
|
||||
p->ctxt.in_kwarg = $ctxt.in_kwarg;
|
||||
$$ = NEW_CASE3($arg, NEW_IN($body, NEW_TRUE(&@body), NEW_FALSE(&@body), &@body), &@$, &NULL_LOC, &NULL_LOC);
|
||||
$$ = NEW_CASE3($arg, NEW_IN($body, NEW_TRUE(&@body), NEW_FALSE(&@body), &@body, &@keyword_in, &NULL_LOC, &NULL_LOC), &@$, &NULL_LOC, &NULL_LOC);
|
||||
/*% ripper: case!($:arg, in!($:body, Qnil, Qnil)) %*/
|
||||
}
|
||||
| arg %prec tLBRACE_ARG
|
||||
|
@ -4621,7 +4621,7 @@ primary : inline_primary
|
|||
bodystmt
|
||||
k_end
|
||||
{
|
||||
$$ = NEW_MODULE($cpath, $bodystmt, &@$);
|
||||
$$ = NEW_MODULE($cpath, $bodystmt, &@$, &@k_module, &@k_end);
|
||||
nd_set_line(RNODE_MODULE($$)->nd_body, @k_end.end_pos.lineno);
|
||||
set_line_body($bodystmt, @cpath.end_pos.lineno);
|
||||
nd_set_line($$, @cpath.end_pos.lineno);
|
||||
|
@ -5399,7 +5399,7 @@ p_case_body : keyword_in
|
|||
compstmt(stmts)
|
||||
p_cases[cases]
|
||||
{
|
||||
$$ = NEW_IN($expr, $compstmt, $cases, &@$);
|
||||
$$ = NEW_IN($expr, $compstmt, $cases, &@$, &@keyword_in, &@then, &NULL_LOC);
|
||||
/*% ripper: in!($:expr, $:compstmt, $:cases) %*/
|
||||
}
|
||||
;
|
||||
|
@ -11438,13 +11438,15 @@ rb_node_sclass_new(struct parser_params *p, NODE *nd_recv, NODE *nd_body, const
|
|||
}
|
||||
|
||||
static rb_node_module_t *
|
||||
rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc)
|
||||
rb_node_module_new(struct parser_params *p, NODE *nd_cpath, NODE *nd_body, const YYLTYPE *loc, const YYLTYPE *module_keyword_loc, const YYLTYPE *end_keyword_loc)
|
||||
{
|
||||
/* Keep the order of node creation */
|
||||
NODE *scope = NEW_SCOPE(0, nd_body, loc);
|
||||
rb_node_module_t *n = NODE_NEWNODE(NODE_MODULE, rb_node_module_t, loc);
|
||||
n->nd_cpath = nd_cpath;
|
||||
n->nd_body = scope;
|
||||
n->module_keyword_loc = *module_keyword_loc;
|
||||
n->end_keyword_loc = *end_keyword_loc;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
@ -11526,12 +11528,15 @@ rb_node_when_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd
|
|||
}
|
||||
|
||||
static rb_node_in_t *
|
||||
rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc)
|
||||
rb_node_in_new(struct parser_params *p, NODE *nd_head, NODE *nd_body, NODE *nd_next, const YYLTYPE *loc, const YYLTYPE *in_keyword_loc, const YYLTYPE *then_keyword_loc, const YYLTYPE *operator_loc)
|
||||
{
|
||||
rb_node_in_t *n = NODE_NEWNODE(NODE_IN, rb_node_in_t, loc);
|
||||
n->nd_head = nd_head;
|
||||
n->nd_body = nd_body;
|
||||
n->nd_next = nd_next;
|
||||
n->in_keyword_loc = *in_keyword_loc;
|
||||
n->then_keyword_loc = *then_keyword_loc;
|
||||
n->operator_loc = *operator_loc;
|
||||
|
||||
return n;
|
||||
}
|
||||
|
|
|
@ -322,13 +322,42 @@ warnings:
|
|||
- UNUSED_LOCAL_VARIABLE
|
||||
- VOID_STATEMENT
|
||||
tokens:
|
||||
# The order of the tokens at the beginning is important, because we use them
|
||||
# for a lookup table.
|
||||
- name: EOF
|
||||
value: 1
|
||||
comment: final token in the file
|
||||
- name: MISSING
|
||||
comment: "a token that was expected but not found"
|
||||
- name: NOT_PROVIDED
|
||||
comment: "a token that was not present but it is okay"
|
||||
- name: BRACE_RIGHT
|
||||
comment: "}"
|
||||
- name: COMMA
|
||||
comment: ","
|
||||
- name: EMBEXPR_END
|
||||
comment: "}"
|
||||
- name: KEYWORD_DO
|
||||
comment: "do"
|
||||
- name: KEYWORD_ELSE
|
||||
comment: "else"
|
||||
- name: KEYWORD_ELSIF
|
||||
comment: "elsif"
|
||||
- name: KEYWORD_END
|
||||
comment: "end"
|
||||
- name: KEYWORD_ENSURE
|
||||
comment: "ensure"
|
||||
- name: KEYWORD_IN
|
||||
comment: "in"
|
||||
- name: KEYWORD_RESCUE
|
||||
comment: "rescue"
|
||||
- name: KEYWORD_THEN
|
||||
comment: "then"
|
||||
- name: KEYWORD_WHEN
|
||||
comment: "when"
|
||||
- name: NEWLINE
|
||||
comment: "a newline character outside of other tokens"
|
||||
- name: PARENTHESIS_RIGHT
|
||||
comment: ")"
|
||||
- name: SEMICOLON
|
||||
comment: ";"
|
||||
# Tokens from here on are not used for lookup, and can be in any order.
|
||||
- name: AMPERSAND
|
||||
comment: "&"
|
||||
- name: AMPERSAND_AMPERSAND
|
||||
|
@ -351,8 +380,6 @@ tokens:
|
|||
comment: "!~"
|
||||
- name: BRACE_LEFT
|
||||
comment: "{"
|
||||
- name: BRACE_RIGHT
|
||||
comment: "}"
|
||||
- name: BRACKET_LEFT
|
||||
comment: "["
|
||||
- name: BRACKET_LEFT_ARRAY
|
||||
|
@ -375,8 +402,6 @@ tokens:
|
|||
comment: ":"
|
||||
- name: COLON_COLON
|
||||
comment: "::"
|
||||
- name: COMMA
|
||||
comment: ","
|
||||
- name: COMMENT
|
||||
comment: "a comment"
|
||||
- name: CONSTANT
|
||||
|
@ -395,8 +420,6 @@ tokens:
|
|||
comment: "a line inside of embedded documentation"
|
||||
- name: EMBEXPR_BEGIN
|
||||
comment: "#{"
|
||||
- name: EMBEXPR_END
|
||||
comment: "}"
|
||||
- name: EMBVAR
|
||||
comment: "#"
|
||||
- name: EQUAL
|
||||
|
@ -463,20 +486,10 @@ tokens:
|
|||
comment: "def"
|
||||
- name: KEYWORD_DEFINED
|
||||
comment: "defined?"
|
||||
- name: KEYWORD_DO
|
||||
comment: "do"
|
||||
- name: KEYWORD_DO_LOOP
|
||||
comment: "do keyword for a predicate in a while, until, or for loop"
|
||||
- name: KEYWORD_ELSE
|
||||
comment: "else"
|
||||
- name: KEYWORD_ELSIF
|
||||
comment: "elsif"
|
||||
- name: KEYWORD_END
|
||||
comment: "end"
|
||||
- name: KEYWORD_END_UPCASE
|
||||
comment: "END"
|
||||
- name: KEYWORD_ENSURE
|
||||
comment: "ensure"
|
||||
- name: KEYWORD_FALSE
|
||||
comment: "false"
|
||||
- name: KEYWORD_FOR
|
||||
|
@ -485,8 +498,6 @@ tokens:
|
|||
comment: "if"
|
||||
- name: KEYWORD_IF_MODIFIER
|
||||
comment: "if in the modifier form"
|
||||
- name: KEYWORD_IN
|
||||
comment: "in"
|
||||
- name: KEYWORD_MODULE
|
||||
comment: "module"
|
||||
- name: KEYWORD_NEXT
|
||||
|
@ -499,8 +510,6 @@ tokens:
|
|||
comment: "or"
|
||||
- name: KEYWORD_REDO
|
||||
comment: "redo"
|
||||
- name: KEYWORD_RESCUE
|
||||
comment: "rescue"
|
||||
- name: KEYWORD_RESCUE_MODIFIER
|
||||
comment: "rescue in the modifier form"
|
||||
- name: KEYWORD_RETRY
|
||||
|
@ -511,8 +520,6 @@ tokens:
|
|||
comment: "self"
|
||||
- name: KEYWORD_SUPER
|
||||
comment: "super"
|
||||
- name: KEYWORD_THEN
|
||||
comment: "then"
|
||||
- name: KEYWORD_TRUE
|
||||
comment: "true"
|
||||
- name: KEYWORD_UNDEF
|
||||
|
@ -525,8 +532,6 @@ tokens:
|
|||
comment: "until"
|
||||
- name: KEYWORD_UNTIL_MODIFIER
|
||||
comment: "until in the modifier form"
|
||||
- name: KEYWORD_WHEN
|
||||
comment: "when"
|
||||
- name: KEYWORD_WHILE
|
||||
comment: "while"
|
||||
- name: KEYWORD_WHILE_MODIFIER
|
||||
|
@ -563,16 +568,12 @@ tokens:
|
|||
comment: "-="
|
||||
- name: MINUS_GREATER
|
||||
comment: "->"
|
||||
- name: NEWLINE
|
||||
comment: "a newline character outside of other tokens"
|
||||
- name: NUMBERED_REFERENCE
|
||||
comment: "a numbered reference to a capture group in the previous regular expression match"
|
||||
- name: PARENTHESIS_LEFT
|
||||
comment: "("
|
||||
- name: PARENTHESIS_LEFT_PARENTHESES
|
||||
comment: "( for a parentheses node"
|
||||
- name: PARENTHESIS_RIGHT
|
||||
comment: ")"
|
||||
- name: PERCENT
|
||||
comment: "%"
|
||||
- name: PERCENT_EQUAL
|
||||
|
@ -605,8 +606,6 @@ tokens:
|
|||
comment: "the beginning of a regular expression"
|
||||
- name: REGEXP_END
|
||||
comment: "the end of a regular expression"
|
||||
- name: SEMICOLON
|
||||
comment: ";"
|
||||
- name: SLASH
|
||||
comment: "/"
|
||||
- name: SLASH_EQUAL
|
||||
|
@ -651,6 +650,10 @@ tokens:
|
|||
comment: "a separator between words in a list"
|
||||
- name: __END__
|
||||
comment: "marker for the point in the file at which the parser should stop"
|
||||
- name: MISSING
|
||||
comment: "a token that was expected but not found"
|
||||
- name: NOT_PROVIDED
|
||||
comment: "a token that was not present but it is okay"
|
||||
flags:
|
||||
- name: ArgumentsNodeFlags
|
||||
values:
|
||||
|
|
150
prism/prism.c
150
prism/prism.c
|
@ -8586,85 +8586,66 @@ parser_lex_magic_comment(pm_parser_t *parser, bool semantic_token_seen) {
|
|||
/* Context manipulations */
|
||||
/******************************************************************************/
|
||||
|
||||
static bool
|
||||
context_terminator(pm_context_t context, pm_token_t *token) {
|
||||
switch (context) {
|
||||
case PM_CONTEXT_MAIN:
|
||||
case PM_CONTEXT_DEF_PARAMS:
|
||||
case PM_CONTEXT_DEFINED:
|
||||
case PM_CONTEXT_MULTI_TARGET:
|
||||
case PM_CONTEXT_TERNARY:
|
||||
case PM_CONTEXT_RESCUE_MODIFIER:
|
||||
return token->type == PM_TOKEN_EOF;
|
||||
case PM_CONTEXT_DEFAULT_PARAMS:
|
||||
return token->type == PM_TOKEN_COMMA || token->type == PM_TOKEN_PARENTHESIS_RIGHT;
|
||||
case PM_CONTEXT_PREEXE:
|
||||
case PM_CONTEXT_POSTEXE:
|
||||
return token->type == PM_TOKEN_BRACE_RIGHT;
|
||||
case PM_CONTEXT_MODULE:
|
||||
case PM_CONTEXT_CLASS:
|
||||
case PM_CONTEXT_SCLASS:
|
||||
case PM_CONTEXT_LAMBDA_DO_END:
|
||||
case PM_CONTEXT_DEF:
|
||||
case PM_CONTEXT_BLOCK_KEYWORDS:
|
||||
return token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ENSURE;
|
||||
case PM_CONTEXT_WHILE:
|
||||
case PM_CONTEXT_UNTIL:
|
||||
case PM_CONTEXT_ELSE:
|
||||
case PM_CONTEXT_FOR:
|
||||
case PM_CONTEXT_BEGIN_ENSURE:
|
||||
case PM_CONTEXT_BLOCK_ENSURE:
|
||||
case PM_CONTEXT_CLASS_ENSURE:
|
||||
case PM_CONTEXT_DEF_ENSURE:
|
||||
case PM_CONTEXT_LAMBDA_ENSURE:
|
||||
case PM_CONTEXT_MODULE_ENSURE:
|
||||
case PM_CONTEXT_SCLASS_ENSURE:
|
||||
return token->type == PM_TOKEN_KEYWORD_END;
|
||||
case PM_CONTEXT_LOOP_PREDICATE:
|
||||
return token->type == PM_TOKEN_KEYWORD_DO || token->type == PM_TOKEN_KEYWORD_THEN;
|
||||
case PM_CONTEXT_FOR_INDEX:
|
||||
return token->type == PM_TOKEN_KEYWORD_IN;
|
||||
case PM_CONTEXT_CASE_WHEN:
|
||||
return token->type == PM_TOKEN_KEYWORD_WHEN || token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_ELSE;
|
||||
case PM_CONTEXT_CASE_IN:
|
||||
return token->type == PM_TOKEN_KEYWORD_IN || token->type == PM_TOKEN_KEYWORD_END || token->type == PM_TOKEN_KEYWORD_ELSE;
|
||||
case PM_CONTEXT_IF:
|
||||
case PM_CONTEXT_ELSIF:
|
||||
return token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_ELSIF || token->type == PM_TOKEN_KEYWORD_END;
|
||||
case PM_CONTEXT_UNLESS:
|
||||
return token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END;
|
||||
case PM_CONTEXT_EMBEXPR:
|
||||
return token->type == PM_TOKEN_EMBEXPR_END;
|
||||
case PM_CONTEXT_BLOCK_BRACES:
|
||||
return token->type == PM_TOKEN_BRACE_RIGHT;
|
||||
case PM_CONTEXT_PARENS:
|
||||
return token->type == PM_TOKEN_PARENTHESIS_RIGHT;
|
||||
case PM_CONTEXT_BEGIN:
|
||||
case PM_CONTEXT_BEGIN_RESCUE:
|
||||
case PM_CONTEXT_BLOCK_RESCUE:
|
||||
case PM_CONTEXT_CLASS_RESCUE:
|
||||
case PM_CONTEXT_DEF_RESCUE:
|
||||
case PM_CONTEXT_LAMBDA_RESCUE:
|
||||
case PM_CONTEXT_MODULE_RESCUE:
|
||||
case PM_CONTEXT_SCLASS_RESCUE:
|
||||
return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_RESCUE || token->type == PM_TOKEN_KEYWORD_ELSE || token->type == PM_TOKEN_KEYWORD_END;
|
||||
case PM_CONTEXT_BEGIN_ELSE:
|
||||
case PM_CONTEXT_BLOCK_ELSE:
|
||||
case PM_CONTEXT_CLASS_ELSE:
|
||||
case PM_CONTEXT_DEF_ELSE:
|
||||
case PM_CONTEXT_LAMBDA_ELSE:
|
||||
case PM_CONTEXT_MODULE_ELSE:
|
||||
case PM_CONTEXT_SCLASS_ELSE:
|
||||
return token->type == PM_TOKEN_KEYWORD_ENSURE || token->type == PM_TOKEN_KEYWORD_END;
|
||||
case PM_CONTEXT_LAMBDA_BRACES:
|
||||
return token->type == PM_TOKEN_BRACE_RIGHT;
|
||||
case PM_CONTEXT_PREDICATE:
|
||||
return token->type == PM_TOKEN_KEYWORD_THEN || token->type == PM_TOKEN_NEWLINE || token->type == PM_TOKEN_SEMICOLON;
|
||||
case PM_CONTEXT_NONE:
|
||||
return false;
|
||||
}
|
||||
static const uint32_t context_terminators[] = {
|
||||
[PM_CONTEXT_NONE] = 0,
|
||||
[PM_CONTEXT_BEGIN] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_BEGIN_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_BEGIN_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_BEGIN_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_BLOCK_BRACES] = (1 << PM_TOKEN_BRACE_RIGHT),
|
||||
[PM_CONTEXT_BLOCK_KEYWORDS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
||||
[PM_CONTEXT_BLOCK_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_BLOCK_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_BLOCK_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_CASE_WHEN] = (1 << PM_TOKEN_KEYWORD_WHEN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
|
||||
[PM_CONTEXT_CASE_IN] = (1 << PM_TOKEN_KEYWORD_IN) | (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_ELSE),
|
||||
[PM_CONTEXT_CLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
||||
[PM_CONTEXT_CLASS_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_CLASS_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_CLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_DEF] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
||||
[PM_CONTEXT_DEF_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_DEF_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_DEF_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_DEF_PARAMS] = (1 << PM_TOKEN_EOF),
|
||||
[PM_CONTEXT_DEFINED] = (1 << PM_TOKEN_EOF),
|
||||
[PM_CONTEXT_DEFAULT_PARAMS] = (1 << PM_TOKEN_COMMA) | (1 << PM_TOKEN_PARENTHESIS_RIGHT),
|
||||
[PM_CONTEXT_ELSE] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_ELSIF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_EMBEXPR] = (1 << PM_TOKEN_EMBEXPR_END),
|
||||
[PM_CONTEXT_FOR] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_FOR_INDEX] = (1 << PM_TOKEN_KEYWORD_IN),
|
||||
[PM_CONTEXT_IF] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_ELSIF) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_LAMBDA_BRACES] = (1 << PM_TOKEN_BRACE_RIGHT),
|
||||
[PM_CONTEXT_LAMBDA_DO_END] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
||||
[PM_CONTEXT_LAMBDA_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_LAMBDA_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_LAMBDA_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_LOOP_PREDICATE] = (1 << PM_TOKEN_KEYWORD_DO) | (1 << PM_TOKEN_KEYWORD_THEN),
|
||||
[PM_CONTEXT_MAIN] = (1 << PM_TOKEN_EOF),
|
||||
[PM_CONTEXT_MODULE] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
||||
[PM_CONTEXT_MODULE_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_MODULE_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_MODULE_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_MULTI_TARGET] = (1 << PM_TOKEN_EOF),
|
||||
[PM_CONTEXT_PARENS] = (1 << PM_TOKEN_PARENTHESIS_RIGHT),
|
||||
[PM_CONTEXT_POSTEXE] = (1 << PM_TOKEN_BRACE_RIGHT),
|
||||
[PM_CONTEXT_PREDICATE] = (1 << PM_TOKEN_KEYWORD_THEN) | (1 << PM_TOKEN_NEWLINE) | (1 << PM_TOKEN_SEMICOLON),
|
||||
[PM_CONTEXT_PREEXE] = (1 << PM_TOKEN_BRACE_RIGHT),
|
||||
[PM_CONTEXT_RESCUE_MODIFIER] = (1 << PM_TOKEN_EOF),
|
||||
[PM_CONTEXT_SCLASS] = (1 << PM_TOKEN_KEYWORD_END) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ENSURE),
|
||||
[PM_CONTEXT_SCLASS_ENSURE] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_SCLASS_ELSE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_SCLASS_RESCUE] = (1 << PM_TOKEN_KEYWORD_ENSURE) | (1 << PM_TOKEN_KEYWORD_RESCUE) | (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_TERNARY] = (1 << PM_TOKEN_EOF),
|
||||
[PM_CONTEXT_UNLESS] = (1 << PM_TOKEN_KEYWORD_ELSE) | (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_UNTIL] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
[PM_CONTEXT_WHILE] = (1 << PM_TOKEN_KEYWORD_END),
|
||||
};
|
||||
|
||||
return false;
|
||||
static inline bool
|
||||
context_terminator(pm_context_t context, pm_token_t *token) {
|
||||
return token->type < 32 && (context_terminators[context] & (1 << token->type));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -21202,6 +21183,13 @@ parse_expression_infix(pm_parser_t *parser, pm_node_t *node, pm_binding_power_t
|
|||
}
|
||||
PRISM_FALLTHROUGH
|
||||
case PM_CASE_WRITABLE: {
|
||||
// When we have `it = value`, we need to add `it` as a local
|
||||
// variable before parsing the value, in case the value
|
||||
// references the variable.
|
||||
if (PM_NODE_TYPE_P(node, PM_IT_LOCAL_VARIABLE_READ_NODE)) {
|
||||
pm_parser_local_add_location(parser, node->location.start, node->location.end, 0);
|
||||
}
|
||||
|
||||
parser_lex(parser);
|
||||
pm_node_t *value = parse_assignment_values(parser, previous_binding_power, PM_NODE_TYPE_P(node, PM_MULTI_TARGET_NODE) ? PM_BINDING_POWER_MULTI_ASSIGNMENT + 1 : binding_power, accepts_command_call, PM_ERR_EXPECT_EXPRESSION_AFTER_EQUAL, (uint16_t) (depth + 1));
|
||||
|
||||
|
@ -22195,6 +22183,12 @@ parse_expression(pm_parser_t *parser, pm_binding_power_t binding_power, bool acc
|
|||
) {
|
||||
node = parse_expression_infix(parser, node, binding_power, current_binding_powers.right, accepts_command_call, (uint16_t) (depth + 1));
|
||||
|
||||
if (context_terminator(parser->current_context->context, &parser->current)) {
|
||||
// If this token terminates the current context, then we need to
|
||||
// stop parsing the expression, as it has become a statement.
|
||||
return node;
|
||||
}
|
||||
|
||||
switch (PM_NODE_TYPE(node)) {
|
||||
case PM_MULTI_WRITE_NODE:
|
||||
// Multi-write nodes are statements, and cannot be followed by
|
||||
|
|
7
ractor.c
7
ractor.c
|
@ -19,6 +19,7 @@
|
|||
#include "internal/thread.h"
|
||||
#include "variable.h"
|
||||
#include "yjit.h"
|
||||
#include "zjit.h"
|
||||
|
||||
VALUE rb_cRactor;
|
||||
static VALUE rb_cRactorSelector;
|
||||
|
@ -511,6 +512,7 @@ ractor_create(rb_execution_context_t *ec, VALUE self, VALUE loc, VALUE name, VAL
|
|||
r->debug = cr->debug;
|
||||
|
||||
rb_yjit_before_ractor_spawn();
|
||||
rb_zjit_before_ractor_spawn();
|
||||
rb_thread_create_ractor(r, args, block);
|
||||
|
||||
RB_GC_GUARD(rv);
|
||||
|
@ -1679,8 +1681,7 @@ obj_traverse_replace_i(VALUE obj, struct obj_traverse_replace_data *data)
|
|||
} while (0)
|
||||
|
||||
if (UNLIKELY(rb_obj_exivar_p(obj))) {
|
||||
VALUE fields_obj;
|
||||
rb_ivar_generic_fields_tbl_lookup(obj, &fields_obj);
|
||||
VALUE fields_obj = rb_obj_fields_no_ractor_check(obj);
|
||||
|
||||
if (UNLIKELY(rb_shape_obj_too_complex_p(obj))) {
|
||||
struct obj_traverse_replace_callback_data d = {
|
||||
|
@ -2303,7 +2304,7 @@ static const rb_data_type_t cross_ractor_require_data_type = {
|
|||
NULL, // memsize
|
||||
NULL, // compact
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_DECL_MARKING | RUBY_TYPED_EMBEDDABLE
|
||||
};
|
||||
|
||||
static VALUE
|
||||
|
|
|
@ -1273,7 +1273,7 @@ static const rb_data_type_t ractor_selector_data_type = {
|
|||
ractor_selector_memsize,
|
||||
NULL, // update
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY,
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
||||
};
|
||||
|
||||
static struct ractor_selector *
|
||||
|
@ -1318,6 +1318,8 @@ ractor_selector_add(VALUE selv, VALUE rpv)
|
|||
}
|
||||
|
||||
st_insert(s->ports, (st_data_t)rpv, (st_data_t)rp);
|
||||
RB_OBJ_WRITTEN(selv, Qundef, rpv);
|
||||
|
||||
return selv;
|
||||
}
|
||||
|
||||
|
|
8
random.c
8
random.c
|
@ -263,7 +263,7 @@ const rb_data_type_t rb_random_data_type = {
|
|||
random_free,
|
||||
random_memsize,
|
||||
},
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
|
||||
0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
||||
};
|
||||
|
||||
#define random_mt_mark rb_random_mark
|
||||
|
@ -284,7 +284,7 @@ static const rb_data_type_t random_mt_type = {
|
|||
},
|
||||
&rb_random_data_type,
|
||||
(void *)&random_mt_if,
|
||||
RUBY_TYPED_FREE_IMMEDIATELY
|
||||
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED
|
||||
};
|
||||
|
||||
static rb_random_t *
|
||||
|
@ -422,10 +422,10 @@ random_init(int argc, VALUE *argv, VALUE obj)
|
|||
argc = rb_check_arity(argc, 0, 1);
|
||||
rb_check_frozen(obj);
|
||||
if (argc == 0) {
|
||||
rnd->seed = rand_init_default(rng, rnd);
|
||||
RB_OBJ_WRITE(obj, &rnd->seed, rand_init_default(rng, rnd));
|
||||
}
|
||||
else {
|
||||
rnd->seed = rand_init(rng, rnd, rb_to_int(argv[0]));
|
||||
RB_OBJ_WRITE(obj, &rnd->seed, rand_init(rng, rnd, rb_to_int(argv[0])));
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
|
6
ruby.c
6
ruby.c
|
@ -1819,8 +1819,10 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
|
|||
|
||||
if (rb_namespace_available())
|
||||
rb_initialize_main_namespace();
|
||||
rb_namespace_init_done();
|
||||
ruby_init_prelude();
|
||||
|
||||
// Initialize JITs after prelude because JITing prelude is typically not optimal.
|
||||
// Initialize JITs after ruby_init_prelude() because JITing prelude is typically not optimal.
|
||||
#if USE_YJIT
|
||||
rb_yjit_init(opt->yjit);
|
||||
#endif
|
||||
|
@ -1831,8 +1833,6 @@ ruby_opt_init(ruby_cmdline_options_t *opt)
|
|||
}
|
||||
#endif
|
||||
|
||||
rb_namespace_init_done();
|
||||
ruby_init_prelude();
|
||||
ruby_set_script_name(opt->script_name);
|
||||
require_libraries(&opt->req_list);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
#include "ruby/atomic.h"
|
||||
|
||||
#define RUBY_ATOMIC_VALUE_LOAD(x) (VALUE)(RUBY_ATOMIC_PTR_LOAD(x))
|
||||
#define RUBY_ATOMIC_VALUE_LOAD(x) rbimpl_atomic_value_load(&(x), RBIMPL_ATOMIC_SEQ_CST)
|
||||
|
||||
/* shim macros only */
|
||||
#define ATOMIC_ADD(var, val) RUBY_ATOMIC_ADD(var, val)
|
||||
|
@ -27,16 +27,7 @@
|
|||
#define ATOMIC_VALUE_CAS(var, oldval, val) RUBY_ATOMIC_VALUE_CAS(var, oldval, val)
|
||||
#define ATOMIC_VALUE_EXCHANGE(var, val) RUBY_ATOMIC_VALUE_EXCHANGE(var, val)
|
||||
|
||||
static inline rb_atomic_t
|
||||
rbimpl_atomic_load_relaxed(volatile rb_atomic_t *ptr)
|
||||
{
|
||||
#if defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
return __atomic_load_n(ptr, __ATOMIC_RELAXED);
|
||||
#else
|
||||
return *ptr;
|
||||
#endif
|
||||
}
|
||||
#define ATOMIC_LOAD_RELAXED(var) rbimpl_atomic_load_relaxed(&(var))
|
||||
#define ATOMIC_LOAD_RELAXED(var) rbimpl_atomic_load(&(var), RBIMPL_ATOMIC_RELAXED)
|
||||
|
||||
typedef RBIMPL_ALIGNAS(8) uint64_t rbimpl_atomic_uint64_t;
|
||||
|
||||
|
|
|
@ -324,6 +324,9 @@ typedef struct RNode_IN {
|
|||
struct RNode *nd_head;
|
||||
struct RNode *nd_body;
|
||||
struct RNode *nd_next;
|
||||
rb_code_location_t in_keyword_loc;
|
||||
rb_code_location_t then_keyword_loc;
|
||||
rb_code_location_t operator_loc;
|
||||
} rb_node_in_t;
|
||||
|
||||
typedef struct RNode_LOOP {
|
||||
|
@ -901,6 +904,8 @@ typedef struct RNode_MODULE {
|
|||
|
||||
struct RNode *nd_cpath;
|
||||
struct RNode *nd_body;
|
||||
rb_code_location_t module_keyword_loc;
|
||||
rb_code_location_t end_keyword_loc;
|
||||
} rb_node_module_t;
|
||||
|
||||
typedef struct RNode_SCLASS {
|
||||
|
|
5
set.c
5
set.c
|
@ -139,7 +139,6 @@ set_mark(void *ptr)
|
|||
static void
|
||||
set_free_embedded(struct set_object *sobj)
|
||||
{
|
||||
free((&sobj->table)->bins);
|
||||
free((&sobj->table)->entries);
|
||||
}
|
||||
|
||||
|
@ -172,9 +171,7 @@ set_foreach_replace(st_data_t key, st_data_t argp, int error)
|
|||
static int
|
||||
set_replace_ref(st_data_t *key, st_data_t argp, int existing)
|
||||
{
|
||||
if (rb_gc_location((VALUE)*key) != (VALUE)*key) {
|
||||
*key = rb_gc_location((VALUE)*key);
|
||||
}
|
||||
rb_gc_mark_and_move((VALUE *)key);
|
||||
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
|
21
shape.c
21
shape.c
|
@ -296,26 +296,13 @@ rb_shape_get_root_shape(void)
|
|||
}
|
||||
|
||||
static void
|
||||
shape_tree_mark(void *data)
|
||||
shape_tree_mark_and_move(void *data)
|
||||
{
|
||||
rb_shape_t *cursor = rb_shape_get_root_shape();
|
||||
rb_shape_t *end = RSHAPE(rb_shape_tree.next_shape_id - 1);
|
||||
while (cursor <= end) {
|
||||
if (cursor->edges && !SINGLE_CHILD_P(cursor->edges)) {
|
||||
rb_gc_mark_movable(cursor->edges);
|
||||
}
|
||||
cursor++;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
shape_tree_compact(void *data)
|
||||
{
|
||||
rb_shape_t *cursor = rb_shape_get_root_shape();
|
||||
rb_shape_t *end = RSHAPE(rb_shape_tree.next_shape_id - 1);
|
||||
while (cursor <= end) {
|
||||
if (cursor->edges && !SINGLE_CHILD_P(cursor->edges)) {
|
||||
cursor->edges = rb_gc_location(cursor->edges);
|
||||
rb_gc_mark_and_move(&cursor->edges);
|
||||
}
|
||||
cursor++;
|
||||
}
|
||||
|
@ -330,10 +317,10 @@ shape_tree_memsize(const void *data)
|
|||
static const rb_data_type_t shape_tree_type = {
|
||||
.wrap_struct_name = "VM/shape_tree",
|
||||
.function = {
|
||||
.dmark = shape_tree_mark,
|
||||
.dmark = shape_tree_mark_and_move,
|
||||
.dfree = NULL, // Nothing to free, done at VM exit in rb_shape_free_all,
|
||||
.dsize = shape_tree_memsize,
|
||||
.dcompact = shape_tree_compact,
|
||||
.dcompact = shape_tree_mark_and_move,
|
||||
},
|
||||
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED,
|
||||
};
|
||||
|
|
96
st.c
96
st.c
|
@ -2395,18 +2395,44 @@ set_get_allocated_entries(const set_table *tab)
|
|||
return ((st_index_t) 1)<<tab->entry_power;
|
||||
}
|
||||
|
||||
static inline size_t
|
||||
set_allocated_entries_size(const set_table *tab)
|
||||
{
|
||||
return set_get_allocated_entries(tab) * sizeof(set_table_entry);
|
||||
}
|
||||
|
||||
static inline bool
|
||||
set_has_bins(const set_table *tab)
|
||||
{
|
||||
return tab->entry_power > MAX_POWER2_FOR_TABLES_WITHOUT_BINS;
|
||||
}
|
||||
|
||||
/* Return size of the allocated bins of table TAB. */
|
||||
static inline st_index_t
|
||||
set_bins_size(const set_table *tab)
|
||||
{
|
||||
return features[tab->entry_power].bins_words * sizeof (st_index_t);
|
||||
if (set_has_bins(tab)) {
|
||||
return features[tab->entry_power].bins_words * sizeof (st_index_t);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline st_index_t *
|
||||
set_bins_ptr(const set_table *tab)
|
||||
{
|
||||
if (set_has_bins(tab)) {
|
||||
return (st_index_t *)(((char *)tab->entries) + set_allocated_entries_size(tab));
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Mark all bins of table TAB as empty. */
|
||||
static void
|
||||
set_initialize_bins(set_table *tab)
|
||||
{
|
||||
memset(tab->bins, 0, set_bins_size(tab));
|
||||
memset(set_bins_ptr(tab), 0, set_bins_size(tab));
|
||||
}
|
||||
|
||||
/* Make table TAB empty. */
|
||||
|
@ -2415,7 +2441,7 @@ set_make_tab_empty(set_table *tab)
|
|||
{
|
||||
tab->num_entries = 0;
|
||||
tab->entries_start = tab->entries_bound = 0;
|
||||
if (tab->bins != NULL)
|
||||
if (set_bins_ptr(tab) != NULL)
|
||||
set_initialize_bins(tab);
|
||||
}
|
||||
|
||||
|
@ -2443,13 +2469,13 @@ set_init_existing_table_with_size(set_table *tab, const struct st_hash_type *typ
|
|||
tab->entry_power = n;
|
||||
tab->bin_power = features[n].bin_power;
|
||||
tab->size_ind = features[n].size_ind;
|
||||
if (n <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS)
|
||||
tab->bins = NULL;
|
||||
else {
|
||||
tab->bins = (st_index_t *) malloc(set_bins_size(tab));
|
||||
|
||||
size_t memsize = 0;
|
||||
if (set_has_bins(tab)) {
|
||||
memsize += set_bins_size(tab);
|
||||
}
|
||||
tab->entries = (set_table_entry *) malloc(set_get_allocated_entries(tab)
|
||||
* sizeof(set_table_entry));
|
||||
memsize += set_get_allocated_entries(tab) * sizeof(set_table_entry);
|
||||
tab->entries = (set_table_entry *)malloc(memsize);
|
||||
set_make_tab_empty(tab);
|
||||
tab->rebuilds_num = 0;
|
||||
return tab;
|
||||
|
@ -2499,7 +2525,6 @@ set_table_clear(set_table *tab)
|
|||
void
|
||||
set_free_table(set_table *tab)
|
||||
{
|
||||
free(tab->bins);
|
||||
free(tab->entries);
|
||||
free(tab);
|
||||
}
|
||||
|
@ -2509,7 +2534,7 @@ size_t
|
|||
set_memsize(const set_table *tab)
|
||||
{
|
||||
return(sizeof(set_table)
|
||||
+ (tab->bins == NULL ? 0 : set_bins_size(tab))
|
||||
+ (tab->entry_power <= MAX_POWER2_FOR_TABLES_WITHOUT_BINS ? 0 : set_bins_size(tab))
|
||||
+ set_get_allocated_entries(tab) * sizeof(set_table_entry));
|
||||
}
|
||||
|
||||
|
@ -2542,7 +2567,7 @@ set_rebuild_table(set_table *tab)
|
|||
|| tab->num_entries < (1 << MINIMAL_POWER2)) {
|
||||
/* Compaction: */
|
||||
tab->num_entries = 0;
|
||||
if (tab->bins != NULL)
|
||||
if (set_has_bins(tab))
|
||||
set_initialize_bins(tab);
|
||||
set_rebuild_table_with(tab, tab);
|
||||
}
|
||||
|
@ -2572,7 +2597,7 @@ set_rebuild_table_with(set_table *const new_tab, set_table *const tab)
|
|||
new_entries = new_tab->entries;
|
||||
|
||||
ni = 0;
|
||||
bins = new_tab->bins;
|
||||
bins = set_bins_ptr(new_tab);
|
||||
size_ind = set_get_size_ind(new_tab);
|
||||
st_index_t bound = tab->entries_bound;
|
||||
set_table_entry *entries = tab->entries;
|
||||
|
@ -2602,8 +2627,6 @@ set_rebuild_move_table(set_table *const new_tab, set_table *const tab)
|
|||
tab->entry_power = new_tab->entry_power;
|
||||
tab->bin_power = new_tab->bin_power;
|
||||
tab->size_ind = new_tab->size_ind;
|
||||
free(tab->bins);
|
||||
tab->bins = new_tab->bins;
|
||||
free(tab->entries);
|
||||
tab->entries = new_tab->entries;
|
||||
free(new_tab);
|
||||
|
@ -2688,7 +2711,7 @@ set_find_table_entry_ind(set_table *tab, st_hash_t hash_value, st_data_t key)
|
|||
perturb = hash_value;
|
||||
#endif
|
||||
for (;;) {
|
||||
bin = get_bin(tab->bins, set_get_size_ind(tab), ind);
|
||||
bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), ind);
|
||||
if (! EMPTY_OR_DELETED_BIN_P(bin)) {
|
||||
DO_PTR_EQUAL_CHECK(tab, &entries[bin - ENTRY_BASE], hash_value, key, eq_p, rebuilt_p);
|
||||
if (EXPECT(rebuilt_p, 0))
|
||||
|
@ -2732,7 +2755,7 @@ set_find_table_bin_ind(set_table *tab, st_hash_t hash_value, st_data_t key)
|
|||
perturb = hash_value;
|
||||
#endif
|
||||
for (;;) {
|
||||
bin = get_bin(tab->bins, set_get_size_ind(tab), ind);
|
||||
bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), ind);
|
||||
if (! EMPTY_OR_DELETED_BIN_P(bin)) {
|
||||
DO_PTR_EQUAL_CHECK(tab, &entries[bin - ENTRY_BASE], hash_value, key, eq_p, rebuilt_p);
|
||||
if (EXPECT(rebuilt_p, 0))
|
||||
|
@ -2773,7 +2796,7 @@ set_find_table_bin_ind_direct(set_table *tab, st_hash_t hash_value, st_data_t ke
|
|||
perturb = hash_value;
|
||||
#endif
|
||||
for (;;) {
|
||||
bin = get_bin(tab->bins, set_get_size_ind(tab), ind);
|
||||
bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), ind);
|
||||
if (EMPTY_OR_DELETED_BIN_P(bin))
|
||||
return ind;
|
||||
#ifdef QUADRATIC_PROBE
|
||||
|
@ -2787,7 +2810,7 @@ set_find_table_bin_ind_direct(set_table *tab, st_hash_t hash_value, st_data_t ke
|
|||
|
||||
/* Mark I-th bin of table TAB as empty, in other words not
|
||||
corresponding to any entry. */
|
||||
#define MARK_SET_BIN_EMPTY(tab, i) (set_bin((tab)->bins, set_get_size_ind(tab), i, EMPTY_BIN))
|
||||
#define MARK_SET_BIN_EMPTY(tab, i) (set_bin(set_bins_ptr(tab), set_get_size_ind(tab), i, EMPTY_BIN))
|
||||
|
||||
/* Return index of table TAB bin for HASH_VALUE and KEY through
|
||||
BIN_IND and the pointed value as the function result. Reserve the
|
||||
|
@ -2823,7 +2846,7 @@ set_find_table_bin_ptr_and_reserve(set_table *tab, st_hash_t *hash_value,
|
|||
firset_deleted_bin_ind = UNDEFINED_BIN_IND;
|
||||
entries = tab->entries;
|
||||
for (;;) {
|
||||
entry_index = get_bin(tab->bins, set_get_size_ind(tab), ind);
|
||||
entry_index = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), ind);
|
||||
if (EMPTY_BIN_P(entry_index)) {
|
||||
tab->num_entries++;
|
||||
entry_index = UNDEFINED_ENTRY_IND;
|
||||
|
@ -2863,7 +2886,7 @@ set_table_lookup(set_table *tab, st_data_t key)
|
|||
st_hash_t hash = set_do_hash(key, tab);
|
||||
|
||||
retry:
|
||||
if (tab->bins == NULL) {
|
||||
if (!set_has_bins(tab)) {
|
||||
bin = set_find_entry(tab, hash, key);
|
||||
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
|
||||
goto retry;
|
||||
|
@ -2907,7 +2930,7 @@ set_insert(set_table *tab, st_data_t key)
|
|||
hash_value = set_do_hash(key, tab);
|
||||
retry:
|
||||
set_rebuild_table_if_necessary(tab);
|
||||
if (tab->bins == NULL) {
|
||||
if (!set_has_bins(tab)) {
|
||||
bin = set_find_entry(tab, hash_value, key);
|
||||
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
|
||||
goto retry;
|
||||
|
@ -2930,7 +2953,7 @@ set_insert(set_table *tab, st_data_t key)
|
|||
entry->hash = hash_value;
|
||||
entry->key = key;
|
||||
if (bin_ind != UNDEFINED_BIN_IND)
|
||||
set_bin(tab->bins, set_get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
|
||||
set_bin(set_bins_ptr(tab), set_get_size_ind(tab), bin_ind, ind + ENTRY_BASE);
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
@ -2941,18 +2964,9 @@ static set_table *
|
|||
set_replace(set_table *new_tab, set_table *old_tab)
|
||||
{
|
||||
*new_tab = *old_tab;
|
||||
if (old_tab->bins == NULL)
|
||||
new_tab->bins = NULL;
|
||||
else {
|
||||
new_tab->bins = (st_index_t *) malloc(set_bins_size(old_tab));
|
||||
}
|
||||
new_tab->entries = (set_table_entry *) malloc(set_get_allocated_entries(old_tab)
|
||||
* sizeof(set_table_entry));
|
||||
MEMCPY(new_tab->entries, old_tab->entries, set_table_entry,
|
||||
set_get_allocated_entries(old_tab));
|
||||
if (old_tab->bins != NULL)
|
||||
MEMCPY(new_tab->bins, old_tab->bins, char, set_bins_size(old_tab));
|
||||
|
||||
size_t memsize = set_allocated_entries_size(old_tab) + set_bins_size(old_tab);
|
||||
new_tab->entries = (set_table_entry *)malloc(memsize);
|
||||
MEMCPY(new_tab->entries, old_tab->entries, char, memsize);
|
||||
return new_tab;
|
||||
}
|
||||
|
||||
|
@ -2991,7 +3005,7 @@ set_update_range_for_deleted(set_table *tab, st_index_t n)
|
|||
corresponding to deleted entries. */
|
||||
#define MARK_SET_BIN_DELETED(tab, i) \
|
||||
do { \
|
||||
set_bin((tab)->bins, set_get_size_ind(tab), i, DELETED_BIN); \
|
||||
set_bin(set_bins_ptr(tab), set_get_size_ind(tab), i, DELETED_BIN); \
|
||||
} while (0)
|
||||
|
||||
/* Delete entry with KEY from table TAB, and return non-zero. If
|
||||
|
@ -3006,7 +3020,7 @@ set_table_delete(set_table *tab, st_data_t *key)
|
|||
|
||||
hash = set_do_hash(*key, tab);
|
||||
retry:
|
||||
if (tab->bins == NULL) {
|
||||
if (!set_has_bins(tab)) {
|
||||
bin = set_find_entry(tab, hash, *key);
|
||||
if (EXPECT(bin == REBUILT_TABLE_ENTRY_IND, 0))
|
||||
goto retry;
|
||||
|
@ -3021,7 +3035,7 @@ set_table_delete(set_table *tab, st_data_t *key)
|
|||
if (bin_ind == UNDEFINED_BIN_IND) {
|
||||
return 0;
|
||||
}
|
||||
bin = get_bin(tab->bins, set_get_size_ind(tab), bin_ind) - ENTRY_BASE;
|
||||
bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), bin_ind) - ENTRY_BASE;
|
||||
MARK_SET_BIN_DELETED(tab, bin_ind);
|
||||
}
|
||||
entry = &tab->entries[bin];
|
||||
|
@ -3052,7 +3066,7 @@ set_general_foreach(set_table *tab, set_foreach_check_callback_func *func,
|
|||
st_index_t i, rebuilds_num;
|
||||
st_hash_t hash;
|
||||
st_data_t key;
|
||||
int error_p, packed_p = tab->bins == NULL;
|
||||
int error_p, packed_p = !set_has_bins(tab);
|
||||
|
||||
entries = tab->entries;
|
||||
/* The bound can change inside the loop even without rebuilding
|
||||
|
@ -3074,7 +3088,7 @@ set_general_foreach(set_table *tab, set_foreach_check_callback_func *func,
|
|||
if (rebuilds_num != tab->rebuilds_num) {
|
||||
retry:
|
||||
entries = tab->entries;
|
||||
packed_p = tab->bins == NULL;
|
||||
packed_p = !set_has_bins(tab);
|
||||
if (packed_p) {
|
||||
i = set_find_entry(tab, hash, key);
|
||||
if (EXPECT(i == REBUILT_TABLE_ENTRY_IND, 0))
|
||||
|
@ -3122,7 +3136,7 @@ set_general_foreach(set_table *tab, set_foreach_check_callback_func *func,
|
|||
goto again;
|
||||
if (bin_ind == UNDEFINED_BIN_IND)
|
||||
break;
|
||||
bin = get_bin(tab->bins, set_get_size_ind(tab), bin_ind) - ENTRY_BASE;
|
||||
bin = get_bin(set_bins_ptr(tab), set_get_size_ind(tab), bin_ind) - ENTRY_BASE;
|
||||
MARK_SET_BIN_DELETED(tab, bin_ind);
|
||||
}
|
||||
curr_entry_ptr = &entries[bin];
|
||||
|
|
52
string.c
52
string.c
|
@ -4381,9 +4381,9 @@ str_casecmp(VALUE str1, VALUE str2)
|
|||
p2 += l2;
|
||||
}
|
||||
}
|
||||
if (RSTRING_LEN(str1) == RSTRING_LEN(str2)) return INT2FIX(0);
|
||||
if (RSTRING_LEN(str1) > RSTRING_LEN(str2)) return INT2FIX(1);
|
||||
return INT2FIX(-1);
|
||||
if (p1 == p1end && p2 == p2end) return INT2FIX(0);
|
||||
if (p1 == p1end) return INT2FIX(-1);
|
||||
return INT2FIX(1);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -6576,15 +6576,12 @@ str_gsub(int argc, VALUE *argv, VALUE str, int bang)
|
|||
* gsub!(pattern) {|match| ... } -> self or nil
|
||||
* gsub!(pattern) -> an_enumerator
|
||||
*
|
||||
* Performs the specified substring replacement(s) on +self+;
|
||||
* returns +self+ if any replacement occurred, +nil+ otherwise.
|
||||
* Like String#gsub, except that:
|
||||
*
|
||||
* See {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
|
||||
*
|
||||
* Returns an Enumerator if no +replacement+ and no block given.
|
||||
*
|
||||
* Related: String#sub, String#gsub, String#sub!.
|
||||
* - Performs substitutions in +self+ (not in a copy of +self+).
|
||||
* - Returns +self+ if any characters are removed, +nil+ otherwise.
|
||||
*
|
||||
* Related: see {Modifying}[rdoc-ref:String@Modifying].
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
|
@ -6601,14 +6598,41 @@ rb_str_gsub_bang(int argc, VALUE *argv, VALUE str)
|
|||
* gsub(pattern) {|match| ... } -> new_string
|
||||
* gsub(pattern) -> enumerator
|
||||
*
|
||||
* Returns a copy of +self+ with all occurrences of the given +pattern+ replaced.
|
||||
* Returns a copy of +self+ with zero or more substrings replaced.
|
||||
*
|
||||
* See {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
|
||||
* Argument +pattern+ may be a string or a Regexp;
|
||||
* argument +replacement+ may be a string or a Hash.
|
||||
* Varying types for the argument values makes this method very versatile.
|
||||
*
|
||||
* Returns an Enumerator if no +replacement+ and no block given.
|
||||
* Below are some simple examples;
|
||||
* for many more examples, see {Substitution Methods}[rdoc-ref:String@Substitution+Methods].
|
||||
*
|
||||
* Related: String#sub, String#sub!, String#gsub!.
|
||||
* With arguments +pattern+ and string +replacement+ given,
|
||||
* replaces each matching substring with the given +replacement+ string:
|
||||
*
|
||||
* s = 'abracadabra'
|
||||
* s.gsub('ab', 'AB') # => "ABracadABra"
|
||||
* s.gsub(/[a-c]/, 'X') # => "XXrXXXdXXrX"
|
||||
*
|
||||
* With arguments +pattern+ and hash +replacement+ given,
|
||||
* replaces each matching substring with a value from the given +replacement+ hash,
|
||||
* or removes it:
|
||||
*
|
||||
* h = {'a' => 'A', 'b' => 'B', 'c' => 'C'}
|
||||
* s.gsub(/[a-c]/, h) # => "ABrACAdABrA" # 'a', 'b', 'c' replaced.
|
||||
* s.gsub(/[a-d]/, h) # => "ABrACAABrA" # 'd' removed.
|
||||
*
|
||||
* With argument +pattern+ and a block given,
|
||||
* calls the block with each matching substring;
|
||||
* replaces that substring with the block's return value:
|
||||
*
|
||||
* s.gsub(/[a-d]/) {|substring| substring.upcase }
|
||||
* # => "ABrACADABrA"
|
||||
*
|
||||
* With argument +pattern+ and no block given,
|
||||
* returns a new Enumerator.
|
||||
*
|
||||
* Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
|
|
11
struct.c
11
struct.c
|
@ -811,13 +811,22 @@ struct_alloc(VALUE klass)
|
|||
{
|
||||
long n = num_members(klass);
|
||||
size_t embedded_size = offsetof(struct RStruct, as.ary) + (sizeof(VALUE) * n);
|
||||
if (RCLASS_MAX_IV_COUNT(klass) > 0) {
|
||||
embedded_size += sizeof(VALUE);
|
||||
}
|
||||
|
||||
VALUE flags = T_STRUCT | (RGENGC_WB_PROTECTED_STRUCT ? FL_WB_PROTECTED : 0);
|
||||
|
||||
if (n > 0 && rb_gc_size_allocatable_p(embedded_size)) {
|
||||
flags |= n << RSTRUCT_EMBED_LEN_SHIFT;
|
||||
|
||||
NEWOBJ_OF(st, struct RStruct, klass, flags, embedded_size, 0);
|
||||
|
||||
if (RCLASS_MAX_IV_COUNT(klass) == 0 && embedded_size == rb_gc_obj_slot_size((VALUE)st)) {
|
||||
FL_SET_RAW((VALUE)st, RSTRUCT_GEN_FIELDS);
|
||||
}
|
||||
else {
|
||||
RSTRUCT_SET_FIELDS_OBJ((VALUE)st, 0);
|
||||
}
|
||||
rb_mem_clear((VALUE *)st->as.ary, n);
|
||||
|
||||
return (VALUE)st;
|
||||
|
|
25
symbol.c
25
symbol.c
|
@ -99,7 +99,9 @@ typedef struct {
|
|||
VALUE ids;
|
||||
} rb_symbols_t;
|
||||
|
||||
rb_symbols_t ruby_global_symbols = {tNEXT_ID-1};
|
||||
rb_symbols_t ruby_global_symbols = {
|
||||
.next_id = tNEXT_ID,
|
||||
};
|
||||
|
||||
struct sym_set_static_sym_entry {
|
||||
VALUE sym;
|
||||
|
@ -369,21 +371,26 @@ Init_sym(void)
|
|||
}
|
||||
|
||||
void
|
||||
rb_sym_global_symbols_mark(void)
|
||||
rb_sym_global_symbols_mark_and_move(void)
|
||||
{
|
||||
rb_symbols_t *symbols = &ruby_global_symbols;
|
||||
|
||||
rb_gc_mark_movable(symbols->sym_set);
|
||||
rb_gc_mark_movable(symbols->ids);
|
||||
rb_gc_mark_and_move(&symbols->sym_set);
|
||||
rb_gc_mark_and_move(&symbols->ids);
|
||||
}
|
||||
|
||||
static int
|
||||
rb_free_global_symbol_table_i(VALUE *sym_ptr, void *data)
|
||||
{
|
||||
sym_set_free(*sym_ptr);
|
||||
|
||||
return ST_DELETE;
|
||||
}
|
||||
|
||||
void
|
||||
rb_sym_global_symbols_update_references(void)
|
||||
rb_free_global_symbol_table(void)
|
||||
{
|
||||
rb_symbols_t *symbols = &ruby_global_symbols;
|
||||
|
||||
symbols->sym_set = rb_gc_location(symbols->sym_set);
|
||||
symbols->ids = rb_gc_location(symbols->ids);
|
||||
rb_concurrent_set_foreach_with_replace(ruby_global_symbols.sym_set, rb_free_global_symbol_table_i, NULL);
|
||||
}
|
||||
|
||||
WARN_UNUSED_RESULT(static ID lookup_str_id(VALUE str));
|
||||
|
|
|
@ -289,6 +289,8 @@ ABI_VERSION_HDR = $(hdrdir)/ruby/internal/abi.h
|
|||
|
||||
CAT_DEPEND = sed -e 's/{\$$([^(){}]*)[^{}]*}//g' -e /AUTOGENERATED/q
|
||||
|
||||
HASH_SIGN = \#
|
||||
|
||||
.SUFFIXES: .inc .h .c .y .i .$(ASMEXT) .$(DTRACE_EXT)
|
||||
|
||||
all:
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
# Issue: https://github.com/Shopify/ruby/issues/646
|
||||
exclude(/test_/, 'Tests make ZJIT panic on Ubuntu')
|
|
@ -46,21 +46,26 @@ class TestMkmfPkgConfig < TestMkmf
|
|||
def test_pkgconfig_with_libs_option_returns_output
|
||||
pend("skipping because pkg-config is not installed") unless PKG_CONFIG
|
||||
expected = ["-L#{@fixtures_lib_dir}", "-ltest1-public"].sort
|
||||
actual = pkg_config("test1", "libs").shellsplit.sort
|
||||
assert_equal(expected, actual, MKMFLOG)
|
||||
actual = pkg_config("test1", "libs")
|
||||
assert_equal_sorted(expected, actual, MKMFLOG)
|
||||
end
|
||||
|
||||
def test_pkgconfig_with_cflags_option_returns_output
|
||||
pend("skipping because pkg-config is not installed") unless PKG_CONFIG
|
||||
expected = ["--cflags-other", "-I#{@fixtures_inc_dir}/cflags-I"].sort
|
||||
actual = pkg_config("test1", "cflags").shellsplit.sort
|
||||
assert_equal(expected, actual, MKMFLOG)
|
||||
actual = pkg_config("test1", "cflags")
|
||||
assert_equal_sorted(expected, actual, MKMFLOG)
|
||||
end
|
||||
|
||||
def test_pkgconfig_with_multiple_options
|
||||
pend("skipping because pkg-config is not installed") unless PKG_CONFIG
|
||||
expected = ["-L#{@fixtures_lib_dir}", "-ltest1-public", "-ltest1-private"].sort
|
||||
actual = pkg_config("test1", "libs", "static").shellsplit.sort
|
||||
assert_equal(expected, actual, MKMFLOG)
|
||||
actual = pkg_config("test1", "libs", "static")
|
||||
assert_equal_sorted(expected, actual, MKMFLOG)
|
||||
end
|
||||
|
||||
private def assert_equal_sorted(expected, actual, msg = nil)
|
||||
actual = actual.shellsplit.sort if actual
|
||||
assert_equal(expected, actual, msg)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -103,6 +103,8 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase
|
|||
end if !openssl?(3, 0, 0)
|
||||
|
||||
def test_params_ok?
|
||||
omit_on_fips
|
||||
|
||||
# Skip the tests in old OpenSSL version 1.1.1c or early versions before
|
||||
# applying the following commits in OpenSSL 1.1.1d to make `DH_check`
|
||||
# function pass the RFC 7919 FFDHE group texts.
|
||||
|
|
|
@ -72,6 +72,8 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase
|
|||
end
|
||||
|
||||
def test_check_key
|
||||
omit_on_fips
|
||||
|
||||
key0 = Fixtures.pkey("p256")
|
||||
assert_equal(true, key0.check_key)
|
||||
assert_equal(true, key0.private?)
|
||||
|
|
|
@ -47,7 +47,7 @@ class TestOptionParserLoad < Test::Unit::TestCase
|
|||
begin
|
||||
yield dir, optdir
|
||||
ensure
|
||||
File.unlink(file)
|
||||
File.unlink(file) rescue nil
|
||||
Dir.rmdir(optdir) rescue nil
|
||||
end
|
||||
else
|
||||
|
@ -101,7 +101,7 @@ class TestOptionParserLoad < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_load_xdg_config_home
|
||||
result, = setup_options_xdg_config_home
|
||||
result, dir = setup_options_xdg_config_home
|
||||
assert_load(result)
|
||||
|
||||
setup_options_home_config do
|
||||
|
@ -115,6 +115,11 @@ class TestOptionParserLoad < Test::Unit::TestCase
|
|||
setup_options_home_config_settings do
|
||||
assert_load(result)
|
||||
end
|
||||
|
||||
File.unlink("#{dir}/#{@basename}.options")
|
||||
setup_options_home_config do
|
||||
assert_load_nothing
|
||||
end
|
||||
end
|
||||
|
||||
def test_load_home_config
|
||||
|
@ -128,6 +133,11 @@ class TestOptionParserLoad < Test::Unit::TestCase
|
|||
setup_options_home_config_settings do
|
||||
assert_load(result)
|
||||
end
|
||||
|
||||
setup_options_xdg_config_home do |_, dir|
|
||||
File.unlink("#{dir}/#{@basename}.options")
|
||||
assert_load_nothing
|
||||
end
|
||||
end
|
||||
|
||||
def test_load_xdg_config_dirs
|
||||
|
|
6
test/prism/fixtures/case_in_hash_key.txt
Normal file
6
test/prism/fixtures/case_in_hash_key.txt
Normal file
|
@ -0,0 +1,6 @@
|
|||
case 1
|
||||
in 2
|
||||
A.print message:
|
||||
in 3
|
||||
A.print message:
|
||||
end
|
1
test/prism/fixtures/it_assignment.txt
Normal file
1
test/prism/fixtures/it_assignment.txt
Normal file
|
@ -0,0 +1 @@
|
|||
42.tap { it = it; p it }
|
1
test/prism/fixtures/it_read_and_assignment.txt
Normal file
1
test/prism/fixtures/it_read_and_assignment.txt
Normal file
|
@ -0,0 +1 @@
|
|||
42.tap { p it; it = it; p it }
|
|
@ -62,7 +62,11 @@ module Prism
|
|||
if reader
|
||||
reader.gets.chomp
|
||||
else
|
||||
puts(ignore_warnings { Ractor.new(*arguments, &block) }.value)
|
||||
ractor = ignore_warnings { Ractor.new(*arguments, &block) }
|
||||
|
||||
# Somewhere in the Ruby 3.5.* series, Ractor#take was removed and
|
||||
# Ractor#value was added.
|
||||
puts(ractor.respond_to?(:value) ? ractor.value : ractor.take)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -54,7 +54,7 @@ module Prism
|
|||
assert_parameters([[:keyrest, :**]], "**")
|
||||
end
|
||||
|
||||
if RUBY_ENGINE != "truffleruby"
|
||||
if RUBY_ENGINE == "ruby"
|
||||
def test_key_ordering
|
||||
assert_parameters([[:keyreq, :a], [:keyreq, :b], [:key, :c], [:key, :d]], "a:, c: 1, b:, d: 2")
|
||||
end
|
||||
|
|
|
@ -99,16 +99,6 @@ module Prism
|
|||
"seattlerb/regexp_esc_C_slash.txt",
|
||||
]
|
||||
|
||||
# These files are either failing to parse or failing to translate, so we'll
|
||||
# skip them for now.
|
||||
skip_all = skip_incorrect | [
|
||||
]
|
||||
|
||||
# Not sure why these files are failing on JRuby, but skipping them for now.
|
||||
if RUBY_ENGINE == "jruby"
|
||||
skip_all.push("emoji_method_calls.txt", "symbols.txt")
|
||||
end
|
||||
|
||||
# These files are failing to translate their lexer output into the lexer
|
||||
# output expected by the parser gem, so we'll skip them for now.
|
||||
skip_tokens = [
|
||||
|
@ -147,7 +137,7 @@ module Prism
|
|||
define_method(fixture.test_name) do
|
||||
assert_equal_parses(
|
||||
fixture,
|
||||
compare_asts: !skip_all.include?(fixture.path),
|
||||
compare_asts: !skip_incorrect.include?(fixture.path),
|
||||
compare_tokens: !skip_tokens.include?(fixture.path),
|
||||
compare_comments: fixture.path != "embdoc_no_newline_at_end.txt"
|
||||
)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
return if RUBY_VERSION < "3.3" || RUBY_ENGINE == "truffleruby"
|
||||
return if RUBY_VERSION < "3.3" || RUBY_ENGINE != "ruby"
|
||||
|
||||
require_relative "../test_helper"
|
||||
|
||||
|
|
|
@ -1491,6 +1491,11 @@ dummy
|
|||
assert_locations(node.children[-1].locations, [[1, 0, 1, 20], [1, 0, 1, 2], [1, 10, 1, 12], [1, 17, 1, 20]])
|
||||
end
|
||||
|
||||
def test_module_locations
|
||||
node = ast_parse('module A end')
|
||||
assert_locations(node.children[-1].locations, [[1, 0, 1, 12], [1, 0, 1, 6], [1, 9, 1, 12]])
|
||||
end
|
||||
|
||||
def test_if_locations
|
||||
node = ast_parse("if cond then 1 else 2 end")
|
||||
assert_locations(node.children[-1].locations, [[1, 0, 1, 25], [1, 0, 1, 2], [1, 8, 1, 12], [1, 22, 1, 25]])
|
||||
|
@ -1509,6 +1514,20 @@ dummy
|
|||
assert_locations(node.children[-1].children[1].children[0].locations, [[1, 11, 1, 17], [1, 13, 1, 15], nil, nil])
|
||||
end
|
||||
|
||||
def test_in_locations
|
||||
node = ast_parse("case 1; in 2 then 3; end")
|
||||
assert_locations(node.children[-1].children[1].locations, [[1, 8, 1, 20], [1, 8, 1, 10], [1, 13, 1, 17], nil])
|
||||
|
||||
node = ast_parse("1 => a")
|
||||
assert_locations(node.children[-1].children[1].locations, [[1, 5, 1, 6], nil, nil, [1, 2, 1, 4]])
|
||||
|
||||
node = ast_parse("1 in a")
|
||||
assert_locations(node.children[-1].children[1].locations, [[1, 5, 1, 6], [1, 2, 1, 4], nil, nil])
|
||||
|
||||
node = ast_parse("case 1; in 2; 3; end")
|
||||
assert_locations(node.children[-1].children[1].locations, [[1, 8, 1, 16], [1, 8, 1, 10], [1, 12, 1, 13], nil])
|
||||
end
|
||||
|
||||
def test_next_locations
|
||||
node = ast_parse("loop { next 1 }")
|
||||
assert_locations(node.children[-1].children[-1].children[-1].locations, [[1, 7, 1, 13], [1, 7, 1, 11]])
|
||||
|
|
|
@ -75,12 +75,9 @@ class TestGc < Test::Unit::TestCase
|
|||
GC.start
|
||||
end
|
||||
|
||||
def test_gc_config_setting_returns_nil_for_missing_keys
|
||||
missing_value = GC.config(no_such_key: true)[:no_such_key]
|
||||
assert_nil(missing_value)
|
||||
ensure
|
||||
GC.config(full_mark: true)
|
||||
GC.start
|
||||
def test_gc_config_setting_returns_config_hash
|
||||
hash = GC.config(no_such_key: true)
|
||||
assert_equal(GC.config, hash)
|
||||
end
|
||||
|
||||
def test_gc_config_disable_major
|
||||
|
|
|
@ -252,3 +252,52 @@ class TestObjectIdRactor < Test::Unit::TestCase
|
|||
end;
|
||||
end
|
||||
end
|
||||
|
||||
class TestObjectIdStruct < TestObjectId
|
||||
EmbeddedStruct = Struct.new(:embedded_field)
|
||||
|
||||
def setup
|
||||
@obj = EmbeddedStruct.new
|
||||
end
|
||||
end
|
||||
|
||||
class TestObjectIdStructGenIvar < TestObjectId
|
||||
GenIvarStruct = Struct.new(:a, :b, :c)
|
||||
|
||||
def setup
|
||||
@obj = GenIvarStruct.new
|
||||
end
|
||||
end
|
||||
|
||||
class TestObjectIdStructNotEmbed < TestObjectId
|
||||
MANY_IVS = 80
|
||||
|
||||
StructNotEmbed = Struct.new(*MANY_IVS.times.map { |i| :"field_#{i}" })
|
||||
|
||||
def setup
|
||||
@obj = StructNotEmbed.new
|
||||
end
|
||||
end
|
||||
|
||||
class TestObjectIdStructTooComplex < TestObjectId
|
||||
StructTooComplex = Struct.new(:a) do
|
||||
def initialize
|
||||
@too_complex_obj_id_test = 1
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
if defined?(RubyVM::Shape::SHAPE_MAX_VARIATIONS)
|
||||
assert_equal 8, RubyVM::Shape::SHAPE_MAX_VARIATIONS
|
||||
end
|
||||
8.times do |i|
|
||||
StructTooComplex.new.instance_variable_set("@TestObjectIdStructTooComplex#{i}", 1)
|
||||
end
|
||||
@obj = StructTooComplex.new
|
||||
@obj.instance_variable_set("@a#{rand(10_000)}", 1)
|
||||
|
||||
if defined?(RubyVM::Shape)
|
||||
assert_predicate(RubyVM::Shape.of(@obj), :too_complex?)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -284,6 +284,21 @@ End
|
|||
end;
|
||||
end
|
||||
|
||||
def test_id2ref_table_build
|
||||
assert_separately([], <<-End)
|
||||
10.times do
|
||||
Object.new.object_id
|
||||
end
|
||||
|
||||
GC.start(immediate_mark: false)
|
||||
|
||||
obj = Object.new
|
||||
EnvUtil.suppress_warning do
|
||||
assert_equal obj, ObjectSpace._id2ref(obj.object_id)
|
||||
end
|
||||
End
|
||||
end
|
||||
|
||||
def test_each_object_singleton_class
|
||||
assert_separately([], <<-End)
|
||||
class C
|
||||
|
|
|
@ -99,6 +99,24 @@ class TestRactor < Test::Unit::TestCase
|
|||
RUBY
|
||||
end
|
||||
|
||||
def test_struct_instance_variables
|
||||
assert_ractor(<<~'RUBY')
|
||||
StructIvar = Struct.new(:member) do
|
||||
def initialize(*)
|
||||
super
|
||||
@ivar = "ivar"
|
||||
end
|
||||
attr_reader :ivar
|
||||
end
|
||||
obj = StructIvar.new("member")
|
||||
obj_copy = Ractor.new { Ractor.receive }.send(obj).value
|
||||
assert_equal obj.ivar, obj_copy.ivar
|
||||
refute_same obj.ivar, obj_copy.ivar
|
||||
assert_equal obj.member, obj_copy.member
|
||||
refute_same obj.member, obj_copy.member
|
||||
RUBY
|
||||
end
|
||||
|
||||
def test_fork_raise_isolation_error
|
||||
assert_ractor(<<~'RUBY')
|
||||
ractor = Ractor.new do
|
||||
|
@ -144,6 +162,45 @@ class TestRactor < Test::Unit::TestCase
|
|||
RUBY
|
||||
end
|
||||
|
||||
# [Bug #21398]
|
||||
def test_port_receive_dnt_with_port_send
|
||||
assert_ractor(<<~'RUBY', timeout: 30)
|
||||
THREADS = 10
|
||||
JOBS_PER_THREAD = 50
|
||||
ARRAY_SIZE = 20_000
|
||||
def ractor_job(job_count, array_size)
|
||||
port = Ractor::Port.new
|
||||
workers = (1..4).map do |i|
|
||||
Ractor.new(port) do |job_port|
|
||||
while job = Ractor.receive
|
||||
result = job.map { |x| x * 2 }.sum
|
||||
job_port.send result
|
||||
end
|
||||
end
|
||||
end
|
||||
jobs = Array.new(job_count) { Array.new(array_size) { rand(1000) } }
|
||||
jobs.each_with_index do |job, i|
|
||||
w_idx = i % 4
|
||||
workers[w_idx].send(job)
|
||||
end
|
||||
results = []
|
||||
jobs.size.times do
|
||||
result = port.receive # dnt receive
|
||||
results << result
|
||||
end
|
||||
results
|
||||
end
|
||||
threads = []
|
||||
# creates 40 ractors (THREADSx4)
|
||||
THREADS.times do
|
||||
threads << Thread.new do
|
||||
ractor_job(JOBS_PER_THREAD, ARRAY_SIZE)
|
||||
end
|
||||
end
|
||||
threads.each(&:join)
|
||||
RUBY
|
||||
end
|
||||
|
||||
def assert_make_shareable(obj)
|
||||
refute Ractor.shareable?(obj), "object was already shareable"
|
||||
Ractor.make_shareable(obj)
|
||||
|
|
|
@ -924,6 +924,18 @@ class TC_Set < Test::Unit::TestCase
|
|||
end
|
||||
end;
|
||||
end
|
||||
|
||||
def test_larger_sets
|
||||
set = Set.new
|
||||
10_000.times do |i|
|
||||
set << i
|
||||
end
|
||||
set = set.dup
|
||||
|
||||
10_000.times do |i|
|
||||
assert_includes set, i
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
class TC_Enumerable < Test::Unit::TestCase
|
||||
|
|
|
@ -2832,16 +2832,32 @@ CODE
|
|||
def test_casecmp
|
||||
assert_equal(0, S("FoO").casecmp("fOO"))
|
||||
assert_equal(1, S("FoO").casecmp("BaR"))
|
||||
assert_equal(-1, S("foo").casecmp("FOOBAR"))
|
||||
assert_equal(-1, S("baR").casecmp("FoO"))
|
||||
assert_equal(1, S("\u3042B").casecmp("\u3042a"))
|
||||
assert_equal(-1, S("foo").casecmp("foo\0"))
|
||||
assert_equal(1, S("FOOBAR").casecmp("foo"))
|
||||
assert_equal(0, S("foo\0bar").casecmp("FOO\0BAR"))
|
||||
|
||||
assert_nil(S("foo").casecmp(:foo))
|
||||
assert_nil(S("foo").casecmp(Object.new))
|
||||
|
||||
assert_nil(S("foo").casecmp(0))
|
||||
assert_nil(S("foo").casecmp(5.00))
|
||||
|
||||
o = Object.new
|
||||
def o.to_str; "fOO"; end
|
||||
assert_equal(0, S("FoO").casecmp(o))
|
||||
|
||||
assert_equal(0, S("#" * 128 + "A" * 256 + "b").casecmp("#" * 128 + "a" * 256 + "B"))
|
||||
assert_equal(0, S("a" * 256 + "B").casecmp("A" * 256 + "b"))
|
||||
|
||||
assert_equal(-1, S("@").casecmp("`"))
|
||||
assert_equal(0, S("hello\u00E9X").casecmp("HELLO\u00E9x"))
|
||||
|
||||
s1 = S("\xff".force_encoding("UTF-8"))
|
||||
s2 = S("\xff".force_encoding("ISO-2022-JP"))
|
||||
assert_nil(s1.casecmp(s2))
|
||||
end
|
||||
|
||||
def test_casecmp?
|
||||
|
@ -2854,9 +2870,16 @@ CODE
|
|||
assert_nil(S("foo").casecmp?(:foo))
|
||||
assert_nil(S("foo").casecmp?(Object.new))
|
||||
|
||||
assert_nil(S("foo").casecmp(0))
|
||||
assert_nil(S("foo").casecmp(5.00))
|
||||
|
||||
o = Object.new
|
||||
def o.to_str; "fOO"; end
|
||||
assert_equal(true, S("FoO").casecmp?(o))
|
||||
|
||||
s1 = S("\xff".force_encoding("UTF-8"))
|
||||
s2 = S("\xff".force_encoding("ISO-2022-JP"))
|
||||
assert_nil(s1.casecmp?(s2))
|
||||
end
|
||||
|
||||
def test_upcase2
|
||||
|
|
|
@ -2320,6 +2320,46 @@ class TestTranscode < Test::Unit::TestCase
|
|||
assert_equal("A\nB\nC", s.encode(usascii, newline: :lf))
|
||||
end
|
||||
|
||||
def test_ractor_lazy_load_encoding
|
||||
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
|
||||
begin;
|
||||
rs = []
|
||||
autoload_encodings = Encoding.list.select { |e| e.inspect.include?("(autoload)") }.freeze
|
||||
7.times do
|
||||
rs << Ractor.new(autoload_encodings) do |encodings|
|
||||
str = "\u0300"
|
||||
encodings.each do |enc|
|
||||
str.encode(enc) rescue Encoding::UndefinedConversionError
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while rs.any?
|
||||
r, _obj = Ractor.select(*rs)
|
||||
rs.delete(r)
|
||||
end
|
||||
assert rs.empty?
|
||||
end;
|
||||
end
|
||||
|
||||
def test_ractor_lazy_load_encoding_random
|
||||
assert_ractor("#{<<~"begin;"}\n#{<<~'end;'}")
|
||||
begin;
|
||||
rs = []
|
||||
100.times do
|
||||
rs << Ractor.new do
|
||||
"\u0300".encode(Encoding.list.sample) rescue Encoding::UndefinedConversionError
|
||||
end
|
||||
end
|
||||
|
||||
while rs.any?
|
||||
r, _obj = Ractor.select(*rs)
|
||||
rs.delete(r)
|
||||
end
|
||||
assert rs.empty?
|
||||
end;
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def assert_conversion_both_ways_utf8(utf8, raw, encoding)
|
||||
|
|
|
@ -9,6 +9,15 @@ require_relative '../lib/jit_support'
|
|||
return unless JITSupport.zjit_supported?
|
||||
|
||||
class TestZJIT < Test::Unit::TestCase
|
||||
def test_enabled
|
||||
assert_runs 'false', <<~RUBY, zjit: false
|
||||
RubyVM::ZJIT.enabled?
|
||||
RUBY
|
||||
assert_runs 'true', <<~RUBY, zjit: true
|
||||
RubyVM::ZJIT.enabled?
|
||||
RUBY
|
||||
end
|
||||
|
||||
def test_call_itself
|
||||
assert_compiles '42', <<~RUBY, call_threshold: 2
|
||||
def test = 42.itself
|
||||
|
@ -52,6 +61,30 @@ class TestZJIT < Test::Unit::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_setglobal
|
||||
assert_compiles '1', %q{
|
||||
def test
|
||||
$a = 1
|
||||
$a
|
||||
end
|
||||
|
||||
test
|
||||
}, insns: [:setglobal]
|
||||
end
|
||||
|
||||
def test_setglobal_with_trace_var_exception
|
||||
assert_compiles '"rescued"', %q{
|
||||
def test
|
||||
$a = 1
|
||||
rescue
|
||||
"rescued"
|
||||
end
|
||||
|
||||
trace_var(:$a) { raise }
|
||||
test
|
||||
}, insns: [:setglobal]
|
||||
end
|
||||
|
||||
def test_setlocal
|
||||
assert_compiles '3', %q{
|
||||
def test(n)
|
||||
|
@ -70,6 +103,15 @@ class TestZJIT < Test::Unit::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_call_a_forwardable_method
|
||||
assert_runs '[]', %q{
|
||||
def test_root = forwardable
|
||||
def forwardable(...) = Array.[](...)
|
||||
test_root
|
||||
test_root
|
||||
}, call_threshold: 2
|
||||
end
|
||||
|
||||
def test_setlocal_on_eval_with_spill
|
||||
assert_compiles '1', %q{
|
||||
@b = binding
|
||||
|
@ -148,6 +190,18 @@ class TestZJIT < Test::Unit::TestCase
|
|||
}, call_threshold: 2
|
||||
end
|
||||
|
||||
def test_send_on_heap_object_in_spilled_arg
|
||||
# This leads to a register spill, so not using `assert_compiles`
|
||||
assert_runs 'Hash', %q{
|
||||
def entry(a1, a2, a3, a4, a5, a6, a7, a8, a9)
|
||||
a9.itself.class
|
||||
end
|
||||
|
||||
entry(1, 2, 3, 4, 5, 6, 7, 8, {}) # profile
|
||||
entry(1, 2, 3, 4, 5, 6, 7, 8, {})
|
||||
}, call_threshold: 2
|
||||
end
|
||||
|
||||
def test_invokebuiltin
|
||||
omit 'Test fails at the moment due to not handling optional parameters'
|
||||
assert_compiles '["."]', %q{
|
||||
|
@ -283,6 +337,14 @@ class TestZJIT < Test::Unit::TestCase
|
|||
}, insns: [:opt_eq], call_threshold: 2
|
||||
end
|
||||
|
||||
def test_opt_eq_with_minus_one
|
||||
assert_compiles '[false, true]', %q{
|
||||
def test(a) = a == -1
|
||||
test(1) # profile opt_eq
|
||||
[test(0), test(-1)]
|
||||
}, insns: [:opt_eq], call_threshold: 2
|
||||
end
|
||||
|
||||
def test_opt_neq_dynamic
|
||||
# TODO(max): Don't split this test; instead, run all tests with and without
|
||||
# profiling.
|
||||
|
@ -879,6 +941,38 @@ class TestZJIT < Test::Unit::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_attr_reader
|
||||
assert_compiles '[4, 4]', %q{
|
||||
class C
|
||||
attr_reader :foo
|
||||
|
||||
def initialize
|
||||
@foo = 4
|
||||
end
|
||||
end
|
||||
|
||||
def test(c) = c.foo
|
||||
c = C.new
|
||||
[test(c), test(c)]
|
||||
}, call_threshold: 2, insns: [:opt_send_without_block]
|
||||
end
|
||||
|
||||
def test_attr_accessor
|
||||
assert_compiles '[4, 4]', %q{
|
||||
class C
|
||||
attr_accessor :foo
|
||||
|
||||
def initialize
|
||||
@foo = 4
|
||||
end
|
||||
end
|
||||
|
||||
def test(c) = c.foo
|
||||
c = C.new
|
||||
[test(c), test(c)]
|
||||
}, call_threshold: 2, insns: [:opt_send_without_block]
|
||||
end
|
||||
|
||||
def test_uncached_getconstant_path
|
||||
assert_compiles RUBY_COPYRIGHT.dump, %q{
|
||||
def test = RUBY_COPYRIGHT
|
||||
|
@ -942,6 +1036,26 @@ class TestZJIT < Test::Unit::TestCase
|
|||
RUBY
|
||||
end
|
||||
|
||||
def test_single_ractor_mode_invalidation
|
||||
# Without invalidating the single-ractor mode, the test would crash
|
||||
assert_compiles '"errored but not crashed"', <<~RUBY, call_threshold: 2, insns: [:opt_getconstant_path]
|
||||
C = Object.new
|
||||
|
||||
def test
|
||||
C
|
||||
rescue Ractor::IsolationError
|
||||
"errored but not crashed"
|
||||
end
|
||||
|
||||
test
|
||||
test
|
||||
|
||||
Ractor.new {
|
||||
test
|
||||
}.value
|
||||
RUBY
|
||||
end
|
||||
|
||||
def test_dupn
|
||||
assert_compiles '[[1], [1, 1], :rhs, [nil, :rhs]]', <<~RUBY, insns: [:dupn]
|
||||
def test(array) = (array[1, 2] ||= :rhs)
|
||||
|
@ -983,6 +1097,26 @@ class TestZJIT < Test::Unit::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_defined_with_defined_values
|
||||
assert_compiles '["constant", "method", "global-variable"]', %q{
|
||||
class Foo; end
|
||||
def bar; end
|
||||
$ruby = 1
|
||||
|
||||
def test = return defined?(Foo), defined?(bar), defined?($ruby)
|
||||
|
||||
test
|
||||
}, insns: [:defined]
|
||||
end
|
||||
|
||||
def test_defined_with_undefined_values
|
||||
assert_compiles '[nil, nil, nil]', %q{
|
||||
def test = return defined?(Foo), defined?(bar), defined?($ruby)
|
||||
|
||||
test
|
||||
}, insns: [:defined]
|
||||
end
|
||||
|
||||
def test_defined_yield
|
||||
assert_compiles "nil", "defined?(yield)"
|
||||
assert_compiles '[nil, nil, "yield"]', %q{
|
||||
|
@ -1372,6 +1506,46 @@ class TestZJIT < Test::Unit::TestCase
|
|||
}, call_threshold: 2, insns: [:opt_nil_p]
|
||||
end
|
||||
|
||||
def test_basic_object_guard_works_with_immediate
|
||||
assert_compiles 'NilClass', %q{
|
||||
class Foo; end
|
||||
|
||||
def test(val) = val.class
|
||||
|
||||
test(Foo.new)
|
||||
test(Foo.new)
|
||||
test(nil)
|
||||
}, call_threshold: 2
|
||||
end
|
||||
|
||||
def test_basic_object_guard_works_with_false
|
||||
assert_compiles 'FalseClass', %q{
|
||||
class Foo; end
|
||||
|
||||
def test(val) = val.class
|
||||
|
||||
test(Foo.new)
|
||||
test(Foo.new)
|
||||
test(false)
|
||||
}, call_threshold: 2
|
||||
end
|
||||
|
||||
def test_string_concat
|
||||
assert_compiles '"123"', %q{
|
||||
def test = "#{1}#{2}#{3}"
|
||||
|
||||
test
|
||||
}, insns: [:concatstrings]
|
||||
end
|
||||
|
||||
def test_string_concat_empty
|
||||
assert_compiles '""', %q{
|
||||
def test = "#{}"
|
||||
|
||||
test
|
||||
}, insns: [:concatstrings]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Assert that every method call in `test_script` can be compiled by ZJIT
|
||||
|
@ -1422,14 +1596,23 @@ class TestZJIT < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
# Run a Ruby process with ZJIT options and a pipe for writing test results
|
||||
def eval_with_jit(script, call_threshold: 1, num_profiles: 1, stats: false, debug: true, timeout: 1000, pipe_fd:)
|
||||
args = [
|
||||
"--disable-gems",
|
||||
"--zjit-call-threshold=#{call_threshold}",
|
||||
"--zjit-num-profiles=#{num_profiles}",
|
||||
]
|
||||
args << "--zjit-stats" if stats
|
||||
args << "--zjit-debug" if debug
|
||||
def eval_with_jit(
|
||||
script,
|
||||
call_threshold: 1,
|
||||
num_profiles: 1,
|
||||
zjit: true,
|
||||
stats: false,
|
||||
debug: true,
|
||||
timeout: 1000,
|
||||
pipe_fd:
|
||||
)
|
||||
args = ["--disable-gems"]
|
||||
if zjit
|
||||
args << "--zjit-call-threshold=#{call_threshold}"
|
||||
args << "--zjit-num-profiles=#{num_profiles}"
|
||||
args << "--zjit-stats" if stats
|
||||
args << "--zjit-debug" if debug
|
||||
end
|
||||
args << "-e" << script_shell_encode(script)
|
||||
pipe_r, pipe_w = IO.pipe
|
||||
# Separate thread so we don't deadlock when
|
||||
|
|
|
@ -5,13 +5,6 @@ require "rubygems"
|
|||
require "shellwords"
|
||||
|
||||
class TestGemConfig < Gem::TestCase
|
||||
def test_datadir
|
||||
util_make_gems
|
||||
spec = Gem::Specification.find_by_name("a")
|
||||
spec.activate
|
||||
assert_equal "#{spec.full_gem_path}/data/a", spec.datadir
|
||||
end
|
||||
|
||||
def test_good_rake_path_is_escaped
|
||||
path = Gem::TestCase.class_variable_get(:@@good_rake)
|
||||
ruby, rake = path.shellsplit
|
||||
|
|
|
@ -527,35 +527,6 @@ class TestGem < Gem::TestCase
|
|||
assert_equal expected, Gem.configuration
|
||||
end
|
||||
|
||||
def test_self_datadir
|
||||
foo = nil
|
||||
|
||||
Dir.chdir @tempdir do
|
||||
FileUtils.mkdir_p "data"
|
||||
File.open File.join("data", "foo.txt"), "w" do |fp|
|
||||
fp.puts "blah"
|
||||
end
|
||||
|
||||
foo = util_spec "foo" do |s|
|
||||
s.files = %w[data/foo.txt]
|
||||
end
|
||||
|
||||
install_gem foo
|
||||
end
|
||||
|
||||
gem "foo"
|
||||
|
||||
expected = File.join @gemhome, "gems", foo.full_name, "data", "foo"
|
||||
|
||||
assert_equal expected, Gem::Specification.find_by_name("foo").datadir
|
||||
end
|
||||
|
||||
def test_self_datadir_nonexistent_package
|
||||
assert_raise(Gem::MissingSpecError) do
|
||||
Gem::Specification.find_by_name("xyzzy").datadir
|
||||
end
|
||||
end
|
||||
|
||||
def test_self_default_exec_format
|
||||
ruby_install_name "ruby" do
|
||||
assert_equal "%s", Gem.default_exec_format
|
||||
|
|
|
@ -8,6 +8,100 @@ require "rubygems/package"
|
|||
class TestGemRemoteFetcherS3 < Gem::TestCase
|
||||
include Gem::DefaultUserInteraction
|
||||
|
||||
class FakeGemRequest < Gem::Request
|
||||
attr_reader :last_request, :uri
|
||||
|
||||
# Override perform_request to stub things
|
||||
def perform_request(request)
|
||||
@last_request = request
|
||||
@response
|
||||
end
|
||||
|
||||
def set_response(response)
|
||||
@response = response
|
||||
end
|
||||
end
|
||||
|
||||
class FakeS3URISigner < Gem::S3URISigner
|
||||
class << self
|
||||
attr_accessor :return_token, :instance_profile
|
||||
end
|
||||
|
||||
# Convenience method to output the recent aws iam queries made in tests
|
||||
# this outputs the verb, path, and any non-generic headers
|
||||
def recent_aws_query_logs
|
||||
sreqs = @aws_iam_calls.map do |c|
|
||||
r = c.last_request
|
||||
s = +"#{r.method} #{c.uri}\n"
|
||||
r.each_header do |key, v|
|
||||
# Only include headers that start with x-
|
||||
next unless key.start_with?("x-")
|
||||
s << " #{key}=#{v}\n"
|
||||
end
|
||||
s
|
||||
end
|
||||
|
||||
sreqs.join("")
|
||||
end
|
||||
|
||||
def initialize(uri, method)
|
||||
@aws_iam_calls = []
|
||||
super
|
||||
end
|
||||
|
||||
def ec2_iam_request(uri, verb)
|
||||
fake_s3_request = FakeGemRequest.new(uri, verb, nil, nil)
|
||||
@aws_iam_calls << fake_s3_request
|
||||
|
||||
case uri.to_s
|
||||
when "http://169.254.169.254/latest/api/token"
|
||||
if FakeS3URISigner.return_token.nil?
|
||||
res = Gem::Net::HTTPUnauthorized.new nil, 401, nil
|
||||
def res.body = "you got a 401! panic!"
|
||||
else
|
||||
res = Gem::Net::HTTPOK.new nil, 200, nil
|
||||
def res.body = FakeS3URISigner.return_token
|
||||
end
|
||||
when "http://169.254.169.254/latest/meta-data/iam/info"
|
||||
res = Gem::Net::HTTPOK.new nil, 200, nil
|
||||
def res.body
|
||||
<<~JSON
|
||||
{
|
||||
"Code": "Success",
|
||||
"LastUpdated": "2023-05-27:05:05",
|
||||
"InstanceProfileArn": "arn:aws:iam::somesecretid:instance-profile/TestRole",
|
||||
"InstanceProfileId": "SOMEPROFILEID"
|
||||
}
|
||||
JSON
|
||||
end
|
||||
|
||||
when "http://169.254.169.254/latest/meta-data/iam/security-credentials/TestRole"
|
||||
res = Gem::Net::HTTPOK.new nil, 200, nil
|
||||
def res.body = FakeS3URISigner.instance_profile
|
||||
else
|
||||
raise "Unexpected request to #{uri}"
|
||||
end
|
||||
|
||||
fake_s3_request.set_response(res)
|
||||
fake_s3_request
|
||||
end
|
||||
end
|
||||
|
||||
class FakeGemFetcher < Gem::RemoteFetcher
|
||||
attr_reader :fetched_uri, :last_s3_uri_signer
|
||||
|
||||
def request(uri, request_class, last_modified = nil)
|
||||
@fetched_uri = uri
|
||||
res = Gem::Net::HTTPOK.new nil, 200, nil
|
||||
def res.body = "success"
|
||||
res
|
||||
end
|
||||
|
||||
def s3_uri_signer(uri, method)
|
||||
@last_s3_uri_signer = FakeS3URISigner.new(uri, method)
|
||||
end
|
||||
end
|
||||
|
||||
def setup
|
||||
super
|
||||
|
||||
|
@ -18,43 +112,61 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
@a1.loaded_from = File.join(@gemhome, "specifications", @a1.full_name)
|
||||
end
|
||||
|
||||
def assert_fetch_s3(url, signature, token=nil, region="us-east-1", instance_profile_json=nil, method="GET")
|
||||
fetcher = Gem::RemoteFetcher.new nil
|
||||
@fetcher = fetcher
|
||||
$fetched_uri = nil
|
||||
$instance_profile = instance_profile_json
|
||||
def assert_fetched_s3_with_imds_v2(expected_token)
|
||||
# Three API requests:
|
||||
# 1. Get the token
|
||||
# 2. Lookup profile details
|
||||
# 3. Query the credentials
|
||||
expected = <<~TEXT
|
||||
PUT http://169.254.169.254/latest/api/token
|
||||
x-aws-ec2-metadata-token-ttl-seconds=60
|
||||
GET http://169.254.169.254/latest/meta-data/iam/info
|
||||
x-aws-ec2-metadata-token=#{expected_token}
|
||||
GET http://169.254.169.254/latest/meta-data/iam/security-credentials/TestRole
|
||||
x-aws-ec2-metadata-token=#{expected_token}
|
||||
TEXT
|
||||
recent_aws_query_logs = @fetcher.last_s3_uri_signer.recent_aws_query_logs
|
||||
assert_equal(expected.strip, recent_aws_query_logs.strip)
|
||||
end
|
||||
|
||||
def fetcher.request(uri, request_class, last_modified = nil)
|
||||
$fetched_uri = uri
|
||||
res = Gem::Net::HTTPOK.new nil, 200, nil
|
||||
def res.body
|
||||
"success"
|
||||
end
|
||||
res
|
||||
end
|
||||
def assert_fetched_s3_with_imds_v1
|
||||
# Three API requests:
|
||||
# 1. Get the token (which fails)
|
||||
# 2. Lookup profile details without token
|
||||
# 3. Query the credentials without token
|
||||
expected = <<~TEXT
|
||||
PUT http://169.254.169.254/latest/api/token
|
||||
x-aws-ec2-metadata-token-ttl-seconds=60
|
||||
GET http://169.254.169.254/latest/meta-data/iam/info
|
||||
GET http://169.254.169.254/latest/meta-data/iam/security-credentials/TestRole
|
||||
TEXT
|
||||
recent_aws_query_logs = @fetcher.last_s3_uri_signer.recent_aws_query_logs
|
||||
assert_equal(expected.strip, recent_aws_query_logs.strip)
|
||||
end
|
||||
|
||||
def fetcher.s3_uri_signer(uri, method)
|
||||
require "json"
|
||||
s3_uri_signer = Gem::S3URISigner.new(uri, method)
|
||||
def s3_uri_signer.ec2_metadata_credentials_json
|
||||
JSON.parse($instance_profile)
|
||||
end
|
||||
# Running sign operation to make sure uri.query is not mutated
|
||||
s3_uri_signer.sign
|
||||
raise "URI query is not empty: #{uri.query}" unless uri.query.nil?
|
||||
s3_uri_signer
|
||||
end
|
||||
def with_imds_v2_failure
|
||||
FakeS3URISigner.should_fail = true
|
||||
yield(fetcher)
|
||||
ensure
|
||||
FakeS3URISigner.should_fail = false
|
||||
end
|
||||
|
||||
res = fetcher.fetch_s3 Gem::URI.parse(url), nil, (method == "HEAD")
|
||||
def assert_fetch_s3(url:, signature:, token: nil, region: "us-east-1", instance_profile_json: nil, fetcher: nil, method: "GET")
|
||||
FakeS3URISigner.instance_profile = instance_profile_json
|
||||
FakeS3URISigner.return_token = token
|
||||
|
||||
assert_equal "https://my-bucket.s3.#{region}.amazonaws.com/gems/specs.4.8.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=testuser%2F20190624%2F#{region}%2Fs3%2Faws4_request&X-Amz-Date=20190624T051941Z&X-Amz-Expires=86400#{token ? "&X-Amz-Security-Token=" + token : ""}&X-Amz-SignedHeaders=host&X-Amz-Signature=#{signature}", $fetched_uri.to_s
|
||||
@fetcher = fetcher || FakeGemFetcher.new(nil)
|
||||
res = @fetcher.fetch_s3 Gem::URI.parse(url), nil, (method == "HEAD")
|
||||
|
||||
assert_equal "https://my-bucket.s3.#{region}.amazonaws.com/gems/specs.4.8.gz?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=testuser%2F20190624%2F#{region}%2Fs3%2Faws4_request&X-Amz-Date=20190624T051941Z&X-Amz-Expires=86400#{token ? "&X-Amz-Security-Token=" + token : ""}&X-Amz-SignedHeaders=host&X-Amz-Signature=#{signature}", @fetcher.fetched_uri.to_s
|
||||
if method == "HEAD"
|
||||
assert_equal 200, res.code
|
||||
else
|
||||
assert_equal "success", res
|
||||
end
|
||||
ensure
|
||||
$fetched_uri = nil
|
||||
FakeS3URISigner.instance_profile = nil
|
||||
FakeS3URISigner.return_token = nil
|
||||
end
|
||||
|
||||
def test_fetch_s3_config_creds
|
||||
|
@ -63,7 +175,10 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
}
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c"
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c",
|
||||
)
|
||||
end
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
|
@ -79,7 +194,15 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
region = "us-east-1"
|
||||
instance_profile_json = nil
|
||||
method = "HEAD"
|
||||
assert_fetch_s3 url, "a3c6cf9a2db62e85f4e57f8fc8ac8b5ff5c1fdd4aeef55935d05e05174d9c885", token, region, instance_profile_json, method
|
||||
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "a3c6cf9a2db62e85f4e57f8fc8ac8b5ff5c1fdd4aeef55935d05e05174d9c885",
|
||||
token: token,
|
||||
region: region,
|
||||
instance_profile_json: instance_profile_json,
|
||||
method: method
|
||||
)
|
||||
end
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
|
@ -91,7 +214,11 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
}
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "ef07487bfd8e3ca594f8fc29775b70c0a0636f51318f95d4f12b2e6e1fd8c716", nil, "us-west-2"
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "ef07487bfd8e3ca594f8fc29775b70c0a0636f51318f95d4f12b2e6e1fd8c716",
|
||||
region: "us-west-2"
|
||||
)
|
||||
end
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
|
@ -103,7 +230,11 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
}
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "e709338735f9077edf8f6b94b247171c266a9605975e08e4a519a123c3322625", "testtoken"
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "e709338735f9077edf8f6b94b247171c266a9605975e08e4a519a123c3322625",
|
||||
token: "testtoken"
|
||||
)
|
||||
end
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
|
@ -118,7 +249,10 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
}
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c"
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c"
|
||||
)
|
||||
end
|
||||
ensure
|
||||
ENV.each_key {|key| ENV.delete(key) if key.start_with?("AWS") }
|
||||
|
@ -134,7 +268,12 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
}
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "ef07487bfd8e3ca594f8fc29775b70c0a0636f51318f95d4f12b2e6e1fd8c716", nil, "us-west-2"
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "ef07487bfd8e3ca594f8fc29775b70c0a0636f51318f95d4f12b2e6e1fd8c716",
|
||||
token: nil,
|
||||
region: "us-west-2"
|
||||
)
|
||||
end
|
||||
ensure
|
||||
ENV.each_key {|key| ENV.delete(key) if key.start_with?("AWS") }
|
||||
|
@ -150,7 +289,11 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
}
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "e709338735f9077edf8f6b94b247171c266a9605975e08e4a519a123c3322625", "testtoken"
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "e709338735f9077edf8f6b94b247171c266a9605975e08e4a519a123c3322625",
|
||||
token: "testtoken"
|
||||
)
|
||||
end
|
||||
ensure
|
||||
ENV.each_key {|key| ENV.delete(key) if key.start_with?("AWS") }
|
||||
|
@ -160,7 +303,10 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
def test_fetch_s3_url_creds
|
||||
url = "s3://testuser:testpass@my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c"
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c"
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -171,8 +317,14 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c", nil, "us-east-1",
|
||||
'{"AccessKeyId": "testuser", "SecretAccessKey": "testpass"}'
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "da82e098bdaed0d3087047670efc98eaadc20559a473b5eac8d70190d2a9e8fd",
|
||||
region: "us-east-1",
|
||||
token: "mysecrettoken",
|
||||
instance_profile_json: '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass", "Token": "mysecrettoken"}'
|
||||
)
|
||||
assert_fetched_s3_with_imds_v2("mysecrettoken")
|
||||
end
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
|
@ -185,8 +337,14 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "ef07487bfd8e3ca594f8fc29775b70c0a0636f51318f95d4f12b2e6e1fd8c716", nil, "us-west-2",
|
||||
'{"AccessKeyId": "testuser", "SecretAccessKey": "testpass"}'
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "532960594dbfe31d1bbfc0e8e7a666c3cbdd8b00a143774da51b7f920704afd2",
|
||||
region: "us-west-2",
|
||||
token: "mysecrettoken",
|
||||
instance_profile_json: '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass", "Token": "mysecrettoken"}'
|
||||
)
|
||||
assert_fetched_s3_with_imds_v2("mysecrettoken")
|
||||
end
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
|
@ -199,14 +357,40 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3 url, "e709338735f9077edf8f6b94b247171c266a9605975e08e4a519a123c3322625", "testtoken", "us-east-1",
|
||||
'{"AccessKeyId": "testuser", "SecretAccessKey": "testpass", "Token": "testtoken"}'
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "e709338735f9077edf8f6b94b247171c266a9605975e08e4a519a123c3322625",
|
||||
token: "testtoken",
|
||||
region: "us-east-1",
|
||||
instance_profile_json: '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass", "Token": "testtoken"}'
|
||||
)
|
||||
assert_fetched_s3_with_imds_v2("testtoken")
|
||||
end
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
end
|
||||
|
||||
def refute_fetch_s3(url, expected_message)
|
||||
def test_fetch_s3_instance_profile_creds_with_fallback
|
||||
Gem.configuration[:s3_source] = {
|
||||
"my-bucket" => { provider: "instance_profile" },
|
||||
}
|
||||
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
Time.stub :now, Time.at(1_561_353_581) do
|
||||
assert_fetch_s3(
|
||||
url: url,
|
||||
signature: "b5cb80c1301f7b1c50c4af54f1f6c034f80b56d32f000a855f0a903dc5a8413c",
|
||||
token: nil,
|
||||
region: "us-east-1",
|
||||
instance_profile_json: '{"AccessKeyId": "testuser", "SecretAccessKey": "testpass"}'
|
||||
)
|
||||
assert_fetched_s3_with_imds_v1
|
||||
end
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
end
|
||||
|
||||
def refute_fetch_s3(url:, expected_message:)
|
||||
fetcher = Gem::RemoteFetcher.new nil
|
||||
@fetcher = fetcher
|
||||
|
||||
|
@ -219,7 +403,7 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
|
||||
def test_fetch_s3_no_source_key
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
refute_fetch_s3 url, "no s3_source key exists in .gemrc"
|
||||
refute_fetch_s3(url: url, expected_message: "no s3_source key exists in .gemrc")
|
||||
end
|
||||
|
||||
def test_fetch_s3_no_host
|
||||
|
@ -228,7 +412,7 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
}
|
||||
|
||||
url = "s3://other-bucket/gems/specs.4.8.gz"
|
||||
refute_fetch_s3 url, "no key for host other-bucket in s3_source in .gemrc"
|
||||
refute_fetch_s3(url: url, expected_message: "no key for host other-bucket in s3_source in .gemrc")
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
end
|
||||
|
@ -237,7 +421,7 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
Gem.configuration[:s3_source] = { "my-bucket" => { secret: "testpass" } }
|
||||
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
refute_fetch_s3 url, "s3_source for my-bucket missing id or secret"
|
||||
refute_fetch_s3(url: url, expected_message: "s3_source for my-bucket missing id or secret")
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
end
|
||||
|
@ -246,7 +430,7 @@ class TestGemRemoteFetcherS3 < Gem::TestCase
|
|||
Gem.configuration[:s3_source] = { "my-bucket" => { id: "testuser" } }
|
||||
|
||||
url = "s3://my-bucket/gems/specs.4.8.gz"
|
||||
refute_fetch_s3 url, "s3_source for my-bucket missing id or secret"
|
||||
refute_fetch_s3(url: url, expected_message: "s3_source for my-bucket missing id or secret")
|
||||
ensure
|
||||
Gem.configuration[:s3_source] = nil
|
||||
end
|
||||
|
|
|
@ -70,6 +70,31 @@ class TestStringIO < Test::Unit::TestCase
|
|||
assert_nil io.getc
|
||||
end
|
||||
|
||||
def test_eof_null
|
||||
io = StringIO.new(nil)
|
||||
assert_predicate io, :eof?
|
||||
end
|
||||
|
||||
def test_pread_null
|
||||
io = StringIO.new(nil)
|
||||
assert_raise(EOFError) { io.pread(1, 0) }
|
||||
end
|
||||
|
||||
def test_read_null
|
||||
io = StringIO.new(nil)
|
||||
assert_equal "", io.read(0)
|
||||
end
|
||||
|
||||
def test_seek_null
|
||||
io = StringIO.new(nil)
|
||||
assert_equal(0, io.seek(0, IO::SEEK_SET))
|
||||
assert_equal(0, io.pos)
|
||||
assert_equal(0, io.seek(0, IO::SEEK_CUR))
|
||||
assert_equal(0, io.pos)
|
||||
assert_equal(0, io.seek(0, IO::SEEK_END)) # This should not segfault
|
||||
assert_equal(0, io.pos)
|
||||
end
|
||||
|
||||
def test_truncate
|
||||
io = StringIO.new("")
|
||||
io.puts "abc"
|
||||
|
|
|
@ -1351,6 +1351,7 @@ rb_ractor_sched_wait(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_fun
|
|||
}
|
||||
|
||||
thread_sched_lock(sched, th);
|
||||
rb_ractor_unlock_self(cr);
|
||||
{
|
||||
// setup sleep
|
||||
bool can_direct_transfer = !th_has_dedicated_nt(th);
|
||||
|
@ -1358,16 +1359,12 @@ rb_ractor_sched_wait(rb_execution_context_t *ec, rb_ractor_t *cr, rb_unblock_fun
|
|||
th->status = THREAD_STOPPED_FOREVER;
|
||||
RB_INTERNAL_THREAD_HOOK(RUBY_INTERNAL_THREAD_EVENT_SUSPENDED, th);
|
||||
thread_sched_wakeup_next_thread(sched, th, can_direct_transfer);
|
||||
|
||||
rb_ractor_unlock_self(cr);
|
||||
{
|
||||
// sleep
|
||||
thread_sched_wait_running_turn(sched, th, can_direct_transfer);
|
||||
th->status = THREAD_RUNNABLE;
|
||||
}
|
||||
rb_ractor_lock_self(cr);
|
||||
// sleep
|
||||
thread_sched_wait_running_turn(sched, th, can_direct_transfer);
|
||||
th->status = THREAD_RUNNABLE;
|
||||
}
|
||||
thread_sched_unlock(sched, th);
|
||||
rb_ractor_lock_self(cr);
|
||||
|
||||
ubf_clear(th);
|
||||
|
||||
|
|
32
time.c
32
time.c
|
@ -1888,39 +1888,25 @@ force_make_tm(VALUE time, struct time_object *tobj)
|
|||
}
|
||||
|
||||
static void
|
||||
time_mark(void *ptr)
|
||||
time_mark_and_move(void *ptr)
|
||||
{
|
||||
struct time_object *tobj = ptr;
|
||||
if (!FIXWV_P(tobj->timew)) {
|
||||
rb_gc_mark_movable(w2v(tobj->timew));
|
||||
if (!WIDEVALUE_IS_WIDER || !FIXWV_P(tobj->timew)) {
|
||||
rb_gc_mark_and_move((VALUE *)&WIDEVAL_GET(tobj->timew));
|
||||
}
|
||||
rb_gc_mark_movable(tobj->vtm.year);
|
||||
rb_gc_mark_movable(tobj->vtm.subsecx);
|
||||
rb_gc_mark_movable(tobj->vtm.utc_offset);
|
||||
rb_gc_mark_movable(tobj->vtm.zone);
|
||||
}
|
||||
|
||||
static void
|
||||
time_compact(void *ptr)
|
||||
{
|
||||
struct time_object *tobj = ptr;
|
||||
if (!FIXWV_P(tobj->timew)) {
|
||||
WIDEVAL_GET(tobj->timew) = WIDEVAL_WRAP(rb_gc_location(w2v(tobj->timew)));
|
||||
}
|
||||
|
||||
tobj->vtm.year = rb_gc_location(tobj->vtm.year);
|
||||
tobj->vtm.subsecx = rb_gc_location(tobj->vtm.subsecx);
|
||||
tobj->vtm.utc_offset = rb_gc_location(tobj->vtm.utc_offset);
|
||||
tobj->vtm.zone = rb_gc_location(tobj->vtm.zone);
|
||||
rb_gc_mark_and_move(&tobj->vtm.year);
|
||||
rb_gc_mark_and_move(&tobj->vtm.subsecx);
|
||||
rb_gc_mark_and_move(&tobj->vtm.utc_offset);
|
||||
rb_gc_mark_and_move(&tobj->vtm.zone);
|
||||
}
|
||||
|
||||
static const rb_data_type_t time_data_type = {
|
||||
.wrap_struct_name = "time",
|
||||
.function = {
|
||||
.dmark = time_mark,
|
||||
.dmark = time_mark_and_move,
|
||||
.dfree = RUBY_TYPED_DEFAULT_FREE,
|
||||
.dsize = NULL,
|
||||
.dcompact = time_compact,
|
||||
.dcompact = time_mark_and_move,
|
||||
},
|
||||
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE,
|
||||
};
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#!ruby -an
|
||||
#!ruby -alnF\s+|#.*
|
||||
BEGIN {
|
||||
require 'fileutils'
|
||||
require_relative 'lib/colorize'
|
||||
|
@ -21,7 +21,6 @@ BEGIN {
|
|||
n, v, u, r = $F
|
||||
|
||||
next unless n
|
||||
next if n =~ /^#/
|
||||
next if bundled_gems&.all? {|pat| !File.fnmatch?(pat, n)}
|
||||
|
||||
unless File.exist?("#{n}/.git")
|
||||
|
|
|
@ -690,17 +690,15 @@ eom
|
|||
assert_warning(*args) {$VERBOSE = false; yield}
|
||||
end
|
||||
|
||||
def assert_deprecated_warning(mesg = /deprecated/)
|
||||
def assert_deprecated_warning(mesg = /deprecated/, &block)
|
||||
assert_warning(mesg) do
|
||||
Warning[:deprecated] = true if Warning.respond_to?(:[]=)
|
||||
yield
|
||||
EnvUtil.deprecation_warning(&block)
|
||||
end
|
||||
end
|
||||
|
||||
def assert_deprecated_warn(mesg = /deprecated/)
|
||||
def assert_deprecated_warn(mesg = /deprecated/, &block)
|
||||
assert_warn(mesg) do
|
||||
Warning[:deprecated] = true if Warning.respond_to?(:[]=)
|
||||
yield
|
||||
EnvUtil.deprecation_warning(&block)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -297,6 +297,21 @@ module EnvUtil
|
|||
end
|
||||
module_function :verbose_warning
|
||||
|
||||
if defined?(Warning.[]=)
|
||||
def deprecation_warning
|
||||
previous_deprecated = Warning[:deprecated]
|
||||
Warning[:deprecated] = true
|
||||
yield
|
||||
ensure
|
||||
Warning[:deprecated] = previous_deprecated
|
||||
end
|
||||
else
|
||||
def deprecation_warning
|
||||
yield
|
||||
end
|
||||
end
|
||||
module_function :deprecation_warning
|
||||
|
||||
def default_warning
|
||||
$VERBOSE = false
|
||||
yield
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue