mirror of
https://github.com/ruby/ruby.git
synced 2025-08-15 13:39:04 +02:00
Merge branch 'master' into refinement-symbol-proc
This commit is contained in:
commit
0ce874b329
1109 changed files with 30618 additions and 20653 deletions
|
@ -22,6 +22,7 @@ marshal.rb
|
|||
numeric.rb
|
||||
nilclass.rb
|
||||
pack.rb
|
||||
pathname_builtin.rb
|
||||
ractor.rb
|
||||
string.rb
|
||||
symbol.rb
|
||||
|
|
4
.gdbinit
4
.gdbinit
|
@ -185,8 +185,8 @@ define rp
|
|||
print (struct RBasic *)($arg0)
|
||||
else
|
||||
if ($flags & RUBY_T_MASK) == RUBY_T_DATA
|
||||
if ((struct RTypedData *)($arg0))->typed_flag == 1
|
||||
printf "%sT_DATA%s(%s): ", $color_type, $color_end, ((struct RTypedData *)($arg0))->type->wrap_struct_name
|
||||
if ((struct RTypedData *)($arg0))->type & 1
|
||||
printf "%sT_DATA%s(%s): ", $color_type, $color_end, ((const rb_data_type_t *)(((struct RTypedData *)($arg0))->type & ~1))->wrap_struct_name
|
||||
print (struct RTypedData *)($arg0)
|
||||
else
|
||||
printf "%sT_DATA%s: ", $color_type, $color_end
|
||||
|
|
|
@ -34,3 +34,5 @@ d2c5867357ed88eccc28c2b3bd4a46e206e7ff85
|
|||
# Miss-and-revived commits
|
||||
a0f7de814ae5c299d6ce99bed5fb308a05d50ba0
|
||||
d4e24021d39e1f80f0055b55d91f8d5f22e15084
|
||||
7a56c316418980b8a41fcbdc94067b2bda2ad112
|
||||
e90282be7ba1bc8e3119f6e1a2c80356ceb3f80a
|
||||
|
|
75
.github/actions/compilers/entrypoint.sh
vendored
75
.github/actions/compilers/entrypoint.sh
vendored
|
@ -74,81 +74,6 @@ btests=''
|
|||
tests=''
|
||||
spec_opts=''
|
||||
|
||||
# Launchable
|
||||
setup_launchable() {
|
||||
pushd ${srcdir}
|
||||
# To prevent a slowdown in CI, disable request retries when the Launchable server is unstable.
|
||||
export LAUNCHABLE_SKIP_TIMEOUT_RETRY=1
|
||||
# Launchable creates .launchable file in the current directory, but cannot a file to ${srcdir} directory.
|
||||
# As a workaround, we set LAUNCHABLE_SESSION_DIR to ${builddir}.
|
||||
export LAUNCHABLE_SESSION_DIR=${builddir}
|
||||
local github_ref="${GITHUB_REF//\//_}"
|
||||
local build_name="${github_ref}"_"${GITHUB_PR_HEAD_SHA}"
|
||||
btest_report_path='launchable_bootstraptest.json'
|
||||
test_report_path='launchable_test_all.json'
|
||||
test_spec_report_path='launchable_test_spec_report'
|
||||
test_all_session_file='launchable_test_all_session.txt'
|
||||
btest_session_file='launchable_btest_session.txt'
|
||||
test_spec_session_file='launchable_test_spec_session.txt'
|
||||
btests+=--launchable-test-reports="${btest_report_path}"
|
||||
echo "::group::Setup Launchable"
|
||||
launchable record build --name "${build_name}" || true
|
||||
launchable record session \
|
||||
--build "${build_name}" \
|
||||
--flavor test_task=test \
|
||||
--flavor workflow=Compilations \
|
||||
--flavor with-gcc="${INPUT_WITH_GCC}" \
|
||||
--flavor CFLAGS="${INPUT_CFLAGS}" \
|
||||
--flavor CXXFLAGS="${INPUT_CXXFLAGS}" \
|
||||
--flavor optflags="${INPUT_OPTFLAGS}" \
|
||||
--flavor cppflags="${INPUT_CPPFLAGS}" \
|
||||
--test-suite btest \
|
||||
> "${builddir}"/${btest_session_file} \
|
||||
|| true
|
||||
if [ "$INPUT_CHECK" = "true" ]; then
|
||||
tests+=--launchable-test-reports="${test_report_path}"
|
||||
launchable record session \
|
||||
--build "${build_name}" \
|
||||
--flavor test_task=test-all \
|
||||
--flavor workflow=Compilations \
|
||||
--flavor with-gcc="${INPUT_WITH_GCC}" \
|
||||
--flavor CFLAGS="${INPUT_CFLAGS}" \
|
||||
--flavor CXXFLAGS="${INPUT_CXXFLAGS}" \
|
||||
--flavor optflags="${INPUT_OPTFLAGS}" \
|
||||
--flavor cppflags="${INPUT_CPPFLAGS}" \
|
||||
--test-suite test-all \
|
||||
> "${builddir}"/${test_all_session_file} \
|
||||
|| true
|
||||
mkdir "${builddir}"/"${test_spec_report_path}"
|
||||
spec_opts+=--launchable-test-reports="${test_spec_report_path}"
|
||||
launchable record session \
|
||||
--build "${build_name}" \
|
||||
--flavor test_task=test-spec \
|
||||
--flavor workflow=Compilations \
|
||||
--flavor with-gcc="${INPUT_WITH_GCC}" \
|
||||
--flavor CFLAGS="${INPUT_CFLAGS}" \
|
||||
--flavor CXXFLAGS="${INPUT_CXXFLAGS}" \
|
||||
--flavor optflags="${INPUT_OPTFLAGS}" \
|
||||
--flavor cppflags="${INPUT_CPPFLAGS}" \
|
||||
--test-suite test-spec \
|
||||
> "${builddir}"/${test_spec_session_file} \
|
||||
|| true
|
||||
fi
|
||||
echo "::endgroup::"
|
||||
trap launchable_record_test EXIT
|
||||
}
|
||||
launchable_record_test() {
|
||||
pushd "${builddir}"
|
||||
grouped launchable record tests --session "$(cat "${btest_session_file}")" raw "${btest_report_path}" || true
|
||||
if [ "$INPUT_CHECK" = "true" ]; then
|
||||
grouped launchable record tests --session "$(cat "${test_all_session_file}")" raw "${test_report_path}" || true
|
||||
grouped launchable record tests --session "$(cat "${test_spec_session_file}")" raw "${test_spec_report_path}"/* || true
|
||||
fi
|
||||
}
|
||||
if [ "$LAUNCHABLE_ENABLED" = "true" ]; then
|
||||
setup_launchable
|
||||
fi
|
||||
|
||||
pushd ${builddir}
|
||||
|
||||
grouped make showflags
|
||||
|
|
206
.github/actions/launchable/setup/action.yml
vendored
206
.github/actions/launchable/setup/action.yml
vendored
|
@ -55,6 +55,17 @@ inputs:
|
|||
description: >-
|
||||
Whether this workflow is executed on YJIT.
|
||||
|
||||
outputs:
|
||||
stdout_report_path:
|
||||
value: ${{ steps.global.outputs.stdout_report_path }}
|
||||
description: >-
|
||||
Report file path for standard output.
|
||||
|
||||
stderr_report_path:
|
||||
value: ${{ steps.global.outputs.stderr_report_path }}
|
||||
description: >-
|
||||
Report file path for standard error.
|
||||
|
||||
runs:
|
||||
using: composite
|
||||
|
||||
|
@ -100,12 +111,11 @@ runs:
|
|||
echo test_all_enabled="${test_all_enabled}" >> $GITHUB_OUTPUT
|
||||
echo btest_enabled="${btest_enabled}" >> $GITHUB_OUTPUT
|
||||
echo test_spec_enabled="${test_spec_enabled}" >> $GITHUB_OUTPUT
|
||||
echo test_all_session_file='launchable_test_all_session.txt' >> $GITHUB_OUTPUT
|
||||
echo btest_session_file='launchable_btest_session.txt' >> $GITHUB_OUTPUT
|
||||
echo test_spec_session_file='launchable_test_spec_session.txt' >> $GITHUB_OUTPUT
|
||||
echo test_all_report_file='launchable_test_all_report.json' >> $GITHUB_OUTPUT
|
||||
echo btest_report_file='launchable_btest_report.json' >> $GITHUB_OUTPUT
|
||||
echo test_spec_report_dir='launchable_test_spec_report' >> $GITHUB_OUTPUT
|
||||
echo stdout_report_path="launchable_stdout.log" >> $GITHUB_OUTPUT
|
||||
echo stderr_report_path="launchable_stderr.log" >> $GITHUB_OUTPUT
|
||||
if: steps.enable-launchable.outputs.enable-launchable
|
||||
|
||||
- name: Set environment variables for Launchable
|
||||
|
@ -123,6 +133,7 @@ runs:
|
|||
echo "LAUNCHABLE_TOKEN=${{ inputs.launchable-token }}" >> $GITHUB_ENV
|
||||
: # To prevent a slowdown in CI, disable request retries when the Launchable server is unstable.
|
||||
echo "LAUNCHABLE_SKIP_TIMEOUT_RETRY=1" >> $GITHUB_ENV
|
||||
echo "LAUNCHABLE_COMMIT_TIMEOUT=1" >> $GITHUB_ENV
|
||||
if: steps.enable-launchable.outputs.enable-launchable
|
||||
|
||||
- name: Set up path
|
||||
|
@ -134,6 +145,7 @@ runs:
|
|||
if: steps.enable-launchable.outputs.enable-launchable && startsWith(inputs.os, 'macos')
|
||||
|
||||
- name: Set up Launchable
|
||||
id: setup-launchable
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.srcdir }}
|
||||
run: |
|
||||
|
@ -156,110 +168,72 @@ runs:
|
|||
btest_test_suite="yjit-${btest_test_suite}"
|
||||
test_spec_test_suite="yjit-${test_spec_test_suite}"
|
||||
fi
|
||||
# launchable_setup target var -- refers ${target} prefixed variables
|
||||
launchable_setup() {
|
||||
local target=$1 session
|
||||
eval [ "\${${target}_enabled}" = "true" ] || return
|
||||
eval local suite=\${${target}_test_suite}
|
||||
session=$(launchable record session \
|
||||
--build "${build_name}" \
|
||||
--observation \
|
||||
--flavor os="${{ inputs.os }}" \
|
||||
--flavor test_task="${{ inputs.test-task }}" \
|
||||
--flavor test_opts="${test_opts}" \
|
||||
--flavor workflow="${{ github.workflow }}" \
|
||||
--test-suite ${suite} \
|
||||
)
|
||||
launchable subset \
|
||||
--get-tests-from-previous-sessions \
|
||||
--non-blocking \
|
||||
--target 90% \
|
||||
--session "${session}" \
|
||||
raw > /dev/null
|
||||
echo "${target}_session=${session}" >> $GITHUB_OUTPUT
|
||||
}
|
||||
|
||||
launchable record build --name "${build_name}"
|
||||
if [ "${test_all_enabled}" = "true" ]; then
|
||||
launchable record session \
|
||||
--build "${build_name}" \
|
||||
--observation \
|
||||
--flavor os="${{ inputs.os }}" \
|
||||
--flavor test_task="${{ inputs.test-task }}" \
|
||||
--flavor test_opts="${test_opts}" \
|
||||
--flavor workflow="${{ github.workflow }}" \
|
||||
--test-suite ${test_all_test_suite} \
|
||||
> "${test_all_session_file}"
|
||||
launchable subset \
|
||||
--get-tests-from-previous-sessions \
|
||||
--non-blocking \
|
||||
--target 90% \
|
||||
--session "$(cat "${test_all_session_file}")" \
|
||||
raw > /dev/null
|
||||
echo "TESTS=${TESTS} --launchable-test-reports=${test_all_report_file}" >> $GITHUB_ENV
|
||||
if launchable_setup test_all; then
|
||||
echo "TESTS=${TESTS:+$TESTS }--launchable-test-reports=${test_all_report_file}" >> $GITHUB_ENV
|
||||
fi
|
||||
if [ "${btest_enabled}" = "true" ]; then
|
||||
launchable record session \
|
||||
--build "${build_name}" \
|
||||
--observation \
|
||||
--flavor os="${{ inputs.os }}" \
|
||||
--flavor test_task="${{ inputs.test-task }}" \
|
||||
--flavor test_opts="${test_opts}" \
|
||||
--flavor workflow="${{ github.workflow }}" \
|
||||
--test-suite ${btest_test_suite} \
|
||||
> "${btest_session_file}"
|
||||
launchable subset \
|
||||
--get-tests-from-previous-sessions \
|
||||
--non-blocking \
|
||||
--target 90% \
|
||||
--session "$(cat "${btest_session_file}")" \
|
||||
raw > /dev/null
|
||||
echo "BTESTS=${BTESTS} --launchable-test-reports=${btest_report_file}" >> $GITHUB_ENV
|
||||
if launchable_setup btest; then
|
||||
echo "BTESTS=${BTESTS:+$BTESTS }--launchable-test-reports=${btest_report_file}" >> $GITHUB_ENV
|
||||
fi
|
||||
if [ "${test_spec_enabled}" = "true" ]; then
|
||||
launchable record session \
|
||||
--build "${build_name}" \
|
||||
--observation \
|
||||
--flavor os="${{ inputs.os }}" \
|
||||
--flavor test_task="${{ inputs.test-task }}" \
|
||||
--flavor test_opts="${test_opts}" \
|
||||
--flavor workflow="${{ github.workflow }}" \
|
||||
--test-suite ${test_spec_test_suite} \
|
||||
> "${test_spec_session_file}"
|
||||
launchable subset \
|
||||
--get-tests-from-previous-sessions \
|
||||
--non-blocking \
|
||||
--target 90% \
|
||||
--session "$(cat "${test_spec_session_file}")" \
|
||||
raw > /dev/null
|
||||
echo "SPECOPTS=${SPECOPTS} --launchable-test-reports=${test_spec_report_dir}" >> $GITHUB_ENV
|
||||
if launchable_setup test_spec; then
|
||||
echo "SPECOPTS=${SPECOPTS:$SPECOPTS }--launchable-test-reports=${test_spec_report_dir}" >> $GITHUB_ENV
|
||||
echo test_spec_enabled=true >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
echo launchable_setup_dir=$(pwd) >> $GITHUB_OUTPUT
|
||||
if: steps.enable-launchable.outputs.enable-launchable
|
||||
env:
|
||||
test_all_enabled: ${{ steps.global.outputs.test_all_enabled }}
|
||||
btest_enabled: ${{ steps.global.outputs.btest_enabled }}
|
||||
test_spec_enabled: ${{ steps.global.outputs.test_spec_enabled }}
|
||||
test_all_session_file: ${{ steps.global.outputs.test_all_session_file }}
|
||||
btest_session_file: ${{ steps.global.outputs.btest_session_file }}
|
||||
test_spec_session_file: ${{ steps.global.outputs.test_spec_session_file }}
|
||||
test_all_report_file: ${{ steps.global.outputs.test_all_report_file }}
|
||||
btest_report_file: ${{ steps.global.outputs.btest_report_file }}
|
||||
test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
|
||||
|
||||
- name: Variables to report Launchable
|
||||
id: variables
|
||||
- name: make test-spec report directory in build directory
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.srcdir }}
|
||||
run: |
|
||||
set -x
|
||||
: # report-path from srcdir
|
||||
if [ "${srcdir}" = "${{ github.workspace }}" ]; then
|
||||
dir=
|
||||
else
|
||||
# srcdir must be equal to or under workspace
|
||||
dir=$(echo ${srcdir:+${srcdir}/} | sed 's:[^/][^/]*/:../:g')
|
||||
fi
|
||||
if [ "${test_all_enabled}" = "true" ]; then
|
||||
test_report_path="${dir}${builddir:+${builddir}/}${test_all_report_file}"
|
||||
echo test_report_path="${test_report_path}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
if [ "${btest_enabled}" = "true" ]; then
|
||||
btest_report_path="${dir}${builddir:+${builddir}/}${btest_report_file}"
|
||||
echo btest_report_path="${btest_report_path}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
if [ "${test_spec_enabled}" = "true" ]; then
|
||||
test_spec_report_path="${dir}${builddir:+${builddir}/}${test_spec_report_dir}"
|
||||
mkdir "${test_spec_report_path}"
|
||||
echo test_spec_report_path="${test_spec_report_path}" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
stdout_report_path="${dir}${builddir:+${builddir}/}launchable_stdout.log"
|
||||
stderr_report_path="${dir}${builddir:+${builddir}/}launchable_stderr.log"
|
||||
echo stdout_report_path="${stdout_report_path}" >> $GITHUB_OUTPUT
|
||||
echo stderr_report_path="${stderr_report_path}" >> $GITHUB_OUTPUT
|
||||
if: steps.enable-launchable.outputs.enable-launchable
|
||||
working-directory: ${{ inputs.builddir }}
|
||||
run: mkdir "${test_spec_report_dir}"
|
||||
if: ${{ steps.setup-launchable.outputs.test_spec_enabled == 'true' }}
|
||||
env:
|
||||
test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
|
||||
|
||||
- name: Clean up test results in Launchable
|
||||
uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0
|
||||
with:
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.builddir }}
|
||||
post: |
|
||||
rm -f "${test_all_report_file}"
|
||||
rm -f "${btest_report_file}"
|
||||
rm -fr "${test_spec_report_dir}"
|
||||
rm -f launchable_stdout.log
|
||||
rm -f launchable_stderr.log
|
||||
if: always() && steps.setup-launchable.outcome == 'success'
|
||||
env:
|
||||
srcdir: ${{ inputs.srcdir }}
|
||||
builddir: ${{ inputs.builddir }}
|
||||
test_all_enabled: ${{ steps.global.outputs.test_all_enabled }}
|
||||
btest_enabled: ${{ steps.global.outputs.btest_enabled }}
|
||||
test_spec_enabled: ${{ steps.global.outputs.test_spec_enabled }}
|
||||
test_all_report_file: ${{ steps.global.outputs.test_all_report_file }}
|
||||
btest_report_file: ${{ steps.global.outputs.btest_report_file }}
|
||||
test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
|
||||
|
@ -268,56 +242,48 @@ runs:
|
|||
uses: gacts/run-and-post-run@674528335da98a7afc80915ff2b4b860a0b3553a # v1.4.0
|
||||
with:
|
||||
shell: bash
|
||||
working-directory: ${{ inputs.srcdir }}
|
||||
working-directory: ${{ inputs.builddir }}
|
||||
post: |
|
||||
if [[ "${test_all_enabled}" = "true" ]]; then \
|
||||
launchable record attachment \
|
||||
--session "$(cat "${test_all_session_file}")" \
|
||||
--session "${test_all_session}" \
|
||||
"${stdout_report_path}" \
|
||||
"${stderr_report_path}"; \
|
||||
launchable record tests \
|
||||
--session "$(cat "${test_all_session_file}")" \
|
||||
raw "${test_report_path}" || true; \
|
||||
--session "${test_all_session}" \
|
||||
raw "${test_all_report_file}" || true; \
|
||||
fi
|
||||
|
||||
if [[ "${btest_enabled}" = "true" ]]; then \
|
||||
launchable record attachment \
|
||||
--session "$(cat "${btest_session_file}")" \
|
||||
--session "${btest_session}" \
|
||||
"${stdout_report_path}" \
|
||||
"${stderr_report_path}"; \
|
||||
launchable record tests \
|
||||
--session "$(cat "${btest_session_file}")" \
|
||||
raw "${btest_report_path}" || true; \
|
||||
--session "${btest_session}" \
|
||||
raw "${btest_report_file}" || true; \
|
||||
fi
|
||||
|
||||
if [[ "${test_spec_enabled}" = "true" ]]; then \
|
||||
launchable record attachment \
|
||||
--session "$(cat "${test_spec_session_file}")" \
|
||||
--session "${test_spec_session}" \
|
||||
"${stdout_report_path}" \
|
||||
"${stderr_report_path}"; \
|
||||
launchable record tests \
|
||||
--session "$(cat "${test_spec_session_file}")" \
|
||||
raw ${test_spec_report_path}/* || true; \
|
||||
--session "${test_spec_session}" \
|
||||
raw ${test_spec_report_dir}/* || true; \
|
||||
fi
|
||||
|
||||
rm -f "${test_all_session_file}"
|
||||
rm -f "${btest_session_file}"
|
||||
rm -f "${test_spec_session_file}"
|
||||
rm -f "${test_report_path}"
|
||||
rm -f "${btest_report_path}"
|
||||
rm -fr "${test_spec_report_path}"
|
||||
rm -f "${stdout_report_path}"
|
||||
rm -f "${stderr_report_path}"
|
||||
if: ${{ always() && steps.enable-launchable.outputs.enable-launchable }}
|
||||
if: ${{ always() && steps.setup-launchable.outcome == 'success' }}
|
||||
env:
|
||||
test_report_path: ${{ steps.variables.outputs.test_report_path }}
|
||||
btest_report_path: ${{ steps.variables.outputs.btest_report_path }}
|
||||
test_spec_report_path: ${{ steps.variables.outputs.test_spec_report_path }}
|
||||
test_all_report_file: ${{ steps.global.outputs.test_all_report_file }}
|
||||
btest_report_file: ${{ steps.global.outputs.btest_report_file }}
|
||||
test_spec_report_dir: ${{ steps.global.outputs.test_spec_report_dir }}
|
||||
test_all_enabled: ${{ steps.global.outputs.test_all_enabled }}
|
||||
btest_enabled: ${{ steps.global.outputs.btest_enabled }}
|
||||
test_spec_enabled: ${{ steps.global.outputs.test_spec_enabled }}
|
||||
test_all_session_file: ${{ steps.global.outputs.test_all_session_file }}
|
||||
btest_session_file: ${{ steps.global.outputs.btest_session_file }}
|
||||
test_spec_session_file: ${{ steps.global.outputs.test_spec_session_file }}
|
||||
stdout_report_path: ${{ steps.variables.outputs.stdout_report_path }}
|
||||
stderr_report_path: ${{ steps.variables.outputs.stderr_report_path }}
|
||||
test_all_session: ${{ steps.setup-launchable.outputs.test_all_session }}
|
||||
btest_session: ${{ steps.setup-launchable.outputs.btest_session }}
|
||||
test_spec_session: ${{ steps.setup-launchable.outputs.test_spec_session }}
|
||||
stdout_report_path: ${{ steps.global.outputs.stdout_report_path }}
|
||||
stderr_report_path: ${{ steps.global.outputs.stderr_report_path }}
|
||||
LAUNCHABLE_SETUP_DIR: ${{ steps.setup-launchable.outputs.launchable_setup_dir }}
|
||||
|
|
4
.github/actions/setup/directories/action.yml
vendored
4
.github/actions/setup/directories/action.yml
vendored
|
@ -76,7 +76,7 @@ runs:
|
|||
shell: bash
|
||||
run: |
|
||||
echo "git=`command -v git`" >> "$GITHUB_OUTPUT"
|
||||
echo "sudo=`command -v sudo`" >> "$GITHUB_OUTPUT"
|
||||
echo "sudo=`sudo true && command -v sudo`" >> "$GITHUB_OUTPUT"
|
||||
echo "autoreconf=`command -v autoreconf`" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- if: steps.which.outputs.git
|
||||
|
@ -183,3 +183,5 @@ runs:
|
|||
${{ steps.clean.outputs.distclean }}
|
||||
${{ steps.clean.outputs.remained-files }}
|
||||
${{ steps.clean.outputs.final }}
|
||||
# rmdir randomly fails due to launchable files
|
||||
continue-on-error: true
|
||||
|
|
2
.github/actions/setup/macos/action.yml
vendored
2
.github/actions/setup/macos/action.yml
vendored
|
@ -21,7 +21,7 @@ runs:
|
|||
dir_config() {
|
||||
local args=() lib var="$1"; shift
|
||||
for lib in "$@"; do
|
||||
args+="--with-${lib%@*}-dir=$(brew --prefix $lib)"
|
||||
args+=("--with-${lib%@*}-dir=$(brew --prefix $lib)")
|
||||
done
|
||||
echo "$var=${args[*]}" >> $GITHUB_ENV
|
||||
}
|
||||
|
|
2
.github/auto_request_review.yml
vendored
2
.github/auto_request_review.yml
vendored
|
@ -10,6 +10,8 @@ files:
|
|||
'zjit/src/cruby_bindings.inc.rs': []
|
||||
'doc/zjit*': [team:jit]
|
||||
'test/ruby/test_zjit*': [team:jit]
|
||||
'test/.excludes-zjit/*': [team:jit]
|
||||
'defs/jit.mk': [team:jit]
|
||||
options:
|
||||
ignore_draft: true
|
||||
# This currently doesn't work as intended. We want to skip reviews when only
|
||||
|
|
2
.github/workflows/annocheck.yml
vendored
2
.github/workflows/annocheck.yml
vendored
|
@ -74,7 +74,7 @@ jobs:
|
|||
builddir: build
|
||||
makeup: true
|
||||
|
||||
- uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: '3.1'
|
||||
bundler: none
|
||||
|
|
2
.github/workflows/auto_request_review.yml
vendored
2
.github/workflows/auto_request_review.yml
vendored
|
@ -17,4 +17,4 @@ jobs:
|
|||
uses: necojackarc/auto-request-review@e89da1a8cd7c8c16d9de9c6e763290b6b0e3d424 # v0.13.0
|
||||
with:
|
||||
# scope: public_repo
|
||||
token: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
|
||||
token: ${{ secrets.MATZBOT_AUTO_REQUEST_REVIEW_TOKEN }}
|
||||
|
|
2
.github/workflows/baseruby.yml
vendored
2
.github/workflows/baseruby.yml
vendored
|
@ -50,7 +50,7 @@ jobs:
|
|||
- ruby-3.3
|
||||
|
||||
steps:
|
||||
- uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler: none
|
||||
|
|
8
.github/workflows/bundled_gems.yml
vendored
8
.github/workflows/bundled_gems.yml
vendored
|
@ -33,11 +33,11 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: ./.github/actions/setup/directories
|
||||
with:
|
||||
# Skip overwriting MATZBOT_GITHUB_TOKEN
|
||||
# Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
|
||||
checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
|
||||
|
||||
- name: Set ENV
|
||||
|
@ -104,7 +104,7 @@ jobs:
|
|||
timeout-minutes: 30
|
||||
env:
|
||||
RUBY_TESTOPTS: '-q --tty=no'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof,rbs,repl_type_completor'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
|
||||
if: ${{ steps.diff.outputs.gems }}
|
||||
|
||||
- name: Commit
|
||||
|
@ -112,7 +112,7 @@ jobs:
|
|||
git pull --ff-only origin ${GITHUB_REF#refs/heads/}
|
||||
message="Update bundled gems list"
|
||||
if [ -z "${gems}" ]; then
|
||||
git commit --message="${message} at ${GITHUB_SHA:0:30} [ci skip]"
|
||||
git commit --message="[DOC] ${message} at ${GITHUB_SHA:0:30}"
|
||||
else
|
||||
git commit --message="${message} as of ${TODAY}"
|
||||
fi
|
||||
|
|
2
.github/workflows/check_dependencies.yml
vendored
2
.github/workflows/check_dependencies.yml
vendored
|
@ -40,7 +40,7 @@ jobs:
|
|||
|
||||
- uses: ./.github/actions/setup/directories
|
||||
|
||||
- uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: '3.1'
|
||||
bundler: none
|
||||
|
|
12
.github/workflows/check_misc.yml
vendored
12
.github/workflows/check_misc.yml
vendored
|
@ -20,12 +20,12 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: ./.github/actions/setup/directories
|
||||
with:
|
||||
makeup: true
|
||||
# Skip overwriting MATZBOT_GITHUB_TOKEN
|
||||
# Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
|
||||
checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
|
||||
|
||||
# Run this step first to make sure auto-style commits are pushed
|
||||
|
@ -37,10 +37,10 @@ jobs:
|
|||
EMAIL: svn-admin@ruby-lang.org
|
||||
GIT_AUTHOR_NAME: git
|
||||
GIT_COMMITTER_NAME: git
|
||||
GITHUB_OLD_SHA: ${{ startsWith(github.event_name, 'pull') && github.event.pull_request.base.sha || github.event.before }}
|
||||
GITHUB_NEW_SHA: ${{ startsWith(github.event_name, 'pull') && github.event.pull_request.merge_commit_sha || github.event.after }}
|
||||
GITHUB_OLD_SHA: ${{ github.event.pull_request.base.sha }}
|
||||
GITHUB_NEW_SHA: ${{ github.event.pull_request.merge_commit_sha }}
|
||||
PUSH_REF: ${{ github.ref == 'refs/heads/master' && github.ref || '' }}
|
||||
if: ${{ github.repository == 'ruby/ruby' }}
|
||||
if: ${{ github.repository == 'ruby/ruby' && startsWith(github.event_name, 'pull') }}
|
||||
|
||||
- name: Check if C-sources are US-ASCII
|
||||
run: |
|
||||
|
@ -64,7 +64,7 @@ jobs:
|
|||
- name: Generate docs
|
||||
id: docs
|
||||
run: |
|
||||
ruby -W0 --disable-gems -I./lib tool/rdoc-srcdir -q --op html .
|
||||
ruby -W0 --disable-gems tool/rdoc-srcdir -q --op html .
|
||||
echo htmlout=ruby-html-${GITHUB_SHA:0:10} >> $GITHUB_OUTPUT
|
||||
# Generate only when document commit/PR
|
||||
if: >-
|
||||
|
|
7
.github/workflows/codeql-analysis.yml
vendored
7
.github/workflows/codeql-analysis.yml
vendored
|
@ -80,6 +80,7 @@ jobs:
|
|||
uses: github/codeql-action/init@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
trap-caching: false
|
||||
debug: true
|
||||
|
||||
- name: Autobuild
|
||||
|
@ -120,9 +121,3 @@ jobs:
|
|||
with:
|
||||
sarif_file: sarif-results/${{ matrix.language }}.sarif
|
||||
continue-on-error: true
|
||||
|
||||
- name: Purge the oldest TRAP cache
|
||||
if: ${{ github.repository == 'ruby/ruby' && matrix.language == 'cpp'}}
|
||||
run: gh cache list --key codeql --order asc --limit 1 --json key --jq '.[].key' | xargs -I{} gh cache delete {}
|
||||
env:
|
||||
GH_TOKEN: ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }}
|
||||
|
|
8
.github/workflows/compilers.yml
vendored
8
.github/workflows/compilers.yml
vendored
|
@ -78,11 +78,11 @@ 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 } }
|
||||
- name: 'GCC 13 LTO'
|
||||
- name: 'GCC 15 LTO'
|
||||
uses: './.github/actions/compilers'
|
||||
with:
|
||||
tag: gcc-13
|
||||
with_gcc: 'gcc-13 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch'
|
||||
tag: gcc-15
|
||||
with_gcc: 'gcc-15 -flto=auto -ffat-lto-objects -Werror=lto-type-mismatch'
|
||||
optflags: '-O2'
|
||||
enable_shared: false
|
||||
- { uses: './.github/actions/compilers', name: 'ext/Setup', with: { static_exts: 'etc json/* */escape' } }
|
||||
|
@ -299,6 +299,8 @@ jobs:
|
|||
- { uses: './.github/actions/compilers', name: 'VM_DEBUG_BP_CHECK', with: { cppflags: '-DVM_DEBUG_BP_CHECK' } }
|
||||
- { uses: './.github/actions/compilers', name: 'VM_DEBUG_VERIFY_METHOD_CACHE', with: { cppflags: '-DVM_DEBUG_VERIFY_METHOD_CACHE' } }
|
||||
- { uses: './.github/actions/compilers', name: 'enable-yjit', with: { append_configure: '--enable-yjit' } }
|
||||
- { uses: './.github/actions/compilers', name: 'enable-{y,z}jit', with: { append_configure: '--enable-yjit --enable-zjit' } }
|
||||
- { uses: './.github/actions/compilers', name: 'enable-{y,z}jit=dev', with: { append_configure: '--enable-yjit=dev --enable-zjit' } }
|
||||
- { uses: './.github/actions/compilers', name: 'YJIT_FORCE_ENABLE', with: { cppflags: '-DYJIT_FORCE_ENABLE' } }
|
||||
- { uses: './.github/actions/compilers', name: 'UNIVERSAL_PARSER', with: { cppflags: '-DUNIVERSAL_PARSER' } }
|
||||
|
||||
|
|
15
.github/workflows/default_gems.yml
vendored
15
.github/workflows/default_gems.yml
vendored
|
@ -22,18 +22,19 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_GITHUB_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
|
||||
- uses: ./.github/actions/setup/directories
|
||||
with:
|
||||
makeup: true
|
||||
# Skip overwriting MATZBOT_GITHUB_TOKEN
|
||||
checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
|
||||
token: ${{ (github.repository == 'ruby/ruby' && !startsWith(github.event_name, 'pull')) && secrets.MATZBOT_AUTO_UPDATE_TOKEN || secrets.GITHUB_TOKEN }}
|
||||
|
||||
- id: gems
|
||||
run: true
|
||||
if: ${{ github.ref == 'refs/heads/master' }}
|
||||
|
||||
- uses: ./.github/actions/setup/directories
|
||||
with:
|
||||
makeup: true
|
||||
# Skip overwriting MATZBOT_AUTO_UPDATE_TOKEN
|
||||
checkout: '' # false (ref: https://github.com/actions/runner/issues/2238)
|
||||
if: ${{ steps.gems.outcome == 'success' }}
|
||||
|
||||
- name: Download previous gems list
|
||||
run: |
|
||||
data=default_gems.json
|
||||
|
|
6
.github/workflows/dependabot_automerge.yml
vendored
6
.github/workflows/dependabot_automerge.yml
vendored
|
@ -13,13 +13,13 @@ jobs:
|
|||
if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository == 'ruby/ruby'
|
||||
steps:
|
||||
- name: Dependabot metadata
|
||||
uses: dependabot/fetch-metadata@d7267f607e9d3fb96fc2fbe83e0af444713e90b7 # v2.3.0
|
||||
uses: dependabot/fetch-metadata@08eff52bf64351f401fb50d4972fa95b9f2c2d1b # v2.4.0
|
||||
id: metadata
|
||||
|
||||
- name: Wait for status checks
|
||||
uses: lewagon/wait-on-check-action@ccfb013c15c8afb7bf2b7c028fb74dc5a068cccc # v1.3.4
|
||||
with:
|
||||
repo-token: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
|
||||
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||
ref: ${{ github.event.pull_request.head.sha || github.sha }}
|
||||
check-regexp: 'make \(check, .*\)'
|
||||
wait-interval: 30
|
||||
|
@ -29,4 +29,4 @@ jobs:
|
|||
run: gh pr merge --auto --rebase "$PR_URL"
|
||||
env:
|
||||
PR_URL: ${{ github.event.pull_request.html_url }}
|
||||
GITHUB_TOKEN: ${{ secrets.MATZBOT_GITHUB_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.MATZBOT_DEPENDABOT_MERGE_TOKEN }}
|
||||
|
|
17
.github/workflows/macos.yml
vendored
17
.github/workflows/macos.yml
vendored
|
@ -107,6 +107,10 @@ jobs:
|
|||
|
||||
- run: make hello
|
||||
|
||||
- name: runirb
|
||||
run: |
|
||||
echo IRB::VERSION | make runirb RUNOPT="-- -f"
|
||||
|
||||
- name: Set test options for skipped tests
|
||||
run: |
|
||||
set -x
|
||||
|
@ -115,6 +119,7 @@ jobs:
|
|||
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
|
||||
|
||||
- name: Set up Launchable
|
||||
id: launchable
|
||||
uses: ./.github/actions/launchable/setup
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
|
@ -123,6 +128,7 @@ jobs:
|
|||
builddir: build
|
||||
srcdir: src
|
||||
continue-on-error: true
|
||||
timeout-minutes: 3
|
||||
|
||||
- name: Set extra test options
|
||||
run: |
|
||||
|
@ -132,19 +138,18 @@ jobs:
|
|||
|
||||
- name: make ${{ matrix.test_task }}
|
||||
run: |
|
||||
if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
|
||||
exec \
|
||||
> >(tee launchable_stdout.log) \
|
||||
2> >(tee launchable_stderr.log)
|
||||
fi
|
||||
test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
|
||||
test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
|
||||
|
||||
ulimit -c unlimited
|
||||
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
RUBY_TESTOPTS: '-q --tty=no'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof,rbs,repl_type_completor'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
|
||||
PRECHECK_BUNDLED_GEMS: 'no'
|
||||
LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
|
||||
LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
|
||||
|
||||
- name: make skipped tests
|
||||
run: |
|
||||
|
|
1
.github/workflows/mingw.yml
vendored
1
.github/workflows/mingw.yml
vendored
|
@ -127,6 +127,7 @@ jobs:
|
|||
srcdir: src
|
||||
test-tasks: '["test", "test-all", "test-spec"]'
|
||||
continue-on-error: true
|
||||
timeout-minutes: 3
|
||||
|
||||
- name: test
|
||||
timeout-minutes: 30
|
||||
|
|
19
.github/workflows/modgc.yml
vendored
19
.github/workflows/modgc.yml
vendored
|
@ -26,8 +26,8 @@ jobs:
|
|||
matrix:
|
||||
gc:
|
||||
- name: default
|
||||
# - name: mmtk
|
||||
# mmtk_build: release
|
||||
- name: mmtk
|
||||
mmtk_build: release
|
||||
os: [macos-latest, ubuntu-latest]
|
||||
include:
|
||||
- test_task: check
|
||||
|
@ -63,7 +63,7 @@ jobs:
|
|||
uses: ./.github/actions/setup/ubuntu
|
||||
if: ${{ contains(matrix.os, 'ubuntu') }}
|
||||
|
||||
- uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: '3.1'
|
||||
bundler: none
|
||||
|
@ -131,6 +131,7 @@ jobs:
|
|||
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
|
||||
|
||||
- name: Set up Launchable
|
||||
id: launchable
|
||||
uses: ./.github/actions/launchable/setup
|
||||
with:
|
||||
os: ${{ matrix.os || 'ubuntu-22.04' }}
|
||||
|
@ -139,14 +140,12 @@ jobs:
|
|||
builddir: build
|
||||
srcdir: src
|
||||
continue-on-error: true
|
||||
timeout-minutes: 3
|
||||
|
||||
- name: make ${{ matrix.test_task }}
|
||||
run: |
|
||||
if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
|
||||
exec \
|
||||
> >(tee launchable_stdout.log) \
|
||||
2> >(tee launchable_stderr.log)
|
||||
fi
|
||||
test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
|
||||
test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
|
||||
|
||||
$SETARCH make -s ${{ matrix.test_task }} \
|
||||
${TESTS:+TESTS="$TESTS"} \
|
||||
|
@ -154,8 +153,10 @@ jobs:
|
|||
timeout-minutes: ${{ matrix.gc.timeout || 40 }}
|
||||
env:
|
||||
RUBY_TESTOPTS: '-q --tty=no'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof,rbs,repl_type_completor'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
|
||||
PRECHECK_BUNDLED_GEMS: 'no'
|
||||
LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
|
||||
LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
|
||||
|
||||
- name: make skipped tests
|
||||
run: |
|
||||
|
|
4
.github/workflows/parse_y.yml
vendored
4
.github/workflows/parse_y.yml
vendored
|
@ -60,7 +60,7 @@ jobs:
|
|||
|
||||
- uses: ./.github/actions/setup/ubuntu
|
||||
|
||||
- uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: '3.1'
|
||||
bundler: none
|
||||
|
@ -87,7 +87,7 @@ jobs:
|
|||
EXCLUDES: '../src/test/.excludes-parsey'
|
||||
RUN_OPTS: ${{ matrix.run_opts || '--parser=parse.y' }}
|
||||
SPECOPTS: ${{ matrix.specopts || '-T --parser=parse.y' }}
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof,rbs,repl_type_completor'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
|
||||
|
||||
- uses: ./.github/actions/slack
|
||||
with:
|
||||
|
|
2
.github/workflows/release.yml
vendored
2
.github/workflows/release.yml
vendored
|
@ -55,7 +55,7 @@ jobs:
|
|||
echo $PREVIOUS_RELEASE_TAG
|
||||
tool/gen-github-release.rb $PREVIOUS_RELEASE_TAG $RELEASE_TAG --no-dry-run
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.MATZBOT_GITHUB_WORKFLOW_TOKEN }}
|
||||
GITHUB_TOKEN: ${{ secrets.MATZBOT_AUTO_UPDATE_TOKEN }}
|
||||
|
||||
- name: Update versions index
|
||||
run: |
|
||||
|
|
44
.github/workflows/scorecards.yml
vendored
44
.github/workflows/scorecards.yml
vendored
|
@ -2,7 +2,7 @@
|
|||
# by a third-party and are governed by separate terms of service, privacy
|
||||
# policy, and support documentation.
|
||||
|
||||
name: Scorecards supply-chain security
|
||||
name: Scorecard supply-chain security
|
||||
on:
|
||||
# For Branch-Protection check. Only the default branch is supported. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
|
||||
|
@ -10,7 +10,7 @@ on:
|
|||
# To guarantee Maintained check is occasionally updated. See
|
||||
# https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
|
||||
schedule:
|
||||
- cron: '22 4 * * 2'
|
||||
- cron: '39 3 * * 5'
|
||||
# push:
|
||||
# branches: [ "master" ]
|
||||
|
||||
|
@ -19,8 +19,10 @@ permissions: read-all
|
|||
|
||||
jobs:
|
||||
analysis:
|
||||
name: Scorecards analysis
|
||||
name: Scorecard analysis
|
||||
runs-on: ubuntu-latest
|
||||
# `publish_results: true` only works when run from the default branch. conditional can be removed if disabled.
|
||||
if: github.event.repository.default_branch == github.ref_name || github.event_name == 'pull_request'
|
||||
permissions:
|
||||
# Needed to upload the results to code-scanning dashboard.
|
||||
security-events: write
|
||||
|
@ -31,21 +33,21 @@ jobs:
|
|||
# actions: read
|
||||
|
||||
steps:
|
||||
- name: 'Checkout code'
|
||||
- name: "Checkout code"
|
||||
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: 'Run analysis'
|
||||
uses: ossf/scorecard-action@62b2cac7ed8198b15735ed49ab1e5cf35480ba46 # v2.4.0
|
||||
- name: "Run analysis"
|
||||
uses: ossf/scorecard-action@05b42c624433fc40578a4040d5cf5e36ddca8cde # v2.4.2
|
||||
with:
|
||||
results_file: results.sarif
|
||||
results_format: sarif
|
||||
# (Optional) Read-only PAT token. Uncomment the `repo_token` line below if:
|
||||
# (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
|
||||
# - you want to enable the Branch-Protection check on a *public* repository, or
|
||||
# - you are installing Scorecards on a *private* repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action#authentication-with-pat.
|
||||
repo_token: ${{ secrets.SCORECARD_READ_TOKEN }}
|
||||
# - you are installing Scorecard on a *private* repository
|
||||
# To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
|
||||
# repo_token: ${{ secrets.SCORECARD_TOKEN }}
|
||||
|
||||
# Public repositories:
|
||||
# - Publish results to OpenSSF REST API for easy access by consumers
|
||||
|
@ -56,17 +58,21 @@ jobs:
|
|||
# of the value entered here.
|
||||
publish_results: true
|
||||
|
||||
# (Optional) Uncomment file_mode if you have a .gitattributes with files marked export-ignore
|
||||
# file_mode: git
|
||||
|
||||
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
|
||||
# format to the repository Actions tab.
|
||||
# - name: "Upload artifact"
|
||||
# uses: actions/upload-artifact@0b7f8abb1508181956e8e162db84b466c27e18ce # v3.1.2
|
||||
# with:
|
||||
# name: SARIF file
|
||||
# path: results.sarif
|
||||
# retention-days: 5
|
||||
- name: "Upload artifact"
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: SARIF file
|
||||
path: results.sarif
|
||||
retention-days: 5
|
||||
|
||||
# Upload the results to GitHub's code scanning dashboard.
|
||||
- name: 'Upload to code-scanning'
|
||||
uses: github/codeql-action/upload-sarif@df409f7d9260372bd5f19e5b04e83cb3c43714ae # v3.27.9
|
||||
# Upload the results to GitHub's code scanning dashboard (optional).
|
||||
# Commenting out will disable upload of results to your repo's Code Scanning dashboard
|
||||
- name: "Upload to code-scanning"
|
||||
uses: github/codeql-action/upload-sarif@v3
|
||||
with:
|
||||
sarif_file: results.sarif
|
||||
|
|
2
.github/workflows/spec_guards.yml
vendored
2
.github/workflows/spec_guards.yml
vendored
|
@ -48,7 +48,7 @@ jobs:
|
|||
steps:
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
|
||||
- uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: ${{ matrix.ruby }}
|
||||
bundler: none
|
||||
|
|
19
.github/workflows/ubuntu.yml
vendored
19
.github/workflows/ubuntu.yml
vendored
|
@ -68,7 +68,7 @@ jobs:
|
|||
with:
|
||||
arch: ${{ matrix.arch }}
|
||||
|
||||
- uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: '3.1'
|
||||
bundler: none
|
||||
|
@ -99,6 +99,10 @@ jobs:
|
|||
|
||||
- run: $SETARCH make hello
|
||||
|
||||
- name: runirb
|
||||
run: |
|
||||
echo IRB::VERSION | $SETARCH make runirb RUNOPT="-- -f"
|
||||
|
||||
- name: Set test options for skipped tests
|
||||
run: |
|
||||
set -x
|
||||
|
@ -107,6 +111,7 @@ jobs:
|
|||
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
|
||||
|
||||
- name: Set up Launchable
|
||||
id: launchable
|
||||
uses: ./.github/actions/launchable/setup
|
||||
with:
|
||||
os: ${{ matrix.os || 'ubuntu-22.04' }}
|
||||
|
@ -115,14 +120,12 @@ jobs:
|
|||
builddir: build
|
||||
srcdir: src
|
||||
continue-on-error: true
|
||||
timeout-minutes: 3
|
||||
|
||||
- name: make ${{ matrix.test_task }}
|
||||
run: |
|
||||
if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
|
||||
exec \
|
||||
> >(tee launchable_stdout.log) \
|
||||
2> >(tee launchable_stderr.log)
|
||||
fi
|
||||
test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
|
||||
test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
|
||||
|
||||
$SETARCH make -s ${{ matrix.test_task }} \
|
||||
${TESTS:+TESTS="$TESTS"} \
|
||||
|
@ -130,8 +133,10 @@ jobs:
|
|||
timeout-minutes: ${{ matrix.timeout || 40 }}
|
||||
env:
|
||||
RUBY_TESTOPTS: '-q --tty=no'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof,rbs,repl_type_completor'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
|
||||
PRECHECK_BUNDLED_GEMS: 'no'
|
||||
LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
|
||||
LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
|
||||
|
||||
- name: make skipped tests
|
||||
run: |
|
||||
|
|
8
.github/workflows/wasm.yml
vendored
8
.github/workflows/wasm.yml
vendored
|
@ -100,7 +100,7 @@ jobs:
|
|||
run: |
|
||||
echo "WASI_SDK_PATH=/opt/wasi-sdk" >> $GITHUB_ENV
|
||||
|
||||
- uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: '3.1'
|
||||
bundler: none
|
||||
|
@ -142,7 +142,7 @@ jobs:
|
|||
- run: tar cfz ../install.tar.gz -C ../install .
|
||||
|
||||
- name: Upload artifacts
|
||||
uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1
|
||||
uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
with:
|
||||
name: ruby-wasm-install
|
||||
path: ${{ github.workspace }}/install.tar.gz
|
||||
|
@ -152,8 +152,6 @@ jobs:
|
|||
|
||||
- name: Run basictest
|
||||
run: wasmtime run ./../build/miniruby --mapdir /::./ -- basictest/test.rb
|
||||
env:
|
||||
WASMTIME_BACKTRACE_DETAILS: '1'
|
||||
working-directory: src
|
||||
|
||||
- name: Run bootstraptest (no thread)
|
||||
|
@ -172,7 +170,7 @@ jobs:
|
|||
- name: Save Pull Request number
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
run: echo "${{ github.event.pull_request.number }}" >> ${{ github.workspace }}/github-pr-info.txt
|
||||
- uses: actions/upload-artifact@604373da6381bf24206979c74d06a550515601b9 # v4.4.1
|
||||
- uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
name: github-pr-info
|
||||
|
|
101
.github/workflows/windows.yml
vendored
101
.github/workflows/windows.yml
vendored
|
@ -26,19 +26,16 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- os: 2022
|
||||
vc: 2019
|
||||
vcvars: '10.0.22621.0 -vcvars_ver=14.2' # The defautl Windows 11 SDK and toolset are broken at windows-2022
|
||||
vc: 2022
|
||||
test_task: check
|
||||
- os: 2025
|
||||
vc: 2019
|
||||
vcvars: '10.0.22621.0 -vcvars_ver=14.2'
|
||||
vc: 2022
|
||||
test_task: check
|
||||
- os: 11-arm
|
||||
test_task: 'btest test-basic test-tool' # check and test-spec are broken yet.
|
||||
target: arm64
|
||||
- os: 2022
|
||||
vc: 2019
|
||||
vcvars: '10.0.22621.0 -vcvars_ver=14.2'
|
||||
- os: 2025
|
||||
vc: 2022
|
||||
test_task: test-bundled-gems
|
||||
fail-fast: false
|
||||
|
||||
|
@ -59,27 +56,18 @@ jobs:
|
|||
env:
|
||||
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
|
||||
VCPKG_DEFAULT_TRIPLET: ${{ matrix.target || 'x64' }}-windows
|
||||
RUBY_OPT_DIR: ${{ matrix.os == '11-arm' && 'C' || 'D' }}:/a/ruby/ruby/src/vcpkg_installed/%VCPKG_DEFAULT_TRIPLET%
|
||||
|
||||
steps:
|
||||
- run: md build
|
||||
working-directory:
|
||||
|
||||
- uses: ruby/setup-ruby@e34163cd15f4bb403dcd72d98e295997e6a55798 # v1.238.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
# windows-11-arm has only 3.4.1, 3.4.2, 3.4.3, head
|
||||
ruby-version: ${{ matrix.os != '11-arm' && '3.1' || '3.4' }}
|
||||
ruby-version: ${{ !endsWith(matrix.os, 'arm') && '3.1' || '3.4' }}
|
||||
bundler: none
|
||||
windows-toolchain: none
|
||||
|
||||
- name: Install libraries with scoop
|
||||
run: |
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
iwr -useb get.scoop.sh | iex
|
||||
Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH
|
||||
scoop install vcpkg uutils-coreutils cmake@3.31.6
|
||||
shell: pwsh
|
||||
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
sparse-checkout-cone-mode: false
|
||||
|
@ -90,27 +78,47 @@ jobs:
|
|||
srcdir: src
|
||||
builddir: build
|
||||
|
||||
- name: Install tools with scoop
|
||||
run: |
|
||||
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser
|
||||
iwr -useb get.scoop.sh | iex
|
||||
Join-Path (Resolve-Path ~).Path "scoop\shims" >> $Env:GITHUB_PATH
|
||||
scoop install vcpkg uutils-coreutils cmake@3.31.6
|
||||
shell: pwsh
|
||||
|
||||
- name: Restore vcpkg artifact
|
||||
uses: actions/cache/restore@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
with:
|
||||
path: src\vcpkg_installed
|
||||
key: windows-${{ matrix.os }}-vcpkg-${{ hashFiles('src/vcpkg.json') }}
|
||||
|
||||
- name: Install libraries with vcpkg
|
||||
run: |
|
||||
vcpkg install --vcpkg-root=C:\Users\runneradmin\scoop\apps\vcpkg\current
|
||||
working-directory: src
|
||||
|
||||
- name: Save vcpkg artifact
|
||||
uses: actions/cache/save@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
with:
|
||||
path: src\vcpkg_installed
|
||||
key: windows-${{ matrix.os }}-vcpkg-${{ hashFiles('src/vcpkg.json') }}
|
||||
|
||||
- name: setup env
|
||||
# Available Ruby versions: https://github.com/actions/runner-images/blob/main/images/windows/Windows2019-Readme.md#ruby
|
||||
# %TEMP% is inconsistent with %TMP% and test-all expects they are consistent.
|
||||
# https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302
|
||||
run: |
|
||||
::- Set up VC ${{ matrix.vc }}
|
||||
set vswhere="%ProgramFiles(x86)%\Microsoft Visual Studio\Installer\vswhere.exe"
|
||||
for /f "delims=;" %%I in ('%vswhere% -latest -property installationPath') do (
|
||||
set VCVARS="%%I\VC\Auxiliary\Build\vcvars64.bat"
|
||||
)
|
||||
if "${{ matrix.os }}" == "11-arm" (
|
||||
set VCVARS="C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvarsarm64.bat"
|
||||
)
|
||||
set VCVARS
|
||||
set | uutils sort > old.env
|
||||
call %VCVARS% ${{ matrix.vcvars || '' }}
|
||||
call ..\src\win32\vssetup.cmd ^
|
||||
-arch=${{ matrix.target || 'amd64' }} ^
|
||||
${{ matrix.vcvars && '-vcvars_ver=' || '' }}${{ matrix.vcvars }}
|
||||
nmake -f nul
|
||||
set TMP=%USERPROFILE%\AppData\Local\Temp
|
||||
set TEMP=%USERPROFILE%\AppData\Local\Temp
|
||||
set MAKEFLAGS=l
|
||||
set /a TEST_JOBS=(15 * %NUMBER_OF_PROCESSORS% / 10) > nul
|
||||
set RUBY_OPT_DIR=%GITHUB_WORKSPACE:\=/%/src/vcpkg_installed/%VCPKG_DEFAULT_TRIPLET%
|
||||
set | uutils sort > new.env
|
||||
uutils comm -13 old.env new.env >> %GITHUB_ENV%
|
||||
del *.env
|
||||
|
@ -125,18 +133,6 @@ jobs:
|
|||
run: Get-Volume
|
||||
shell: pwsh
|
||||
|
||||
# vcpkg built-in cache is not working now
|
||||
- name: Restore vcpkg artifact
|
||||
uses: actions/cache@5a3ec84eff668545956fd18022155c47e93e2684 # v4.2.3
|
||||
with:
|
||||
path: C:\Users\runneradmin\AppData\Local\vcpkg\archives
|
||||
key: windows-${{ matrix.os }}-vcpkg-${{ hashFiles('src/vcpkg.json') }}
|
||||
|
||||
- name: Install libraries with vcpkg
|
||||
run: |
|
||||
vcpkg install --vcpkg-root=C:\Users\runneradmin\scoop\apps\vcpkg\current
|
||||
working-directory: src
|
||||
|
||||
# TODO: We should use `../src` instead of `D:/a/ruby/ruby/src`
|
||||
- name: Configure
|
||||
run: >-
|
||||
|
@ -157,26 +153,30 @@ jobs:
|
|||
# windows-11-arm runner cannot run `ruby tool/file2lastrev.rb --revision.h --output=revision.h`
|
||||
- name: make revision.h
|
||||
run: |
|
||||
if not exist revision.h (
|
||||
for /f "tokens=1-3" %%I in ('git log -1 "--date=format-local:%%F %%T" "--format=%%H %%cd" @') do (
|
||||
set rev=%%I
|
||||
set dt=%%J
|
||||
set tm=%%K
|
||||
)
|
||||
set yy=%dt:~0,4%
|
||||
set /a mm=100%dt:~5,2% %% 100
|
||||
set /a dd=100%dt:~8,2% %% 100
|
||||
call set yy=%%dt:~0,4%%
|
||||
call set /a mm=100%%dt:~5,2%% %%%% 100
|
||||
call set /a dd=100%%dt:~8,2%% %%%% 100
|
||||
call set branch=%%GITHUB_REF:refs/heads/=%%
|
||||
(
|
||||
echo #define RUBY_REVISION "%rev:~,10%"
|
||||
echo #define RUBY_FULL_REVISION "%rev%"
|
||||
echo #define RUBY_BRANCH_NAME "%GITHUB_REF%"
|
||||
echo #define RUBY_RELEASE_DATETIME "%dt%T%tm%"
|
||||
echo #define RUBY_RELEASE_YEAR %yy%
|
||||
echo #define RUBY_RELEASE_MONTH %mm%
|
||||
echo #define RUBY_RELEASE_DAY %dd%
|
||||
call echo #define RUBY_REVISION "%%rev:~,10%%"
|
||||
call echo #define RUBY_FULL_REVISION "%%rev%%"
|
||||
call echo #define RUBY_BRANCH_NAME "%%branch%%"
|
||||
call echo #define RUBY_RELEASE_DATETIME "%%dt%%T%%tm%%"
|
||||
call echo #define RUBY_RELEASE_YEAR %%yy%%
|
||||
call echo #define RUBY_RELEASE_MONTH %%mm%%
|
||||
call echo #define RUBY_RELEASE_DAY %%dd%%
|
||||
) > revision.h
|
||||
copy /y NUL .revision.time
|
||||
)
|
||||
type revision.h
|
||||
env:
|
||||
TZ: UTC
|
||||
if: ${{ matrix.os == '11-arm' }}
|
||||
|
||||
- run: nmake
|
||||
|
||||
|
@ -190,6 +190,7 @@ jobs:
|
|||
test-task: ${{ matrix.test_task || 'check' }}
|
||||
continue-on-error: true
|
||||
if: ${{ matrix.test_task != 'test-bundled-gems' }}
|
||||
timeout-minutes: 3
|
||||
|
||||
- run: nmake ${{ matrix.test_task || 'check' }}
|
||||
env:
|
||||
|
|
5
.github/workflows/wsl.yml
vendored
5
.github/workflows/wsl.yml
vendored
|
@ -16,7 +16,7 @@ on:
|
|||
|
||||
jobs:
|
||||
wsl:
|
||||
runs-on: windows-latest
|
||||
runs-on: windows-2025
|
||||
|
||||
if: >-
|
||||
${{!(false
|
||||
|
@ -29,9 +29,6 @@ jobs:
|
|||
)}}
|
||||
|
||||
steps:
|
||||
- name: Install winget
|
||||
uses: Cyberboss/install-winget@v1
|
||||
|
||||
- name: Install or update WSL
|
||||
uses: Ubuntu/WSL/.github/actions/wsl-install@main
|
||||
with:
|
||||
|
|
20
.github/workflows/yjit-macos.yml
vendored
20
.github/workflows/yjit-macos.yml
vendored
|
@ -112,6 +112,13 @@ jobs:
|
|||
|
||||
- run: make
|
||||
|
||||
- name: Verify that --yjit-dump-disasm works
|
||||
run: |
|
||||
./miniruby --yjit-call-threshold=1 --yjit-dump-disasm -e0 | \
|
||||
wc -l | \
|
||||
ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
|
||||
if: ${{ contains(matrix.configure, 'jit=dev') }}
|
||||
|
||||
- name: Enable YJIT through ENV
|
||||
run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
|
||||
|
||||
|
@ -123,6 +130,7 @@ jobs:
|
|||
if: ${{ matrix.test_task == 'check' && matrix.skipped_tests }}
|
||||
|
||||
- name: Set up Launchable
|
||||
id: launchable
|
||||
uses: ./.github/actions/launchable/setup
|
||||
with:
|
||||
os: macos-14
|
||||
|
@ -132,14 +140,12 @@ jobs:
|
|||
srcdir: src
|
||||
is-yjit: true
|
||||
continue-on-error: true
|
||||
timeout-minutes: 3
|
||||
|
||||
- name: make ${{ matrix.test_task }}
|
||||
run: |
|
||||
if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
|
||||
exec \
|
||||
> >(tee launchable_stdout.log) \
|
||||
2> >(tee launchable_stderr.log)
|
||||
fi
|
||||
test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
|
||||
test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
|
||||
|
||||
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \
|
||||
RUN_OPTS="$RUN_OPTS" \
|
||||
|
@ -147,9 +153,11 @@ jobs:
|
|||
timeout-minutes: 60
|
||||
env:
|
||||
RUBY_TESTOPTS: '-q --tty=no'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof,rbs,repl_type_completor'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
|
||||
SYNTAX_SUGGEST_TIMEOUT: '5'
|
||||
PRECHECK_BUNDLED_GEMS: 'no'
|
||||
LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
|
||||
LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
|
||||
continue-on-error: ${{ matrix.continue-on-test_task || false }}
|
||||
|
||||
- name: make skipped tests
|
||||
|
|
22
.github/workflows/yjit-ubuntu.yml
vendored
22
.github/workflows/yjit-ubuntu.yml
vendored
|
@ -135,7 +135,7 @@ jobs:
|
|||
|
||||
- uses: ./.github/actions/setup/ubuntu
|
||||
|
||||
- uses: ruby/setup-ruby@d8d83c3960843afb664e821fed6be52f37da5267 # v1.231.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: '3.1'
|
||||
bundler: none
|
||||
|
@ -163,6 +163,13 @@ jobs:
|
|||
|
||||
- run: make
|
||||
|
||||
- name: Verify that --yjit-dump-disasm works
|
||||
run: |
|
||||
./miniruby --yjit-call-threshold=1 --yjit-dump-disasm -e0 | \
|
||||
wc -l | \
|
||||
ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
|
||||
if: ${{ contains(matrix.configure, 'jit=dev') }}
|
||||
|
||||
- name: Enable YJIT through ENV
|
||||
run: echo "RUBY_YJIT_ENABLE=1" >> $GITHUB_ENV
|
||||
|
||||
|
@ -171,6 +178,7 @@ jobs:
|
|||
run: ./miniruby --yjit -v | grep "+YJIT"
|
||||
|
||||
- name: Set up Launchable
|
||||
id: launchable
|
||||
uses: ./.github/actions/launchable/setup
|
||||
with:
|
||||
os: ubuntu-22.04
|
||||
|
@ -180,14 +188,12 @@ jobs:
|
|||
srcdir: src
|
||||
is-yjit: true
|
||||
continue-on-error: true
|
||||
timeout-minutes: 3
|
||||
|
||||
- name: make ${{ matrix.test_task }}
|
||||
run: |
|
||||
if [ -n "${LAUNCHABLE_ORGANIZATION}" ]; then
|
||||
exec \
|
||||
> >(tee launchable_stdout.log) \
|
||||
2> >(tee launchable_stderr.log)
|
||||
fi
|
||||
test -n "${LAUNCHABLE_STDOUT}" && exec 1> >(tee "${LAUNCHABLE_STDOUT}")
|
||||
test -n "${LAUNCHABLE_STDERR}" && exec 2> >(tee "${LAUNCHABLE_STDERR}")
|
||||
|
||||
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"} \
|
||||
RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS" \
|
||||
|
@ -195,11 +201,13 @@ jobs:
|
|||
timeout-minutes: 90
|
||||
env:
|
||||
RUBY_TESTOPTS: '-q --tty=no'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof,rbs,repl_type_completor'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
|
||||
PRECHECK_BUNDLED_GEMS: 'no'
|
||||
SYNTAX_SUGGEST_TIMEOUT: '5'
|
||||
YJIT_BINDGEN_DIFF_OPTS: '--exit-code'
|
||||
LIBCLANG_PATH: ${{ matrix.libclang_path }}
|
||||
LAUNCHABLE_STDOUT: ${{ steps.launchable.outputs.stdout_report_path }}
|
||||
LAUNCHABLE_STDERR: ${{ steps.launchable.outputs.stderr_report_path }}
|
||||
continue-on-error: ${{ matrix.continue-on-test_task || false }}
|
||||
|
||||
- name: Show ${{ github.event.pull_request.base.ref }} GitHub URL for yjit-bench comparison
|
||||
|
|
65
.github/workflows/zjit-macos.yml
vendored
65
.github/workflows/zjit-macos.yml
vendored
|
@ -33,16 +33,23 @@ jobs:
|
|||
matrix:
|
||||
include:
|
||||
- test_task: 'zjit-test'
|
||||
configure: '--enable-zjit=dev'
|
||||
configure: '--enable-yjit=dev --enable-zjit'
|
||||
|
||||
- test_task: 'test-all'
|
||||
- test_task: 'ruby' # build test for combo build
|
||||
configure: '--enable-yjit --enable-zjit'
|
||||
|
||||
- test_task: 'zjit-test-all'
|
||||
configure: '--enable-zjit=dev'
|
||||
testopts: '--seed=11831'
|
||||
|
||||
- test_task: 'btest'
|
||||
configure: '--enable-zjit=dev'
|
||||
tests: '../src/test/ruby/test_zjit.rb'
|
||||
|
||||
env:
|
||||
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
|
||||
RUN_OPTS: ${{ matrix.zjit_opts }}
|
||||
SPECOPTS: ${{ matrix.specopts }}
|
||||
TESTOPTS: ${{ matrix.testopts }}
|
||||
|
||||
runs-on: macos-14
|
||||
|
||||
|
@ -57,7 +64,7 @@ jobs:
|
|||
)}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
sparse-checkout-cone-mode: false
|
||||
sparse-checkout: /.github
|
||||
|
@ -90,19 +97,67 @@ jobs:
|
|||
|
||||
- run: make
|
||||
|
||||
- name: Verify that --zjit-dump-disasm works
|
||||
run: |
|
||||
./miniruby --zjit-call-threshold=1 --zjit-dump-disasm -e0 | \
|
||||
wc -l | \
|
||||
ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
|
||||
if: ${{ contains(matrix.configure, 'jit=dev') }}
|
||||
|
||||
- name: btest
|
||||
run: |
|
||||
RUST_BACKTRACE=1 ruby --disable=gems ../src/bootstraptest/runner.rb --ruby="./miniruby -I../src/lib -I. -I.ext/common --zjit-call-threshold=1" \
|
||||
../src/bootstraptest/test_attr.rb \
|
||||
../src/bootstraptest/test_autoload.rb \
|
||||
../src/bootstraptest/test_block.rb \
|
||||
../src/bootstraptest/test_class.rb \
|
||||
../src/bootstraptest/test_constant_cache.rb \
|
||||
../src/bootstraptest/test_env.rb \
|
||||
../src/bootstraptest/test_eval.rb \
|
||||
../src/bootstraptest/test_exception.rb \
|
||||
../src/bootstraptest/test_fiber.rb \
|
||||
../src/bootstraptest/test_finalizer.rb \
|
||||
../src/bootstraptest/test_flip.rb \
|
||||
../src/bootstraptest/test_flow.rb \
|
||||
../src/bootstraptest/test_fork.rb \
|
||||
../src/bootstraptest/test_gc.rb \
|
||||
../src/bootstraptest/test_insns.rb \
|
||||
../src/bootstraptest/test_io.rb \
|
||||
../src/bootstraptest/test_jump.rb \
|
||||
../src/bootstraptest/test_literal.rb \
|
||||
../src/bootstraptest/test_literal_suffix.rb \
|
||||
../src/bootstraptest/test_load.rb \
|
||||
../src/bootstraptest/test_marshal.rb \
|
||||
../src/bootstraptest/test_massign.rb \
|
||||
../src/bootstraptest/test_method.rb \
|
||||
../src/bootstraptest/test_objectspace.rb \
|
||||
../src/bootstraptest/test_proc.rb \
|
||||
../src/bootstraptest/test_ractor.rb \
|
||||
../src/bootstraptest/test_string.rb \
|
||||
../src/bootstraptest/test_struct.rb \
|
||||
../src/bootstraptest/test_syntax.rb \
|
||||
../src/bootstraptest/test_thread.rb \
|
||||
../src/bootstraptest/test_yjit_30k_ifelse.rb \
|
||||
../src/bootstraptest/test_yjit_30k_methods.rb \
|
||||
../src/bootstraptest/test_yjit_rust_port.rb
|
||||
# ../src/bootstraptest/test_yjit.rb \
|
||||
if: ${{ matrix.test_task == 'btest' }}
|
||||
|
||||
- name: make ${{ matrix.test_task }}
|
||||
run: >-
|
||||
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
|
||||
RUN_OPTS="$RUN_OPTS"
|
||||
SPECOPTS="$SPECOPTS"
|
||||
TESTOPTS="$TESTOPTS"
|
||||
timeout-minutes: 60
|
||||
env:
|
||||
RUBY_TESTOPTS: '-q --tty=no'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
|
||||
SYNTAX_SUGGEST_TIMEOUT: '5'
|
||||
PRECHECK_BUNDLED_GEMS: 'no'
|
||||
TESTS: ${{ matrix.tests }}
|
||||
continue-on-error: ${{ matrix.continue-on-test_task || false }}
|
||||
if: ${{ matrix.test_task != 'btest' }}
|
||||
|
||||
result:
|
||||
if: ${{ always() }}
|
||||
|
|
64
.github/workflows/zjit-ubuntu.yml
vendored
64
.github/workflows/zjit-ubuntu.yml
vendored
|
@ -38,17 +38,21 @@ jobs:
|
|||
libclang_path: '/usr/lib/llvm-14/lib/libclang.so.1'
|
||||
|
||||
- test_task: 'zjit-test'
|
||||
configure: '--enable-zjit=dev'
|
||||
configure: '--enable-yjit --enable-zjit=dev'
|
||||
|
||||
- test_task: 'test-all'
|
||||
- test_task: 'zjit-test-all'
|
||||
configure: '--enable-zjit=dev'
|
||||
testopts: '--seed=18140'
|
||||
|
||||
- test_task: 'btest'
|
||||
configure: '--enable-zjit=dev'
|
||||
tests: '../src/test/ruby/test_zjit.rb'
|
||||
|
||||
env:
|
||||
GITPULLOPTIONS: --no-tags origin ${{ github.ref }}
|
||||
RUN_OPTS: ${{ matrix.zjit_opts }}
|
||||
YJIT_BENCH_OPTS: ${{ matrix.yjit_bench_opts }}
|
||||
SPECOPTS: ${{ matrix.specopts }}
|
||||
TESTOPTS: ${{ matrix.testopts }}
|
||||
RUBY_DEBUG: ci
|
||||
BUNDLE_JOBS: 8 # for yjit-bench
|
||||
RUST_BACKTRACE: 1
|
||||
|
@ -66,14 +70,14 @@ jobs:
|
|||
)}}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@d632683dd7b4114ad314bca15554477dd762a938 # v4.2.0
|
||||
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
|
||||
with:
|
||||
sparse-checkout-cone-mode: false
|
||||
sparse-checkout: /.github
|
||||
|
||||
- uses: ./.github/actions/setup/ubuntu
|
||||
|
||||
- uses: ruby/setup-ruby@a6e6f86333f0a2523ece813039b8b4be04560854 # v1.190.0
|
||||
- uses: ruby/setup-ruby@a4effe49ee8ee5b8b5091268c473a4628afb5651 # v1.245.0
|
||||
with:
|
||||
ruby-version: '3.1'
|
||||
bundler: none
|
||||
|
@ -110,26 +114,74 @@ jobs:
|
|||
|
||||
- run: make
|
||||
|
||||
- name: Verify that --zjit-dump-disasm works
|
||||
run: |
|
||||
./miniruby --zjit-call-threshold=1 --zjit-dump-disasm -e0 | \
|
||||
wc -l | \
|
||||
ruby -ne 'raise "Disassembly seems broken in dev build (output has too few lines)" unless $_.to_i > 10'
|
||||
if: ${{ contains(matrix.configure, 'jit=dev') }}
|
||||
|
||||
# Check that the binary was built with ZJIT
|
||||
- name: Check ZJIT enabled
|
||||
run: ./miniruby --zjit -v | grep "+ZJIT"
|
||||
if: ${{ matrix.configure != '--disable-zjit' }}
|
||||
|
||||
- name: btest
|
||||
run: |
|
||||
RUST_BACKTRACE=1 ruby --disable=gems ../src/bootstraptest/runner.rb --ruby="./miniruby -I../src/lib -I. -I.ext/common --zjit-call-threshold=1" \
|
||||
../src/bootstraptest/test_attr.rb \
|
||||
../src/bootstraptest/test_autoload.rb \
|
||||
../src/bootstraptest/test_block.rb \
|
||||
../src/bootstraptest/test_class.rb \
|
||||
../src/bootstraptest/test_constant_cache.rb \
|
||||
../src/bootstraptest/test_env.rb \
|
||||
../src/bootstraptest/test_env.rb \
|
||||
../src/bootstraptest/test_exception.rb \
|
||||
../src/bootstraptest/test_fiber.rb \
|
||||
../src/bootstraptest/test_finalizer.rb \
|
||||
../src/bootstraptest/test_flip.rb \
|
||||
../src/bootstraptest/test_flow.rb \
|
||||
../src/bootstraptest/test_fork.rb \
|
||||
../src/bootstraptest/test_gc.rb \
|
||||
../src/bootstraptest/test_insns.rb \
|
||||
../src/bootstraptest/test_io.rb \
|
||||
../src/bootstraptest/test_jump.rb \
|
||||
../src/bootstraptest/test_literal.rb \
|
||||
../src/bootstraptest/test_literal_suffix.rb \
|
||||
../src/bootstraptest/test_load.rb \
|
||||
../src/bootstraptest/test_marshal.rb \
|
||||
../src/bootstraptest/test_massign.rb \
|
||||
../src/bootstraptest/test_method.rb \
|
||||
../src/bootstraptest/test_objectspace.rb \
|
||||
../src/bootstraptest/test_proc.rb \
|
||||
../src/bootstraptest/test_ractor.rb \
|
||||
../src/bootstraptest/test_string.rb \
|
||||
../src/bootstraptest/test_struct.rb \
|
||||
../src/bootstraptest/test_syntax.rb \
|
||||
../src/bootstraptest/test_thread.rb \
|
||||
../src/bootstraptest/test_yjit_30k_ifelse.rb \
|
||||
../src/bootstraptest/test_yjit_30k_methods.rb \
|
||||
../src/bootstraptest/test_yjit_rust_port.rb
|
||||
# ../src/bootstraptest/test_yjit.rb \
|
||||
if: ${{ matrix.test_task == 'btest' }}
|
||||
|
||||
- name: make ${{ matrix.test_task }}
|
||||
run: >-
|
||||
make -s ${{ matrix.test_task }} ${TESTS:+TESTS="$TESTS"}
|
||||
RUN_OPTS="$RUN_OPTS" MSPECOPT=--debug SPECOPTS="$SPECOPTS"
|
||||
TESTOPTS="$TESTOPTS"
|
||||
ZJIT_BINDGEN_DIFF_OPTS="$ZJIT_BINDGEN_DIFF_OPTS"
|
||||
timeout-minutes: 90
|
||||
env:
|
||||
RUBY_TESTOPTS: '-q --tty=no'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: 'typeprof'
|
||||
TEST_BUNDLED_GEMS_ALLOW_FAILURES: ''
|
||||
PRECHECK_BUNDLED_GEMS: 'no'
|
||||
SYNTAX_SUGGEST_TIMEOUT: '5'
|
||||
ZJIT_BINDGEN_DIFF_OPTS: '--exit-code'
|
||||
LIBCLANG_PATH: ${{ matrix.libclang_path }}
|
||||
TESTS: ${{ matrix.tests }}
|
||||
continue-on-error: ${{ matrix.continue-on-test_task || false }}
|
||||
if: ${{ matrix.test_task != 'btest' }}
|
||||
|
||||
result:
|
||||
if: ${{ always() }}
|
||||
|
|
3
.gitignore
vendored
3
.gitignore
vendored
|
@ -246,6 +246,9 @@ lcov*.info
|
|||
/yjit-bench
|
||||
/yjit_exit_locations.dump
|
||||
|
||||
# Rust
|
||||
/target
|
||||
|
||||
# /wasm/
|
||||
/wasm/tests/*.wasm
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ rdoc_include:
|
|||
|
||||
exclude:
|
||||
- \Alib/irb
|
||||
- .gemspec\z
|
||||
- \.gemspec\z
|
||||
|
||||
autolink_excluded_words:
|
||||
- Class
|
||||
|
@ -20,3 +20,5 @@ autolink_excluded_words:
|
|||
- RDoc
|
||||
- Ruby
|
||||
- Set
|
||||
|
||||
canonical_root: https://docs.ruby-lang.org/en/master
|
||||
|
|
89
Cargo.lock
generated
Normal file
89
Cargo.lock
generated
Normal file
|
@ -0,0 +1,89 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "capstone"
|
||||
version = "0.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "015ef5d5ca1743e3f94af9509ba6bd2886523cfee46e48d15c2ef5216fd4ac9a"
|
||||
dependencies = [
|
||||
"capstone-sys",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "capstone-sys"
|
||||
version = "0.17.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2267cb8d16a1e4197863ec4284ffd1aec26fe7e57c58af46b02590a0235809a0"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.2.18"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "525046617d8376e3db1deffb079e91cef90a89fc3ca5c185bbf8c9ecdd15cd5c"
|
||||
dependencies = [
|
||||
"shlex",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dissimilar"
|
||||
version = "1.0.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8975ffdaa0ef3661bfe02dbdcc06c9f829dfafe6a3c474de366a8d5e44276921"
|
||||
|
||||
[[package]]
|
||||
name = "expect-test"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63af43ff4431e848fb47472a920f14fa71c24de13255a5692e93d4e90302acb0"
|
||||
dependencies = [
|
||||
"dissimilar",
|
||||
"once_cell",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "jit"
|
||||
version = "0.0.0"
|
||||
dependencies = [
|
||||
"yjit",
|
||||
"zjit",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.171"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c19937216e9d3aa9956d9bb8dfc0b0c8beb6058fc4f7a4dc4d850edf86a237d6"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.21.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d"
|
||||
|
||||
[[package]]
|
||||
name = "shlex"
|
||||
version = "1.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "yjit"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"capstone",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zjit"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"capstone",
|
||||
"expect-test",
|
||||
]
|
51
Cargo.toml
Normal file
51
Cargo.toml
Normal file
|
@ -0,0 +1,51 @@
|
|||
# Using Cargo's workspace feature to build all the Rust code in
|
||||
# into a single package.
|
||||
# TODO(alan) notes about rust version requirements. Undecided yet.
|
||||
|
||||
[workspace]
|
||||
members = ["zjit", "yjit"]
|
||||
|
||||
[package]
|
||||
name = "jit"
|
||||
version = "0.0.0"
|
||||
edition = "2024"
|
||||
rust-version = "1.85.0"
|
||||
publish = false # Don't publish to crates.io
|
||||
|
||||
[dependencies]
|
||||
yjit = { path = "yjit", optional = true }
|
||||
zjit = { path = "zjit", optional = true }
|
||||
|
||||
[lib]
|
||||
crate-type = ["staticlib"]
|
||||
path = "jit.rs"
|
||||
|
||||
[features]
|
||||
disasm = ["yjit?/disasm", "zjit?/disasm"]
|
||||
runtime_checks = ["yjit?/runtime_checks", "zjit?/runtime_checks"]
|
||||
yjit = [ "dep:yjit" ]
|
||||
zjit = [ "dep:zjit" ]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
debug = true
|
||||
debug-assertions = true
|
||||
overflow-checks = true
|
||||
|
||||
[profile.dev_nodebug]
|
||||
inherits = "dev"
|
||||
|
||||
[profile.stats]
|
||||
inherits = "release"
|
||||
|
||||
[profile.release]
|
||||
# NOTE: --enable-yjit and zjit builds use `rustc` without going through Cargo. You
|
||||
# might want to update the `rustc` invocation if you change this profile.
|
||||
opt-level = 3
|
||||
# The extra robustness that comes from checking for arithmetic overflow is
|
||||
# worth the performance cost for the compiler.
|
||||
overflow-checks = true
|
||||
# Generate debug info
|
||||
debug = true
|
||||
# Use ThinLTO. Much smaller output for a small amount of build time increase.
|
||||
lto = "thin"
|
155
NEWS.md
155
NEWS.md
|
@ -14,17 +14,86 @@ Note that each entry is kept to a minimum, see links for details.
|
|||
|
||||
Note: We're only listing outstanding class updates.
|
||||
|
||||
* Kernel
|
||||
|
||||
* `Kernel#inspect` now checks for the existence of a `#instance_variables_to_inspect` method,
|
||||
allowing control over which instance variables are displayed in the `#inspect` string:
|
||||
|
||||
```ruby
|
||||
class DatabaseConfig
|
||||
def initialize(host, user, password)
|
||||
@host = host
|
||||
@user = user
|
||||
@password = password
|
||||
end
|
||||
|
||||
private def instance_variables_to_inspect = [:@host, :@user]
|
||||
end
|
||||
|
||||
conf = DatabaseConfig.new("localhost", "root", "hunter2")
|
||||
conf.inspect #=> #<DatabaseConfig:0x0000000104def350 @host="localhost", @user="root">
|
||||
```
|
||||
|
||||
[[Feature #21219]]
|
||||
|
||||
* Binding
|
||||
|
||||
* `Binding#local_variables` does no longer include numbered parameters.
|
||||
Also, `Binding#local_variable_get` and `Binding#local_variable_set` reject to handle numbered parameters.
|
||||
[[Bug #21049]]
|
||||
Also, `Binding#local_variable_get` and `Binding#local_variable_set` reject
|
||||
to handle numbered parameters. [[Bug #21049]]
|
||||
|
||||
* IO
|
||||
|
||||
* `IO.select` accepts +Float::INFINITY+ as a timeout argument.
|
||||
[[Feature #20610]]
|
||||
|
||||
* Socket
|
||||
|
||||
* `Socket.tcp` & `TCPSocket.new` accepts `open_timeout` as a keyword argument to specify
|
||||
the timeout for the initial connection. [[Feature #21347]]
|
||||
|
||||
* Ractor
|
||||
|
||||
* `Ractor::Port` class was added for a new synchronization mechanism
|
||||
to communicate between Ractors. [[Feature #21262]]
|
||||
|
||||
```ruby
|
||||
port1 = Ractor::Port.new
|
||||
port2 = Ractor::Port.new
|
||||
Ractor.new port1, port2 do |port1, port2|
|
||||
port1 << 1
|
||||
port2 << 11
|
||||
port1 << 2
|
||||
port2 << 12
|
||||
end
|
||||
2.times{ p port1.receive } #=> 1, 2
|
||||
2.times{ p port2.receive } #=> 11, 12
|
||||
```
|
||||
|
||||
`Ractor::Port` provides the following methods:
|
||||
|
||||
* `Ractor::Port#receive`
|
||||
* `Ractor::Port#send` (or `Ractor::Port#<<`)
|
||||
* `Ractor::Port#close`
|
||||
* `Ractor::Port#closed?`
|
||||
|
||||
As result, `Ractor.yield` and `Ractor#take` were removed.
|
||||
|
||||
* `Ractor#join` and `Ractor#value` were added to wait for the
|
||||
termination of a Ractor. These are similar to `Thread#join`
|
||||
and `Thread#value`.
|
||||
|
||||
* `Ractor#monitor` and `Ractor#unmonitor` were added as low-level
|
||||
interfaces used internally to implement `Ractor#join`.
|
||||
|
||||
* `Ractor.select` now only accepts Ractors and Ports. If Ractors are given,
|
||||
it returns when a Ractor terminates.
|
||||
|
||||
* `Ractor#default_port` was added. Each `Ractor` has a default port,
|
||||
which is used by `Ractor.send`, `Ractor.receive`.
|
||||
|
||||
* `Ractor#close_incoming` and `Ractor#close_outgoing` were removed.
|
||||
|
||||
* Set
|
||||
|
||||
* Set is now a core class, instead of an autoloaded stdlib class.
|
||||
|
@ -32,18 +101,30 @@ Note: We're only listing outstanding class updates.
|
|||
|
||||
* String
|
||||
|
||||
* Update Unicode to Version 16.0.0 and Emoji Version 16.0. [[Feature #19908]][[Feature #20724]]
|
||||
(also applies to Regexp)
|
||||
* Update Unicode to Version 16.0.0 and Emoji Version 16.0.
|
||||
[[Feature #19908]][[Feature #20724]] (also applies to Regexp)
|
||||
|
||||
* Fiber::Scheduler
|
||||
|
||||
* Introduce `Fiber::Scheduler#fiber_interrupt` to interrupt a fiber with a
|
||||
given exception. The initial use case is to interrupt a fiber that is
|
||||
waiting on a blocking IO operation when the IO operation is closed.
|
||||
[[Feature #21166]]
|
||||
|
||||
* Pathname
|
||||
|
||||
* Pathname has been promoted from a default gem to a core class of Ruby.
|
||||
[[Feature #17473]]
|
||||
|
||||
## Stdlib updates
|
||||
|
||||
The following bundled gems are promoted from default gems.
|
||||
|
||||
* ostruct 0.6.1
|
||||
* ostruct 0.6.3
|
||||
* pstore 0.2.0
|
||||
* benchmark 0.4.0
|
||||
* benchmark 0.4.1
|
||||
* logger 1.7.0
|
||||
* rdoc 6.13.1
|
||||
* rdoc 6.14.2
|
||||
* win32ole 1.9.2
|
||||
* irb 1.15.2
|
||||
* reline 0.6.1
|
||||
|
@ -52,7 +133,9 @@ The following bundled gems are promoted from default gems.
|
|||
|
||||
We only list stdlib changes that are notable feature changes.
|
||||
|
||||
Other changes are listed in the following sections. we also listed release history from the previous bundled version that is Ruby 3.3.0 if it has GitHub releases.
|
||||
Other changes are listed in the following sections. We also listed release
|
||||
history from the previous bundled version that is Ruby 3.3.0 if it has GitHub
|
||||
releases.
|
||||
|
||||
The following default gem is added.
|
||||
|
||||
|
@ -60,16 +143,22 @@ The following default gem is added.
|
|||
|
||||
The following default gems are updated.
|
||||
|
||||
* RubyGems 3.7.0.dev
|
||||
* bundler 2.7.0.dev
|
||||
* erb 5.0.0
|
||||
* json 2.12.0
|
||||
* RubyGems 3.8.0.dev
|
||||
* bundler 2.8.0.dev
|
||||
* erb 5.0.2
|
||||
* etc 1.4.6
|
||||
* io-console 0.8.1
|
||||
* io-nonblock 0.3.2
|
||||
* io-wait 0.3.2
|
||||
* json 2.12.2
|
||||
* optparse 0.7.0.dev.2
|
||||
* prism 1.4.0
|
||||
* psych 5.2.6
|
||||
* resolv 0.6.2
|
||||
* stringio 3.1.8.dev
|
||||
* strscan 3.1.5.dev
|
||||
* strscan 3.1.6.dev
|
||||
* uri 1.0.3
|
||||
* weakref 0.1.4
|
||||
|
||||
The following bundled gems are added.
|
||||
|
||||
|
@ -77,30 +166,52 @@ The following bundled gems are added.
|
|||
The following bundled gems are updated.
|
||||
|
||||
* minitest 5.25.5
|
||||
* test-unit 3.6.8
|
||||
* rake 13.3.0
|
||||
* test-unit 3.7.0
|
||||
* rexml 3.4.1
|
||||
* net-imap 0.5.8
|
||||
* net-imap 0.5.9
|
||||
* net-smtp 0.5.1
|
||||
* rbs 3.9.3
|
||||
* bigdecimal 3.1.9
|
||||
* matrix 0.4.3
|
||||
* prime 0.1.4
|
||||
* rbs 3.9.4
|
||||
* debug 1.11.0
|
||||
* base64 0.3.0
|
||||
* bigdecimal 3.2.2
|
||||
* drb 2.2.3
|
||||
* syslog 0.3.0
|
||||
* csv 3.3.4
|
||||
* csv 3.3.5
|
||||
* repl_type_completor 0.1.11
|
||||
|
||||
## Supported platforms
|
||||
|
||||
## Compatibility issues
|
||||
|
||||
* The following methods were removed from Ractor due because of `Ractor::Port`:
|
||||
|
||||
* `Ractor.yield`
|
||||
* `Ractor#take`
|
||||
* `Ractor#close_incoming`
|
||||
* `Ractor#close_outgoging`
|
||||
|
||||
[[Feature #21262]]
|
||||
|
||||
## Stdlib compatibility issues
|
||||
|
||||
* CGI library is removed from the default gems. Now we only provide `cgi/escape` for
|
||||
the following methods:
|
||||
|
||||
* `CGI.escape` and `CGI.unescape`
|
||||
* `CGI.escapeHTML` and `CGI.unescapeHTML`
|
||||
* `CGI.escapeURIComponent` and `CGI.unescapeURIComponent`
|
||||
* `CGI.escapeElement` and `CGI.unescapeElement`
|
||||
|
||||
[[Feature #21258]]
|
||||
|
||||
* With the move of `Set` from stdlib to core class, `set/sorted_set.rb` has
|
||||
been removed, and `SortedSet` is no longer an autoloaded constant. Please
|
||||
install the `sorted_set` gem and `require 'sorted_set'` to use `SortedSet`.
|
||||
[[Feature #21287]]
|
||||
|
||||
## C API updates
|
||||
|
||||
* IO
|
||||
|
@ -110,7 +221,7 @@ The following bundled gems are updated.
|
|||
using `RUBY_IO_MODE_EXTERNAL` and use `rb_io_close(io)` to close it (this
|
||||
also interrupts and waits for all pending operations on the `IO`
|
||||
instance). Directly closing file descriptors does not interrupt pending
|
||||
operations, and may lead to undefined beahviour. In other words, if two
|
||||
operations, and may lead to undefined behaviour. In other words, if two
|
||||
`IO` objects share the same file descriptor, closing one does not affect
|
||||
the other. [[Feature #18455]]
|
||||
|
||||
|
@ -118,11 +229,17 @@ The following bundled gems are updated.
|
|||
|
||||
## JIT
|
||||
|
||||
[Feature #17473]: https://bugs.ruby-lang.org/issues/17473
|
||||
[Feature #18455]: https://bugs.ruby-lang.org/issues/18455
|
||||
[Feature #19908]: https://bugs.ruby-lang.org/issues/19908
|
||||
[Feature #20610]: https://bugs.ruby-lang.org/issues/20610
|
||||
[Feature #20724]: https://bugs.ruby-lang.org/issues/20724
|
||||
[Feature #21047]: https://bugs.ruby-lang.org/issues/21047
|
||||
[Bug #21049]: https://bugs.ruby-lang.org/issues/21049
|
||||
[Feature #21166]: https://bugs.ruby-lang.org/issues/21166
|
||||
[Feature #21216]: https://bugs.ruby-lang.org/issues/21216
|
||||
[Feature #21219]: https://bugs.ruby-lang.org/issues/21219
|
||||
[Feature #21258]: https://bugs.ruby-lang.org/issues/21258
|
||||
[Feature #21262]: https://bugs.ruby-lang.org/issues/21262
|
||||
[Feature #21287]: https://bugs.ruby-lang.org/issues/21287
|
||||
[Feature #21347]: https://bugs.ruby-lang.org/issues/21347
|
||||
|
|
3
array.c
3
array.c
|
@ -3439,10 +3439,9 @@ rb_ary_sort_bang(VALUE ary)
|
|||
ARY_SET_CAPA(ary, ARY_HEAP_LEN(tmp));
|
||||
}
|
||||
/* tmp was lost ownership for the ptr */
|
||||
FL_UNSET(tmp, FL_FREEZE);
|
||||
FL_SET_EMBED(tmp);
|
||||
ARY_SET_EMBED_LEN(tmp, 0);
|
||||
FL_SET(tmp, FL_FREEZE);
|
||||
OBJ_FREEZE(tmp);
|
||||
}
|
||||
/* tmp will be GC'ed. */
|
||||
RBASIC_SET_CLASS_RAW(tmp, rb_cArray); /* rb_cArray must be marked */
|
||||
|
|
10
ast.c
10
ast.c
|
@ -812,6 +812,16 @@ node_locations(VALUE ast_value, const NODE *node)
|
|||
location_new(&RNODE_CLASS(node)->class_keyword_loc),
|
||||
location_new(&RNODE_CLASS(node)->inheritance_operator_loc),
|
||||
location_new(&RNODE_CLASS(node)->end_keyword_loc));
|
||||
case NODE_COLON2:
|
||||
return rb_ary_new_from_args(3,
|
||||
location_new(nd_code_loc(node)),
|
||||
location_new(&RNODE_COLON2(node)->delimiter_loc),
|
||||
location_new(&RNODE_COLON2(node)->name_loc));
|
||||
case NODE_COLON3:
|
||||
return rb_ary_new_from_args(3,
|
||||
location_new(nd_code_loc(node)),
|
||||
location_new(&RNODE_COLON3(node)->delimiter_loc),
|
||||
location_new(&RNODE_COLON3(node)->name_loc));
|
||||
case NODE_DOT2:
|
||||
return rb_ary_new_from_args(2,
|
||||
location_new(nd_code_loc(node)),
|
||||
|
|
|
@ -40,7 +40,7 @@ Usage: benchmark-driver [options] RUBY|YAML...
|
|||
--filter REGEXP Filter out benchmarks with given regexp
|
||||
--run-duration SECONDS Warmup estimates loop_count to run for this duration (default: 3)
|
||||
--timeout SECONDS Timeout ruby command execution with timeout(1)
|
||||
-v, --verbose Verbose mode. Multiple -v options increase visilibity (max: 2)
|
||||
-v, --verbose Verbose mode. Multiple -v options increase visibility (max: 2)
|
||||
```
|
||||
|
||||
## make benchmark
|
||||
|
|
23
benchmark/class_superclass.yml
Normal file
23
benchmark/class_superclass.yml
Normal file
|
@ -0,0 +1,23 @@
|
|||
prelude: |
|
||||
class SimpleClass; end
|
||||
class OneModuleClass
|
||||
1.times { include Module.new }
|
||||
end
|
||||
class MediumClass
|
||||
10.times { include Module.new }
|
||||
end
|
||||
class LargeClass
|
||||
100.times { include Module.new }
|
||||
end
|
||||
benchmark:
|
||||
object_class_superclass: |
|
||||
Object.superclass
|
||||
simple_class_superclass: |
|
||||
SimpleClass.superclass
|
||||
one_module_class: |
|
||||
OneModuleClass.superclass
|
||||
medium_class_superclass: |
|
||||
MediumClass.superclass
|
||||
large_class_superclass: |
|
||||
LargeClass.superclass
|
||||
loop_count: 20000000
|
13
benchmark/io_close.yml
Normal file
13
benchmark/io_close.yml
Normal file
|
@ -0,0 +1,13 @@
|
|||
prelude: |
|
||||
ios = 1000.times.map do
|
||||
100.times.map{IO.pipe}
|
||||
end
|
||||
benchmark:
|
||||
# Close IO
|
||||
io_close: |
|
||||
# Process each batch of ios per iteration of the benchmark.
|
||||
ios.pop.each do |r, w|
|
||||
r.close
|
||||
w.close
|
||||
end
|
||||
loop_count: 100
|
21
benchmark/io_close_contended.yml
Normal file
21
benchmark/io_close_contended.yml
Normal file
|
@ -0,0 +1,21 @@
|
|||
prelude: |
|
||||
ios = 100.times.map do
|
||||
10.times.map do
|
||||
pipe = IO.pipe.tap do |r, w|
|
||||
Thread.new do
|
||||
r.read
|
||||
rescue IOError
|
||||
# Ignore
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
benchmark:
|
||||
# Close IO
|
||||
io_close_contended: |
|
||||
# Process each batch of ios per iteration of the benchmark.
|
||||
ios.pop.each do |r, w|
|
||||
r.close
|
||||
w.close
|
||||
end
|
||||
loop_count: 10
|
|
@ -87,7 +87,7 @@ __bmdv_ractors << Ractor.new(__bmdv_loop_after - __bmdv_loop_before) { |__bmdv_l
|
|||
<% end %>
|
||||
|
||||
# Wait for all Ractors before executing code to write results
|
||||
__bmdv_ractors.map!(&:take)
|
||||
__bmdv_ractors.map!(&:value)
|
||||
|
||||
<% results.each do |result| %>
|
||||
File.write(<%= result.dump %>, __bmdv_ractors.shift)
|
||||
|
|
|
@ -1,10 +1,16 @@
|
|||
prelude: |
|
||||
def a = nil
|
||||
benchmark:
|
||||
rationalize:
|
||||
nil.rationalize
|
||||
to_c: |
|
||||
nil.to_c
|
||||
to_i: |
|
||||
nil.to_i
|
||||
to_f: |
|
||||
nil.to_f
|
||||
to_r: |
|
||||
nil.to_r
|
||||
splat: |
|
||||
a(*nil)
|
||||
loop_count: 100000
|
||||
|
|
|
@ -625,6 +625,8 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
|
|||
end
|
||||
end
|
||||
|
||||
class Timeout < StandardError; end
|
||||
|
||||
def get_result_string(opt = '', timeout: BT.timeout, **argh)
|
||||
if BT.ruby
|
||||
timeout = BT.apply_timeout_scale(timeout)
|
||||
|
@ -634,7 +636,11 @@ class Assertion < Struct.new(:src, :path, :lineno, :proc)
|
|||
out = IO.popen("#{BT.ruby} -W0 #{opt} #{filename}", **kw)
|
||||
pid = out.pid
|
||||
th = Thread.new {out.read.tap {Process.waitpid(pid); out.close}}
|
||||
th.value if th.join(timeout)
|
||||
if th.join(timeout)
|
||||
th.value
|
||||
else
|
||||
Timeout.new("timed out after #{timeout} seconds")
|
||||
end
|
||||
ensure
|
||||
raise Interrupt if $? and $?.signaled? && $?.termsig == Signal.list["INT"]
|
||||
|
||||
|
@ -891,4 +897,8 @@ def yjit_enabled?
|
|||
ENV.key?('RUBY_YJIT_ENABLE') || ENV.fetch('RUN_OPTS', '').include?('yjit') || BT.ruby.include?('yjit')
|
||||
end
|
||||
|
||||
def zjit_enabled?
|
||||
ENV.key?('RUBY_ZJIT_ENABLE') || ENV.fetch('RUN_OPTS', '').include?('zjit') || BT.ruby.include?('zjit')
|
||||
end
|
||||
|
||||
exit main
|
||||
|
|
|
@ -37,3 +37,8 @@ assert_normal_exit %q{
|
|||
assert_normal_exit %q{
|
||||
Fiber.new(&Object.method(:class_eval)).resume("foo")
|
||||
}, '[ruby-dev:34128]'
|
||||
|
||||
# [Bug #21400]
|
||||
assert_normal_exit %q{
|
||||
Thread.new { Fiber.current.kill }.join
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -220,7 +220,7 @@ assert_equal 'Sub', %q{
|
|||
call(Sub.new('o')).class
|
||||
}
|
||||
|
||||
# String#dup with FL_EXIVAR
|
||||
# String#dup with generic ivars
|
||||
assert_equal '["str", "ivar"]', %q{
|
||||
def str_dup(str) = str.dup
|
||||
str = "str"
|
||||
|
@ -3018,15 +3018,16 @@ assert_equal '[:itself]', %q{
|
|||
itself
|
||||
end
|
||||
|
||||
tracing_ractor = Ractor.new do
|
||||
port = Ractor::Port.new
|
||||
tracing_ractor = Ractor.new port do |port|
|
||||
# 1: start tracing
|
||||
events = []
|
||||
tp = TracePoint.new(:c_call) { events << _1.method_id }
|
||||
tp.enable
|
||||
Ractor.yield(nil)
|
||||
port << nil
|
||||
|
||||
# 3: run compiled method on tracing ractor
|
||||
Ractor.yield(nil)
|
||||
port << nil
|
||||
traced_method
|
||||
|
||||
events
|
||||
|
@ -3034,13 +3035,13 @@ assert_equal '[:itself]', %q{
|
|||
tp&.disable
|
||||
end
|
||||
|
||||
tracing_ractor.take
|
||||
port.receive
|
||||
|
||||
# 2: compile on non tracing ractor
|
||||
traced_method
|
||||
|
||||
tracing_ractor.take
|
||||
tracing_ractor.take
|
||||
port.receive
|
||||
tracing_ractor.value
|
||||
}
|
||||
|
||||
# Try to hit a lazy branch stub while another ractor enables tracing
|
||||
|
@ -3054,17 +3055,18 @@ assert_equal '42', %q{
|
|||
end
|
||||
end
|
||||
|
||||
ractor = Ractor.new do
|
||||
port = Ractor::Port.new
|
||||
ractor = Ractor.new port do |port|
|
||||
compiled(false)
|
||||
Ractor.yield(nil)
|
||||
port << nil
|
||||
compiled(41)
|
||||
end
|
||||
|
||||
tp = TracePoint.new(:line) { itself }
|
||||
ractor.take
|
||||
port.receive
|
||||
tp.enable
|
||||
|
||||
ractor.take
|
||||
ractor.value
|
||||
}
|
||||
|
||||
# Test equality with changing types
|
||||
|
@ -3140,7 +3142,7 @@ assert_equal '42', %q{
|
|||
A.foo
|
||||
A.foo
|
||||
|
||||
Ractor.new { A.foo }.take
|
||||
Ractor.new { A.foo }.value
|
||||
}
|
||||
|
||||
assert_equal '["plain", "special", "sub", "plain"]', %q{
|
||||
|
@ -3859,36 +3861,6 @@ assert_equal '3,12', %q{
|
|||
pt_inspect(p)
|
||||
}
|
||||
|
||||
# Regression test for deadlock between branch_stub_hit and ractor_receive_if
|
||||
assert_equal '10', %q{
|
||||
r = Ractor.new Ractor.current do |main|
|
||||
main << 1
|
||||
main << 2
|
||||
main << 3
|
||||
main << 4
|
||||
main << 5
|
||||
main << 6
|
||||
main << 7
|
||||
main << 8
|
||||
main << 9
|
||||
main << 10
|
||||
end
|
||||
|
||||
a = []
|
||||
a << Ractor.receive_if{|msg| msg == 10}
|
||||
a << Ractor.receive_if{|msg| msg == 9}
|
||||
a << Ractor.receive_if{|msg| msg == 8}
|
||||
a << Ractor.receive_if{|msg| msg == 7}
|
||||
a << Ractor.receive_if{|msg| msg == 6}
|
||||
a << Ractor.receive_if{|msg| msg == 5}
|
||||
a << Ractor.receive_if{|msg| msg == 4}
|
||||
a << Ractor.receive_if{|msg| msg == 3}
|
||||
a << Ractor.receive_if{|msg| msg == 2}
|
||||
a << Ractor.receive_if{|msg| msg == 1}
|
||||
|
||||
a.length
|
||||
}
|
||||
|
||||
# checktype
|
||||
assert_equal 'false', %q{
|
||||
def function()
|
||||
|
|
|
@ -374,7 +374,7 @@ assert_equal 'ok', %q{
|
|||
r = Ractor.new do
|
||||
'ok'
|
||||
end
|
||||
r.take
|
||||
r.value
|
||||
}
|
||||
|
||||
# Passed arguments to Ractor.new will be a block parameter
|
||||
|
@ -384,7 +384,7 @@ assert_equal 'ok', %q{
|
|||
r = Ractor.new 'ok' do |msg|
|
||||
msg
|
||||
end
|
||||
r.take
|
||||
r.value
|
||||
}
|
||||
|
||||
# Pass multiple arguments to Ractor.new
|
||||
|
@ -393,7 +393,7 @@ assert_equal 'ok', %q{
|
|||
r = Ractor.new 'ping', 'pong' do |msg, msg2|
|
||||
[msg, msg2]
|
||||
end
|
||||
'ok' if r.take == ['ping', 'pong']
|
||||
'ok' if r.value == ['ping', 'pong']
|
||||
}
|
||||
|
||||
# Ractor#send passes an object with copy to a Ractor
|
||||
|
@ -403,7 +403,7 @@ assert_equal 'ok', %q{
|
|||
msg = Ractor.receive
|
||||
end
|
||||
r.send 'ok'
|
||||
r.take
|
||||
r.value
|
||||
}
|
||||
|
||||
assert_equal '[1, 2, 3]', %q{
|
||||
|
|
200
class.c
200
class.c
|
@ -42,10 +42,10 @@
|
|||
* 2: RCLASS_PRIME_CLASSEXT_PRIME_WRITABLE
|
||||
* This class's prime classext is the only classext and writable from any namespaces.
|
||||
* If unset, the prime classext is writable only from the root namespace.
|
||||
* if !SHAPE_IN_BASIC_FLAGS
|
||||
* 4-19: SHAPE_FLAG_MASK
|
||||
* Shape ID for the class.
|
||||
* endif
|
||||
* 3: RCLASS_IS_INITIALIZED
|
||||
* Class has been initialized.
|
||||
* 4: RCLASS_NAMESPACEABLE
|
||||
* Is a builtin class that may be namespaced. It larger than a normal class.
|
||||
*/
|
||||
|
||||
/* Flags of T_ICLASS
|
||||
|
@ -53,10 +53,8 @@
|
|||
* 2: RCLASS_PRIME_CLASSEXT_PRIME_WRITABLE
|
||||
* This module's prime classext is the only classext and writable from any namespaces.
|
||||
* If unset, the prime classext is writable only from the root namespace.
|
||||
* if !SHAPE_IN_BASIC_FLAGS
|
||||
* 4-19: SHAPE_FLAG_MASK
|
||||
* Shape ID. This is set but not used.
|
||||
* endif
|
||||
* 4: RCLASS_NAMESPACEABLE
|
||||
* Is a builtin class that may be namespaced. It larger than a normal class.
|
||||
*/
|
||||
|
||||
/* Flags of T_MODULE
|
||||
|
@ -64,17 +62,15 @@
|
|||
* 0: RCLASS_IS_ROOT
|
||||
* The class has been added to the VM roots. Will always be marked and pinned.
|
||||
* This is done for classes defined from C to allow storing them in global variables.
|
||||
* 1: RMODULE_ALLOCATED_BUT_NOT_INITIALIZED
|
||||
* Module has not been initialized.
|
||||
* 1: RMODULE_IS_REFINEMENT
|
||||
* Module is used for refinements.
|
||||
* 2: RCLASS_PRIME_CLASSEXT_PRIME_WRITABLE
|
||||
* This module's prime classext is the only classext and writable from any namespaces.
|
||||
* If unset, the prime classext is writable only from the root namespace.
|
||||
* 3: RMODULE_IS_REFINEMENT
|
||||
* Module is used for refinements.
|
||||
* if !SHAPE_IN_BASIC_FLAGS
|
||||
* 4-19: SHAPE_FLAG_MASK
|
||||
* Shape ID for the module.
|
||||
* endif
|
||||
* 3: RCLASS_IS_INITIALIZED
|
||||
* Module has been initialized.
|
||||
* 4: RCLASS_NAMESPACEABLE
|
||||
* Is a builtin class that may be namespaced. It larger than a normal class.
|
||||
*/
|
||||
|
||||
#define METACLASS_OF(k) RBASIC(k)->klass
|
||||
|
@ -183,16 +179,6 @@ duplicate_classext_const_tbl(struct rb_id_table *src, VALUE klass)
|
|||
return dst;
|
||||
}
|
||||
|
||||
static void
|
||||
duplicate_classext_superclasses(rb_classext_t *orig, rb_classext_t *copy)
|
||||
{
|
||||
RCLASSEXT_SUPERCLASSES(copy) = RCLASSEXT_SUPERCLASSES(orig);
|
||||
RCLASSEXT_SUPERCLASS_DEPTH(copy) = RCLASSEXT_SUPERCLASS_DEPTH(orig);
|
||||
// the copy is always not the owner and the orig (or its parent class) will maintain the superclasses array
|
||||
RCLASSEXT_SUPERCLASSES_OWNER(copy) = false;
|
||||
RCLASSEXT_SUPERCLASSES_WITH_SELF(copy) = RCLASSEXT_SUPERCLASSES_WITH_SELF(orig);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
namespace_subclasses_tbl_key(const rb_namespace_t *ns)
|
||||
{
|
||||
|
@ -256,6 +242,8 @@ duplicate_classext_subclasses(rb_classext_t *orig, rb_classext_t *copy)
|
|||
static void
|
||||
class_duplicate_iclass_classext(VALUE iclass, rb_classext_t *mod_ext, const rb_namespace_t *ns)
|
||||
{
|
||||
RUBY_ASSERT(RB_TYPE_P(iclass, T_ICLASS));
|
||||
|
||||
rb_classext_t *src = RCLASS_EXT_PRIME(iclass);
|
||||
rb_classext_t *ext = RCLASS_EXT_TABLE_LOOKUP_INTERNAL(iclass, ns);
|
||||
int first_set = 0;
|
||||
|
@ -278,7 +266,7 @@ class_duplicate_iclass_classext(VALUE iclass, rb_classext_t *mod_ext, const rb_n
|
|||
else {
|
||||
RCLASSEXT_M_TBL(ext) = RCLASSEXT_M_TBL(mod_ext);
|
||||
}
|
||||
RCLASSEXT_FIELDS(ext) = (VALUE *)st_init_numtable();
|
||||
|
||||
RCLASSEXT_CONST_TBL(ext) = RCLASSEXT_CONST_TBL(mod_ext);
|
||||
RCLASSEXT_CVC_TBL(ext) = RCLASSEXT_CVC_TBL(mod_ext);
|
||||
|
||||
|
@ -315,13 +303,8 @@ rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_namespace
|
|||
|
||||
RCLASSEXT_M_TBL(ext) = duplicate_classext_m_tbl(RCLASSEXT_M_TBL(orig), klass, dup_iclass);
|
||||
|
||||
// TODO: consider shapes for performance
|
||||
if (RCLASSEXT_FIELDS(orig)) {
|
||||
RCLASSEXT_FIELDS(ext) = (VALUE *)st_copy((st_table *)RCLASSEXT_FIELDS(orig));
|
||||
rb_autoload_copy_table_for_namespace((st_table *)RCLASSEXT_FIELDS(ext), ns);
|
||||
}
|
||||
else {
|
||||
RCLASSEXT_FIELDS(ext) = (VALUE *)st_init_numtable();
|
||||
if (orig->fields_obj) {
|
||||
RB_OBJ_WRITE(klass, &ext->fields_obj, rb_imemo_fields_clone(orig->fields_obj));
|
||||
}
|
||||
|
||||
if (RCLASSEXT_SHARED_CONST_TBL(orig)) {
|
||||
|
@ -344,9 +327,6 @@ rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_namespace
|
|||
|
||||
RCLASSEXT_CVC_TBL(ext) = duplicate_classext_id_table(RCLASSEXT_CVC_TBL(orig), dup_iclass);
|
||||
|
||||
// superclass_depth, superclasses
|
||||
duplicate_classext_superclasses(orig, ext);
|
||||
|
||||
// subclasses, subclasses_index
|
||||
duplicate_classext_subclasses(orig, ext);
|
||||
|
||||
|
@ -356,9 +336,9 @@ rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_namespace
|
|||
* * refined_class
|
||||
* * as.class.allocator / as.singleton_class.attached_object
|
||||
* * includer
|
||||
* * max IV count
|
||||
* * variation count
|
||||
*/
|
||||
RCLASSEXT_MAX_IV_COUNT(ext) = RCLASSEXT_MAX_IV_COUNT(orig);
|
||||
RCLASSEXT_VARIATION_COUNT(ext) = RCLASSEXT_VARIATION_COUNT(orig);
|
||||
RCLASSEXT_PERMANENT_CLASSPATH(ext) = RCLASSEXT_PERMANENT_CLASSPATH(orig);
|
||||
RCLASSEXT_CLONED(ext) = RCLASSEXT_CLONED(orig);
|
||||
RCLASSEXT_CLASSPATH(ext) = RCLASSEXT_CLASSPATH(orig);
|
||||
|
@ -378,6 +358,8 @@ rb_class_duplicate_classext(rb_classext_t *orig, VALUE klass, const rb_namespace
|
|||
if (subclass_entry->klass && RB_TYPE_P(subclass_entry->klass, T_ICLASS)) {
|
||||
iclass = subclass_entry->klass;
|
||||
if (RBASIC_CLASS(iclass) == klass) {
|
||||
// Is the subclass an ICLASS including this module into another class
|
||||
// If so we need to re-associate it under our namespace with the new ext
|
||||
class_duplicate_iclass_classext(iclass, ext, ns);
|
||||
}
|
||||
}
|
||||
|
@ -412,7 +394,7 @@ class_classext_foreach_i(st_data_t key, st_data_t value, st_data_t arg)
|
|||
void
|
||||
rb_class_classext_foreach(VALUE klass, rb_class_classext_foreach_callback_func *func, void *arg)
|
||||
{
|
||||
st_table *tbl = RCLASS(klass)->ns_classext_tbl;
|
||||
st_table *tbl = RCLASS_CLASSEXT_TBL(klass);
|
||||
struct class_classext_foreach_arg foreach_arg;
|
||||
if (tbl) {
|
||||
foreach_arg.func = func;
|
||||
|
@ -452,8 +434,7 @@ push_subclass_entry_to_list(VALUE super, VALUE klass, bool is_module)
|
|||
entry = ZALLOC(rb_subclass_entry_t);
|
||||
entry->klass = klass;
|
||||
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
RB_VM_LOCKING() {
|
||||
anchor = RCLASS_WRITABLE_SUBCLASSES(super);
|
||||
VM_ASSERT(anchor);
|
||||
ns_subclasses = (rb_ns_subclasses_t *)anchor->ns_subclasses;
|
||||
|
@ -470,7 +451,6 @@ push_subclass_entry_to_list(VALUE super, VALUE klass, bool is_module)
|
|||
entry->prev = head;
|
||||
st_insert(tbl, namespace_subclasses_tbl_key(ns), (st_data_t)entry);
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
|
||||
if (is_module) {
|
||||
RCLASS_WRITE_NS_MODULE_SUBCLASSES(klass, anchor->ns_subclasses);
|
||||
|
@ -654,24 +634,30 @@ class_switch_superclass(VALUE super, VALUE klass)
|
|||
}
|
||||
|
||||
/**
|
||||
* Allocates a struct RClass for a new class.
|
||||
* Allocates a struct RClass for a new class, iclass, or module.
|
||||
*
|
||||
* @param flags initial value for basic.flags of the returned class.
|
||||
* @param klass the class of the returned class.
|
||||
* @return an uninitialized Class object.
|
||||
* @pre `klass` must refer `Class` class or an ancestor of Class.
|
||||
* @pre `(flags | T_CLASS) != 0`
|
||||
* @post the returned class can safely be `#initialize` 'd.
|
||||
* @param type The type of the RClass (T_CLASS, T_ICLASS, or T_MODULE)
|
||||
* @param klass value for basic.klass of the returned object.
|
||||
* @return an uninitialized Class/IClass/Module object.
|
||||
* @pre `klass` must refer to a class or module
|
||||
*
|
||||
* @note this function is not Class#allocate.
|
||||
*/
|
||||
static VALUE
|
||||
class_alloc(VALUE flags, VALUE klass)
|
||||
class_alloc0(enum ruby_value_type type, VALUE klass, bool namespaceable)
|
||||
{
|
||||
rb_ns_subclasses_t *ns_subclasses;
|
||||
rb_subclass_anchor_t *anchor;
|
||||
const rb_namespace_t *ns = rb_definition_namespace();
|
||||
size_t alloc_size = sizeof(struct RClass) + sizeof(rb_classext_t);
|
||||
|
||||
if (!ruby_namespace_init_done) {
|
||||
namespaceable = true;
|
||||
}
|
||||
|
||||
size_t alloc_size = sizeof(struct RClass_and_rb_classext_t);
|
||||
if (namespaceable) {
|
||||
alloc_size = sizeof(struct RClass_namespaceable);
|
||||
}
|
||||
|
||||
// class_alloc is supposed to return a new object that is not promoted yet.
|
||||
// So, we need to avoid GC after NEWOBJ_OF.
|
||||
|
@ -686,8 +672,12 @@ class_alloc(VALUE flags, VALUE klass)
|
|||
anchor->ns_subclasses = ns_subclasses;
|
||||
anchor->head = ZALLOC(rb_subclass_entry_t);
|
||||
|
||||
flags &= T_MASK;
|
||||
RUBY_ASSERT(type == T_CLASS || type == T_ICLASS || type == T_MODULE);
|
||||
|
||||
VALUE flags = type;
|
||||
if (RGENGC_WB_PROTECTED_CLASS) flags |= FL_WB_PROTECTED;
|
||||
if (namespaceable) flags |= RCLASS_NAMESPACEABLE;
|
||||
|
||||
NEWOBJ_OF(obj, struct RClass, klass, flags, alloc_size, 0);
|
||||
|
||||
memset(RCLASS_EXT_PRIME(obj), 0, sizeof(rb_classext_t));
|
||||
|
@ -702,17 +692,22 @@ class_alloc(VALUE flags, VALUE klass)
|
|||
RCLASS_PRIME_NS((VALUE)obj) = ns;
|
||||
// Classes/Modules defined in user namespaces are
|
||||
// writable directly because it exists only in a namespace.
|
||||
RCLASS_SET_PRIME_CLASSEXT_WRITABLE((VALUE)obj, NAMESPACE_USER_P(ns) ? true : false);
|
||||
RCLASS_SET_PRIME_CLASSEXT_WRITABLE((VALUE)obj, !namespaceable || NAMESPACE_USER_P(ns));
|
||||
|
||||
RCLASS_SET_ORIGIN((VALUE)obj, (VALUE)obj);
|
||||
RCLASS_SET_REFINED_CLASS((VALUE)obj, Qnil);
|
||||
RCLASS_SET_ALLOCATOR((VALUE)obj, 0);
|
||||
|
||||
RCLASS_SET_SUBCLASSES((VALUE)obj, anchor);
|
||||
|
||||
return (VALUE)obj;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
class_alloc(enum ruby_value_type type, VALUE klass)
|
||||
{
|
||||
return class_alloc0(type, klass, false);
|
||||
}
|
||||
|
||||
static VALUE
|
||||
class_associate_super(VALUE klass, VALUE super, bool init)
|
||||
{
|
||||
|
@ -748,6 +743,23 @@ class_clear_method_table(VALUE c)
|
|||
RCLASS_WRITE_M_TBL_EVEN_WHEN_PROMOTED(c, rb_id_table_create(0));
|
||||
}
|
||||
|
||||
static VALUE
|
||||
class_boot_namespaceable(VALUE super, bool namespaceable)
|
||||
{
|
||||
VALUE klass = class_alloc0(T_CLASS, rb_cClass, namespaceable);
|
||||
|
||||
// initialize method table prior to class_associate_super()
|
||||
// because class_associate_super() may cause GC and promote klass
|
||||
class_initialize_method_table(klass);
|
||||
|
||||
class_associate_super(klass, super, true);
|
||||
if (super && !UNDEF_P(super)) {
|
||||
rb_class_set_initialized(klass);
|
||||
}
|
||||
|
||||
return (VALUE)klass;
|
||||
}
|
||||
|
||||
/**
|
||||
* A utility function that wraps class_alloc.
|
||||
*
|
||||
|
@ -760,15 +772,7 @@ class_clear_method_table(VALUE c)
|
|||
VALUE
|
||||
rb_class_boot(VALUE super)
|
||||
{
|
||||
VALUE klass = class_alloc(T_CLASS, rb_cClass);
|
||||
|
||||
// initialize method table prior to class_associate_super()
|
||||
// because class_associate_super() may cause GC and promote klass
|
||||
class_initialize_method_table(klass);
|
||||
|
||||
class_associate_super(klass, super, true);
|
||||
|
||||
return (VALUE)klass;
|
||||
return class_boot_namespaceable(super, false);
|
||||
}
|
||||
|
||||
static VALUE *
|
||||
|
@ -825,11 +829,11 @@ rb_class_update_superclasses(VALUE klass)
|
|||
}
|
||||
else {
|
||||
superclasses = class_superclasses_including_self(super);
|
||||
RCLASS_WRITE_SUPERCLASSES(super, super_depth, superclasses, true, true);
|
||||
RCLASS_WRITE_SUPERCLASSES(super, super_depth, superclasses, true);
|
||||
}
|
||||
|
||||
size_t depth = super_depth == RCLASS_MAX_SUPERCLASS_DEPTH ? super_depth : super_depth + 1;
|
||||
RCLASS_WRITE_SUPERCLASSES(klass, depth, superclasses, false, false);
|
||||
RCLASS_WRITE_SUPERCLASSES(klass, depth, superclasses, false);
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -858,6 +862,8 @@ rb_class_new(VALUE super)
|
|||
RCLASS_SET_MAX_IV_COUNT(klass, RCLASS_MAX_IV_COUNT(super));
|
||||
}
|
||||
|
||||
RUBY_ASSERT(getenv("RUBY_NAMESPACE") || RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass));
|
||||
|
||||
return klass;
|
||||
}
|
||||
|
||||
|
@ -871,8 +877,7 @@ static void
|
|||
clone_method(VALUE old_klass, VALUE new_klass, ID mid, const rb_method_entry_t *me)
|
||||
{
|
||||
if (me->def->type == VM_METHOD_TYPE_ISEQ) {
|
||||
rb_cref_t *new_cref;
|
||||
rb_vm_rewrite_cref(me->def->body.iseq.cref, old_klass, new_klass, &new_cref);
|
||||
rb_cref_t *new_cref = rb_vm_rewrite_cref(me->def->body.iseq.cref, old_klass, new_klass);
|
||||
rb_add_method_iseq(new_klass, mid, me->def->body.iseq.iseqptr, new_cref, METHOD_ENTRY_VISI(me));
|
||||
}
|
||||
else {
|
||||
|
@ -922,7 +927,7 @@ class_init_copy_check(VALUE clone, VALUE orig)
|
|||
if (orig == rb_cBasicObject) {
|
||||
rb_raise(rb_eTypeError, "can't copy the root class");
|
||||
}
|
||||
if (RCLASS_SUPER(clone) != 0 || clone == rb_cBasicObject) {
|
||||
if (RCLASS_INITIALIZED_P(clone)) {
|
||||
rb_raise(rb_eTypeError, "already initialized class");
|
||||
}
|
||||
if (RCLASS_SINGLETON_P(orig)) {
|
||||
|
@ -975,48 +980,33 @@ copy_tables(VALUE clone, VALUE orig)
|
|||
rb_id_table_free(RCLASS_M_TBL(clone));
|
||||
RCLASS_WRITE_M_TBL_EVEN_WHEN_PROMOTED(clone, 0);
|
||||
if (!RB_TYPE_P(clone, T_ICLASS)) {
|
||||
st_data_t id;
|
||||
|
||||
rb_fields_tbl_copy(clone, orig);
|
||||
CONST_ID(id, "__tmp_classpath__");
|
||||
rb_attr_delete(clone, id);
|
||||
CONST_ID(id, "__classpath__");
|
||||
rb_attr_delete(clone, id);
|
||||
}
|
||||
if (RCLASS_CONST_TBL(orig)) {
|
||||
struct clone_const_arg arg;
|
||||
struct rb_id_table *const_tbl;
|
||||
arg.tbl = const_tbl = rb_id_table_create(0);
|
||||
struct rb_id_table *orig_tbl = RCLASS_CONST_TBL(orig);
|
||||
arg.tbl = const_tbl = rb_id_table_create(rb_id_table_size(orig_tbl));
|
||||
arg.klass = clone;
|
||||
rb_id_table_foreach(RCLASS_CONST_TBL(orig), clone_const_i, &arg);
|
||||
rb_id_table_foreach(orig_tbl, clone_const_i, &arg);
|
||||
RCLASS_WRITE_CONST_TBL(clone, const_tbl, false);
|
||||
}
|
||||
}
|
||||
|
||||
static bool ensure_origin(VALUE klass);
|
||||
|
||||
/**
|
||||
* If this flag is set, that module is allocated but not initialized yet.
|
||||
*/
|
||||
enum {RMODULE_ALLOCATED_BUT_NOT_INITIALIZED = RUBY_FL_USER1};
|
||||
|
||||
static inline bool
|
||||
RMODULE_UNINITIALIZED(VALUE module)
|
||||
{
|
||||
return FL_TEST_RAW(module, RMODULE_ALLOCATED_BUT_NOT_INITIALIZED);
|
||||
}
|
||||
|
||||
void
|
||||
rb_module_set_initialized(VALUE mod)
|
||||
rb_class_set_initialized(VALUE klass)
|
||||
{
|
||||
FL_UNSET_RAW(mod, RMODULE_ALLOCATED_BUT_NOT_INITIALIZED);
|
||||
RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS) || RB_TYPE_P(klass, T_MODULE));
|
||||
FL_SET_RAW(klass, RCLASS_IS_INITIALIZED);
|
||||
/* no more re-initialization */
|
||||
}
|
||||
|
||||
void
|
||||
rb_module_check_initializable(VALUE mod)
|
||||
{
|
||||
if (!RMODULE_UNINITIALIZED(mod)) {
|
||||
if (RCLASS_INITIALIZED_P(mod)) {
|
||||
rb_raise(rb_eTypeError, "already initialized module");
|
||||
}
|
||||
}
|
||||
|
@ -1025,9 +1015,11 @@ rb_module_check_initializable(VALUE mod)
|
|||
VALUE
|
||||
rb_mod_init_copy(VALUE clone, VALUE orig)
|
||||
{
|
||||
/* Only class or module is valid here, but other classes may enter here and
|
||||
* only hit an exception on the OBJ_INIT_COPY checks
|
||||
*/
|
||||
switch (BUILTIN_TYPE(clone)) {
|
||||
case T_CLASS:
|
||||
case T_ICLASS:
|
||||
class_init_copy_check(clone, orig);
|
||||
break;
|
||||
case T_MODULE:
|
||||
|
@ -1038,6 +1030,11 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
|
|||
}
|
||||
if (!OBJ_INIT_COPY(clone, orig)) return clone;
|
||||
|
||||
RUBY_ASSERT(RB_TYPE_P(orig, T_CLASS) || RB_TYPE_P(orig, T_MODULE));
|
||||
RUBY_ASSERT(BUILTIN_TYPE(clone) == BUILTIN_TYPE(orig));
|
||||
|
||||
rb_class_set_initialized(clone);
|
||||
|
||||
/* cloned flag is refer at constant inline cache
|
||||
* see vm_get_const_key_cref() in vm_insnhelper.c
|
||||
*/
|
||||
|
@ -1048,7 +1045,9 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
|
|||
RBASIC_SET_CLASS(clone, rb_singleton_class_clone(orig));
|
||||
rb_singleton_class_attached(METACLASS_OF(clone), (VALUE)clone);
|
||||
}
|
||||
if (BUILTIN_TYPE(clone) == T_CLASS) {
|
||||
RCLASS_SET_ALLOCATOR(clone, RCLASS_ALLOCATOR(orig));
|
||||
}
|
||||
copy_tables(clone, orig);
|
||||
if (RCLASS_M_TBL(orig)) {
|
||||
struct clone_method_arg arg;
|
||||
|
@ -1081,7 +1080,7 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
|
|||
if (BUILTIN_TYPE(p) != T_ICLASS) {
|
||||
rb_bug("non iclass between module/class and origin");
|
||||
}
|
||||
clone_p = class_alloc(RBASIC(p)->flags, METACLASS_OF(p));
|
||||
clone_p = class_alloc(T_ICLASS, METACLASS_OF(p));
|
||||
/* We should set the m_tbl right after allocation before anything
|
||||
* that can trigger GC to avoid clone_p from becoming old and
|
||||
* needing to fire write barriers. */
|
||||
|
@ -1089,7 +1088,6 @@ rb_mod_init_copy(VALUE clone, VALUE orig)
|
|||
rb_class_set_super(prev_clone_p, clone_p);
|
||||
prev_clone_p = clone_p;
|
||||
RCLASS_SET_CONST_TBL(clone_p, RCLASS_CONST_TBL(p), false);
|
||||
RCLASS_SET_ALLOCATOR(clone_p, RCLASS_ALLOCATOR(p));
|
||||
if (RB_TYPE_P(clone, T_CLASS)) {
|
||||
RCLASS_SET_INCLUDER(clone_p, clone);
|
||||
}
|
||||
|
@ -1159,7 +1157,8 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
|
|||
else {
|
||||
/* copy singleton(unnamed) class */
|
||||
bool klass_of_clone_is_new;
|
||||
VALUE clone = class_alloc(RBASIC(klass)->flags, 0);
|
||||
RUBY_ASSERT(RB_TYPE_P(klass, T_CLASS));
|
||||
VALUE clone = class_alloc(T_CLASS, 0);
|
||||
|
||||
if (BUILTIN_TYPE(obj) == T_CLASS) {
|
||||
klass_of_clone_is_new = true;
|
||||
|
@ -1265,7 +1264,7 @@ static inline VALUE
|
|||
make_metaclass(VALUE klass)
|
||||
{
|
||||
VALUE super;
|
||||
VALUE metaclass = rb_class_boot(Qundef);
|
||||
VALUE metaclass = class_boot_namespaceable(Qundef, FL_TEST_RAW(klass, RCLASS_NAMESPACEABLE));
|
||||
|
||||
FL_SET(metaclass, FL_SINGLETON);
|
||||
rb_singleton_class_attached(metaclass, klass);
|
||||
|
@ -1283,6 +1282,7 @@ make_metaclass(VALUE klass)
|
|||
super = RCLASS_SUPER(klass);
|
||||
while (RB_TYPE_P(super, T_ICLASS)) super = RCLASS_SUPER(super);
|
||||
class_associate_super(metaclass, super ? ENSURE_EIGENCLASS(super) : rb_cClass, true);
|
||||
rb_class_set_initialized(klass);
|
||||
|
||||
// Full class ancestry may not have been filled until we reach here.
|
||||
rb_class_update_superclasses(METACLASS_OF(metaclass));
|
||||
|
@ -1300,7 +1300,7 @@ static inline VALUE
|
|||
make_singleton_class(VALUE obj)
|
||||
{
|
||||
VALUE orig_class = METACLASS_OF(obj);
|
||||
VALUE klass = rb_class_boot(orig_class);
|
||||
VALUE klass = class_boot_namespaceable(orig_class, FL_TEST_RAW(orig_class, RCLASS_NAMESPACEABLE));
|
||||
|
||||
FL_SET(klass, FL_SINGLETON);
|
||||
RBASIC_SET_CLASS(obj, klass);
|
||||
|
@ -1565,7 +1565,6 @@ rb_module_s_alloc(VALUE klass)
|
|||
{
|
||||
VALUE mod = class_alloc(T_MODULE, klass);
|
||||
class_initialize_method_table(mod);
|
||||
FL_SET(mod, RMODULE_ALLOCATED_BUT_NOT_INITIALIZED);
|
||||
return mod;
|
||||
}
|
||||
|
||||
|
@ -1689,7 +1688,7 @@ ensure_includable(VALUE klass, VALUE module)
|
|||
{
|
||||
rb_class_modify_check(klass);
|
||||
Check_Type(module, T_MODULE);
|
||||
rb_module_set_initialized(module);
|
||||
rb_class_set_initialized(module);
|
||||
if (!NIL_P(rb_refinement_module_get_refined_class(module))) {
|
||||
rb_raise(rb_eArgError, "refinement module is not allowed");
|
||||
}
|
||||
|
@ -2766,7 +2765,8 @@ rb_freeze_singleton_class(VALUE x)
|
|||
if (!RCLASS_SINGLETON_P(x)) {
|
||||
VALUE klass = RBASIC_CLASS(x);
|
||||
if (klass && // no class when hidden from ObjectSpace
|
||||
FL_TEST(klass, (FL_SINGLETON|FL_FREEZE)) == FL_SINGLETON) {
|
||||
FL_TEST_RAW(klass, FL_SINGLETON) &&
|
||||
!OBJ_FROZEN_RAW(klass)) {
|
||||
OBJ_FREEZE(klass);
|
||||
}
|
||||
}
|
||||
|
|
68
compile.c
68
compile.c
|
@ -2178,13 +2178,14 @@ iseq_set_local_table(rb_iseq_t *iseq, const rb_ast_id_table_t *tbl, const NODE *
|
|||
// then its local table should only be `...`
|
||||
// FIXME: I think this should be fixed in the AST rather than special case here.
|
||||
if (args->forwarding && args->pre_args_num == 0 && !args->opt_args) {
|
||||
CHECK(size >= 3);
|
||||
size -= 3;
|
||||
offset += 3;
|
||||
}
|
||||
}
|
||||
|
||||
if (size > 0) {
|
||||
ID *ids = (ID *)ALLOC_N(ID, size);
|
||||
ID *ids = ALLOC_N(ID, size);
|
||||
MEMCPY(ids, tbl->ids + offset, ID, size);
|
||||
ISEQ_BODY(iseq)->local_table = ids;
|
||||
}
|
||||
|
@ -2481,7 +2482,7 @@ array_to_idlist(VALUE arr)
|
|||
RUBY_ASSERT(RB_TYPE_P(arr, T_ARRAY));
|
||||
long size = RARRAY_LEN(arr);
|
||||
ID *ids = (ID *)ALLOC_N(ID, size + 1);
|
||||
for (int i = 0; i < size; i++) {
|
||||
for (long i = 0; i < size; i++) {
|
||||
VALUE sym = RARRAY_AREF(arr, i);
|
||||
ids[i] = SYM2ID(sym);
|
||||
}
|
||||
|
@ -3490,7 +3491,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
|
|||
iobj->insn_id = BIN(opt_ary_freeze);
|
||||
iobj->operand_size = 2;
|
||||
iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
|
||||
iobj->operands[0] = rb_cArray_empty_frozen;
|
||||
RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cArray_empty_frozen);
|
||||
iobj->operands[1] = (VALUE)ci;
|
||||
ELEM_REMOVE(next);
|
||||
}
|
||||
|
@ -3513,7 +3514,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
|
|||
iobj->insn_id = BIN(opt_hash_freeze);
|
||||
iobj->operand_size = 2;
|
||||
iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
|
||||
iobj->operands[0] = rb_cHash_empty_frozen;
|
||||
RB_OBJ_WRITE(iseq, &iobj->operands[0], rb_cHash_empty_frozen);
|
||||
iobj->operands[1] = (VALUE)ci;
|
||||
ELEM_REMOVE(next);
|
||||
}
|
||||
|
@ -4091,7 +4092,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
|
|||
unsigned int flags = vm_ci_flag(ci);
|
||||
if ((flags & set_flags) == set_flags && !(flags & unset_flags)) {
|
||||
((INSN*)niobj)->insn_id = BIN(putobject);
|
||||
OPERAND_AT(niobj, 0) = rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0)));
|
||||
RB_OBJ_WRITE(iseq, &OPERAND_AT(niobj, 0), rb_hash_freeze(rb_hash_resurrect(OPERAND_AT(niobj, 0))));
|
||||
|
||||
const struct rb_callinfo *nci = vm_ci_new(vm_ci_mid(ci),
|
||||
flags & ~VM_CALL_KW_SPLAT_MUT, vm_ci_argc(ci), vm_ci_kwarg(ci));
|
||||
|
@ -6640,6 +6641,14 @@ setup_args_dup_rest_p(const NODE *argn)
|
|||
return false;
|
||||
case NODE_COLON2:
|
||||
return setup_args_dup_rest_p(RNODE_COLON2(argn)->nd_head);
|
||||
case NODE_LIST:
|
||||
while (argn) {
|
||||
if (setup_args_dup_rest_p(RNODE_LIST(argn)->nd_head)) {
|
||||
return true;
|
||||
}
|
||||
argn = RNODE_LIST(argn)->nd_next;
|
||||
}
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
|
@ -9254,12 +9263,13 @@ compile_builtin_mandatory_only_method(rb_iseq_t *iseq, const NODE *node, const N
|
|||
|
||||
VALUE ast_value = rb_ruby_ast_new(RNODE(&scope_node));
|
||||
|
||||
ISEQ_BODY(iseq)->mandatory_only_iseq =
|
||||
const rb_iseq_t *mandatory_only_iseq =
|
||||
rb_iseq_new_with_opt(ast_value, rb_iseq_base_label(iseq),
|
||||
rb_iseq_path(iseq), rb_iseq_realpath(iseq),
|
||||
nd_line(line_node), NULL, 0,
|
||||
ISEQ_TYPE_METHOD, ISEQ_COMPILE_DATA(iseq)->option,
|
||||
ISEQ_BODY(iseq)->variable.script_lines);
|
||||
RB_OBJ_WRITE(iseq, &ISEQ_BODY(iseq)->mandatory_only_iseq, (VALUE)mandatory_only_iseq);
|
||||
|
||||
ALLOCV_END(idtmp);
|
||||
return COMPILE_OK;
|
||||
|
@ -9530,7 +9540,8 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
|
|||
|
||||
ADD_LABEL(ret, not_basic_new_finish);
|
||||
ADD_INSN(ret, line_node, pop);
|
||||
} else {
|
||||
}
|
||||
else {
|
||||
ADD_SEND_R(ret, line_node, mid, argc, parent_block, INT2FIX(flag), keywords);
|
||||
}
|
||||
|
||||
|
@ -12589,8 +12600,13 @@ static ibf_offset_t
|
|||
ibf_dump_write(struct ibf_dump *dump, const void *buff, unsigned long size)
|
||||
{
|
||||
ibf_offset_t pos = ibf_dump_pos(dump);
|
||||
#if SIZEOF_LONG > SIZEOF_INT
|
||||
/* ensure the resulting dump does not exceed UINT_MAX */
|
||||
if (size >= UINT_MAX || pos + size >= UINT_MAX) {
|
||||
rb_raise(rb_eRuntimeError, "dump size exceeds");
|
||||
}
|
||||
#endif
|
||||
rb_str_cat(dump->current_buffer->str, (const char *)buff, size);
|
||||
/* TODO: overflow check */
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
@ -13283,12 +13299,13 @@ ibf_dump_catch_table(struct ibf_dump *dump, const rb_iseq_t *iseq)
|
|||
}
|
||||
}
|
||||
|
||||
static struct iseq_catch_table *
|
||||
ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size)
|
||||
static void
|
||||
ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offset, unsigned int size, const rb_iseq_t *parent_iseq)
|
||||
{
|
||||
if (size) {
|
||||
struct iseq_catch_table *table = ruby_xmalloc(iseq_catch_table_bytes(size));
|
||||
struct iseq_catch_table *table = ruby_xcalloc(1, iseq_catch_table_bytes(size));
|
||||
table->size = size;
|
||||
ISEQ_BODY(parent_iseq)->catch_table = table;
|
||||
|
||||
ibf_offset_t reading_pos = catch_table_offset;
|
||||
|
||||
|
@ -13301,12 +13318,12 @@ ibf_load_catch_table(const struct ibf_load *load, ibf_offset_t catch_table_offse
|
|||
table->entries[i].cont = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
||||
table->entries[i].sp = (unsigned int)ibf_load_small_value(load, &reading_pos);
|
||||
|
||||
table->entries[i].iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
|
||||
rb_iseq_t *catch_iseq = (rb_iseq_t *)ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)iseq_index);
|
||||
RB_OBJ_WRITE(parent_iseq, UNALIGNED_MEMBER_PTR(&table->entries[i], iseq), catch_iseq);
|
||||
}
|
||||
return table;
|
||||
}
|
||||
else {
|
||||
return NULL;
|
||||
ISEQ_BODY(parent_iseq)->catch_table = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -13377,6 +13394,14 @@ outer_variable_cmp(const void *a, const void *b, void *arg)
|
|||
{
|
||||
const struct outer_variable_pair *ap = (const struct outer_variable_pair *)a;
|
||||
const struct outer_variable_pair *bp = (const struct outer_variable_pair *)b;
|
||||
|
||||
if (!ap->name) {
|
||||
return -1;
|
||||
}
|
||||
else if (!bp->name) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
return rb_str_cmp(ap->name, bp->name);
|
||||
}
|
||||
|
||||
|
@ -13811,10 +13836,15 @@ ibf_load_iseq_each(struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t offset)
|
|||
load_body->insns_info.body = ibf_load_insns_info_body(load, insns_info_body_offset, insns_info_size);
|
||||
load_body->insns_info.positions = ibf_load_insns_info_positions(load, insns_info_positions_offset, insns_info_size);
|
||||
load_body->local_table = ibf_load_local_table(load, local_table_offset, local_table_size);
|
||||
load_body->catch_table = ibf_load_catch_table(load, catch_table_offset, catch_table_size);
|
||||
load_body->parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
|
||||
load_body->local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
|
||||
load_body->mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
|
||||
ibf_load_catch_table(load, catch_table_offset, catch_table_size, iseq);
|
||||
|
||||
const rb_iseq_t *parent_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)parent_iseq_index);
|
||||
const rb_iseq_t *local_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)local_iseq_index);
|
||||
const rb_iseq_t *mandatory_only_iseq = ibf_load_iseq(load, (const rb_iseq_t *)(VALUE)mandatory_only_iseq_index);
|
||||
|
||||
RB_OBJ_WRITE(iseq, &load_body->parent_iseq, parent_iseq);
|
||||
RB_OBJ_WRITE(iseq, &load_body->local_iseq, local_iseq);
|
||||
RB_OBJ_WRITE(iseq, &load_body->mandatory_only_iseq, mandatory_only_iseq);
|
||||
|
||||
// This must be done after the local table is loaded.
|
||||
if (load_body->param.keyword != NULL) {
|
||||
|
@ -14430,7 +14460,7 @@ ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
|
|||
else {
|
||||
obj_header.internal = SPECIAL_CONST_P(obj) ? FALSE : (RBASIC_CLASS(obj) == 0) ? TRUE : FALSE;
|
||||
obj_header.special_const = FALSE;
|
||||
obj_header.frozen = FL_TEST(obj, FL_FREEZE) ? TRUE : FALSE;
|
||||
obj_header.frozen = OBJ_FROZEN(obj) ? TRUE : FALSE;
|
||||
ibf_dump_object_object_header(dump, obj_header);
|
||||
(*dump_object_functions[obj_header.type])(dump, obj);
|
||||
}
|
||||
|
|
16
complex.c
16
complex.c
|
@ -1925,21 +1925,6 @@ nucomp_to_c(VALUE self)
|
|||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* to_c -> (0+0i)
|
||||
*
|
||||
* Returns zero as a Complex:
|
||||
*
|
||||
* nil.to_c # => (0+0i)
|
||||
*
|
||||
*/
|
||||
static VALUE
|
||||
nilclass_to_c(VALUE self)
|
||||
{
|
||||
return rb_complex_new1(INT2FIX(0));
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* to_c -> complex
|
||||
|
@ -2693,7 +2678,6 @@ Init_Complex(void)
|
|||
rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
|
||||
rb_define_method(rb_cComplex, "rationalize", nucomp_rationalize, -1);
|
||||
rb_define_method(rb_cComplex, "to_c", nucomp_to_c, 0);
|
||||
rb_define_method(rb_cNilClass, "to_c", nilclass_to_c, 0);
|
||||
rb_define_method(rb_cNumeric, "to_c", numeric_to_c, 0);
|
||||
|
||||
rb_define_method(rb_cString, "to_c", string_to_c, 0);
|
||||
|
|
325
concurrent_set.c
Normal file
325
concurrent_set.c
Normal file
|
@ -0,0 +1,325 @@
|
|||
#include "internal.h"
|
||||
#include "internal/gc.h"
|
||||
#include "internal/concurrent_set.h"
|
||||
#include "ruby_atomic.h"
|
||||
#include "ruby/atomic.h"
|
||||
#include "vm_sync.h"
|
||||
|
||||
enum concurrent_set_special_values {
|
||||
CONCURRENT_SET_EMPTY,
|
||||
CONCURRENT_SET_DELETED,
|
||||
CONCURRENT_SET_MOVED,
|
||||
CONCURRENT_SET_SPECIAL_VALUE_COUNT
|
||||
};
|
||||
|
||||
struct concurrent_set_entry {
|
||||
VALUE hash;
|
||||
VALUE key;
|
||||
};
|
||||
|
||||
struct concurrent_set {
|
||||
rb_atomic_t size;
|
||||
unsigned int capacity;
|
||||
unsigned int deleted_entries;
|
||||
const struct rb_concurrent_set_funcs *funcs;
|
||||
struct concurrent_set_entry *entries;
|
||||
};
|
||||
|
||||
static void
|
||||
concurrent_set_free(void *ptr)
|
||||
{
|
||||
struct concurrent_set *set = ptr;
|
||||
xfree(set->entries);
|
||||
}
|
||||
|
||||
static size_t
|
||||
concurrent_set_size(const void *ptr)
|
||||
{
|
||||
const struct concurrent_set *set = ptr;
|
||||
return sizeof(struct concurrent_set) +
|
||||
(set->capacity * sizeof(struct concurrent_set_entry));
|
||||
}
|
||||
|
||||
static const rb_data_type_t concurrent_set_type = {
|
||||
.wrap_struct_name = "VM/concurrent_set",
|
||||
.function = {
|
||||
.dmark = NULL,
|
||||
.dfree = concurrent_set_free,
|
||||
.dsize = concurrent_set_size,
|
||||
},
|
||||
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE
|
||||
};
|
||||
|
||||
VALUE
|
||||
rb_concurrent_set_new(const struct rb_concurrent_set_funcs *funcs, int capacity)
|
||||
{
|
||||
struct concurrent_set *set;
|
||||
VALUE obj = TypedData_Make_Struct(0, struct concurrent_set, &concurrent_set_type, set);
|
||||
set->funcs = funcs;
|
||||
set->entries = ZALLOC_N(struct concurrent_set_entry, capacity);
|
||||
set->capacity = capacity;
|
||||
return obj;
|
||||
}
|
||||
|
||||
struct concurrent_set_probe {
|
||||
int idx;
|
||||
int d;
|
||||
int mask;
|
||||
};
|
||||
|
||||
static int
|
||||
concurrent_set_probe_start(struct concurrent_set_probe *probe, struct concurrent_set *set, VALUE hash)
|
||||
{
|
||||
RUBY_ASSERT((set->capacity & (set->capacity - 1)) == 0);
|
||||
probe->d = 0;
|
||||
probe->mask = set->capacity - 1;
|
||||
probe->idx = hash & probe->mask;
|
||||
return probe->idx;
|
||||
}
|
||||
|
||||
static int
|
||||
concurrent_set_probe_next(struct concurrent_set_probe *probe)
|
||||
{
|
||||
probe->d++;
|
||||
probe->idx = (probe->idx + probe->d) & probe->mask;
|
||||
return probe->idx;
|
||||
}
|
||||
|
||||
static void
|
||||
concurrent_set_try_resize_without_locking(VALUE old_set_obj, VALUE *set_obj_ptr)
|
||||
{
|
||||
// Check if another thread has already resized.
|
||||
if (RUBY_ATOMIC_VALUE_LOAD(*set_obj_ptr) != old_set_obj) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct concurrent_set *old_set = RTYPEDDATA_GET_DATA(old_set_obj);
|
||||
|
||||
// This may overcount by up to the number of threads concurrently attempting to insert
|
||||
// GC may also happen between now and the set being rebuilt
|
||||
int expected_size = RUBY_ATOMIC_LOAD(old_set->size) - old_set->deleted_entries;
|
||||
|
||||
struct concurrent_set_entry *old_entries = old_set->entries;
|
||||
int old_capacity = old_set->capacity;
|
||||
int new_capacity = old_capacity * 2;
|
||||
if (new_capacity > expected_size * 8) {
|
||||
new_capacity = old_capacity / 2;
|
||||
}
|
||||
else if (new_capacity > expected_size * 4) {
|
||||
new_capacity = old_capacity;
|
||||
}
|
||||
|
||||
// May cause GC and therefore deletes, so must hapen first.
|
||||
VALUE new_set_obj = rb_concurrent_set_new(old_set->funcs, new_capacity);
|
||||
struct concurrent_set *new_set = RTYPEDDATA_GET_DATA(new_set_obj);
|
||||
|
||||
for (int i = 0; i < old_capacity; i++) {
|
||||
struct concurrent_set_entry *entry = &old_entries[i];
|
||||
VALUE key = RUBY_ATOMIC_VALUE_EXCHANGE(entry->key, CONCURRENT_SET_MOVED);
|
||||
RUBY_ASSERT(key != CONCURRENT_SET_MOVED);
|
||||
|
||||
if (key < CONCURRENT_SET_SPECIAL_VALUE_COUNT) continue;
|
||||
if (rb_objspace_garbage_object_p(key)) continue;
|
||||
|
||||
VALUE hash = RUBY_ATOMIC_VALUE_LOAD(entry->hash);
|
||||
if (hash == 0) {
|
||||
// Either in-progress insert or extremely unlikely 0 hash.
|
||||
// Re-calculate the hash.
|
||||
hash = old_set->funcs->hash(key);
|
||||
}
|
||||
RUBY_ASSERT(hash == old_set->funcs->hash(key));
|
||||
|
||||
// Insert key into new_set.
|
||||
struct concurrent_set_probe probe;
|
||||
int idx = concurrent_set_probe_start(&probe, new_set, hash);
|
||||
|
||||
while (true) {
|
||||
struct concurrent_set_entry *entry = &new_set->entries[idx];
|
||||
|
||||
if (entry->key == CONCURRENT_SET_EMPTY) {
|
||||
new_set->size++;
|
||||
|
||||
RUBY_ASSERT(new_set->size < new_set->capacity / 2);
|
||||
RUBY_ASSERT(entry->hash == 0);
|
||||
|
||||
entry->key = key;
|
||||
entry->hash = hash;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
RUBY_ASSERT(entry->key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT);
|
||||
}
|
||||
|
||||
idx = concurrent_set_probe_next(&probe);
|
||||
}
|
||||
}
|
||||
|
||||
RUBY_ATOMIC_VALUE_SET(*set_obj_ptr, new_set_obj);
|
||||
|
||||
RB_GC_GUARD(old_set_obj);
|
||||
}
|
||||
|
||||
static void
|
||||
concurrent_set_try_resize(VALUE old_set_obj, VALUE *set_obj_ptr)
|
||||
{
|
||||
RB_VM_LOCKING() {
|
||||
concurrent_set_try_resize_without_locking(old_set_obj, set_obj_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_concurrent_set_find_or_insert(VALUE *set_obj_ptr, VALUE key, void *data)
|
||||
{
|
||||
RUBY_ASSERT(key >= CONCURRENT_SET_SPECIAL_VALUE_COUNT);
|
||||
|
||||
bool inserting = false;
|
||||
VALUE set_obj;
|
||||
|
||||
retry:
|
||||
set_obj = RUBY_ATOMIC_VALUE_LOAD(*set_obj_ptr);
|
||||
RUBY_ASSERT(set_obj);
|
||||
struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
|
||||
|
||||
struct concurrent_set_probe probe;
|
||||
VALUE hash = set->funcs->hash(key);
|
||||
int idx = concurrent_set_probe_start(&probe, set, hash);
|
||||
|
||||
while (true) {
|
||||
struct concurrent_set_entry *entry = &set->entries[idx];
|
||||
VALUE curr_key = RUBY_ATOMIC_VALUE_LOAD(entry->key);
|
||||
|
||||
switch (curr_key) {
|
||||
case CONCURRENT_SET_EMPTY: {
|
||||
// Not in set
|
||||
if (!inserting) {
|
||||
key = set->funcs->create(key, data);
|
||||
RUBY_ASSERT(hash == set->funcs->hash(key));
|
||||
inserting = true;
|
||||
}
|
||||
|
||||
rb_atomic_t prev_size = RUBY_ATOMIC_FETCH_ADD(set->size, 1);
|
||||
|
||||
if (UNLIKELY(prev_size > set->capacity / 2)) {
|
||||
concurrent_set_try_resize(set_obj, set_obj_ptr);
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
curr_key = RUBY_ATOMIC_VALUE_CAS(entry->key, CONCURRENT_SET_EMPTY, key);
|
||||
if (curr_key == CONCURRENT_SET_EMPTY) {
|
||||
RUBY_ATOMIC_VALUE_SET(entry->hash, hash);
|
||||
|
||||
RB_GC_GUARD(set_obj);
|
||||
return key;
|
||||
}
|
||||
else {
|
||||
// Entry was not inserted.
|
||||
RUBY_ATOMIC_DEC(set->size);
|
||||
|
||||
// Another thread won the race, try again at the same location.
|
||||
continue;
|
||||
}
|
||||
}
|
||||
case CONCURRENT_SET_DELETED:
|
||||
break;
|
||||
case CONCURRENT_SET_MOVED:
|
||||
// Wait
|
||||
RB_VM_LOCKING();
|
||||
|
||||
goto retry;
|
||||
default: {
|
||||
VALUE curr_hash = RUBY_ATOMIC_VALUE_LOAD(entry->hash);
|
||||
if ((curr_hash == hash || curr_hash == 0) && set->funcs->cmp(key, curr_key)) {
|
||||
// We've found a match.
|
||||
if (UNLIKELY(rb_objspace_garbage_object_p(curr_key))) {
|
||||
// This is a weakref set, so after marking but before sweeping is complete we may find a matching garbage object.
|
||||
// Skip it and mark it as deleted.
|
||||
RUBY_ATOMIC_VALUE_CAS(entry->key, curr_key, CONCURRENT_SET_DELETED);
|
||||
|
||||
// Fall through and continue our search.
|
||||
}
|
||||
else {
|
||||
RB_GC_GUARD(set_obj);
|
||||
return curr_key;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
idx = concurrent_set_probe_next(&probe);
|
||||
}
|
||||
}
|
||||
|
||||
VALUE
|
||||
rb_concurrent_set_delete_by_identity(VALUE set_obj, VALUE key)
|
||||
{
|
||||
// Assume locking and barrier (which there is no assert for).
|
||||
ASSERT_vm_locking();
|
||||
|
||||
struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
|
||||
|
||||
VALUE hash = set->funcs->hash(key);
|
||||
|
||||
struct concurrent_set_probe probe;
|
||||
int idx = concurrent_set_probe_start(&probe, set, hash);
|
||||
|
||||
while (true) {
|
||||
struct concurrent_set_entry *entry = &set->entries[idx];
|
||||
VALUE curr_key = RUBY_ATOMIC_VALUE_LOAD(entry->key);
|
||||
|
||||
switch (curr_key) {
|
||||
case CONCURRENT_SET_EMPTY:
|
||||
// We didn't find our entry to delete.
|
||||
return 0;
|
||||
case CONCURRENT_SET_DELETED:
|
||||
break;
|
||||
case CONCURRENT_SET_MOVED:
|
||||
rb_bug("rb_concurrent_set_delete_by_identity: moved entry");
|
||||
break;
|
||||
default:
|
||||
if (key == curr_key) {
|
||||
entry->key = CONCURRENT_SET_DELETED;
|
||||
set->deleted_entries++;
|
||||
return curr_key;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
idx = concurrent_set_probe_next(&probe);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
rb_concurrent_set_foreach_with_replace(VALUE set_obj, int (*callback)(VALUE *key, void *data), void *data)
|
||||
{
|
||||
// Assume locking and barrier (which there is no assert for).
|
||||
ASSERT_vm_locking();
|
||||
|
||||
struct concurrent_set *set = RTYPEDDATA_GET_DATA(set_obj);
|
||||
|
||||
for (unsigned int i = 0; i < set->capacity; i++) {
|
||||
VALUE key = set->entries[i].key;
|
||||
|
||||
switch (key) {
|
||||
case CONCURRENT_SET_EMPTY:
|
||||
case CONCURRENT_SET_DELETED:
|
||||
continue;
|
||||
case CONCURRENT_SET_MOVED:
|
||||
rb_bug("rb_concurrent_set_foreach_with_replace: moved entry");
|
||||
break;
|
||||
default: {
|
||||
int ret = callback(&set->entries[i].key, data);
|
||||
switch (ret) {
|
||||
case ST_STOP:
|
||||
return;
|
||||
case ST_DELETE:
|
||||
set->entries[i].key = CONCURRENT_SET_DELETED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
124
configure.ac
124
configure.ac
|
@ -1006,7 +1006,7 @@ AS_IF([test "x$OPT_DIR" != x], [
|
|||
save_IFS="$IFS" IFS="$PATH_SEPARATOR" val= PWD=
|
||||
for dir in $OPT_DIR; do
|
||||
test -z "$dir" && continue
|
||||
dir=`eval $CHDIR '"$dir"' && pwd` || continue
|
||||
dir=`eval $CHDIR '"$dir"' 2>/dev/null && pwd` || continue
|
||||
val="${val:+$val$PATH_SEPARATOR}$dir"
|
||||
done
|
||||
IFS="$save_IFS" OPT_DIR="$val"
|
||||
|
@ -1743,6 +1743,18 @@ AS_IF([test "$GCC" = yes], [
|
|||
[rb_cv_gcc_atomic_builtins=no])])
|
||||
AS_IF([test "$rb_cv_gcc_atomic_builtins" = yes], [
|
||||
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
AC_CACHE_CHECK([for 64bit __atomic builtins], [rb_cv_gcc_atomic_builtins_64], [
|
||||
AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <stdint.h>
|
||||
uint64_t atomic_var;]],
|
||||
[[
|
||||
__atomic_load_n(&atomic_var, __ATOMIC_RELAXED);
|
||||
__atomic_store_n(&atomic_var, 0, __ATOMIC_RELAXED);
|
||||
]])],
|
||||
[rb_cv_gcc_atomic_builtins_64=yes],
|
||||
[rb_cv_gcc_atomic_builtins_64=no])])
|
||||
AS_IF([test "$rb_cv_gcc_atomic_builtins_64" = yes], [
|
||||
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS_64)
|
||||
])
|
||||
])
|
||||
|
||||
AC_CACHE_CHECK([for __sync builtins], [rb_cv_gcc_sync_builtins], [
|
||||
|
@ -3924,46 +3936,33 @@ AC_ARG_ENABLE(yjit,
|
|||
CARGO=
|
||||
CARGO_BUILD_ARGS=
|
||||
YJIT_LIBS=
|
||||
JIT_CARGO_SUPPORT=no
|
||||
AS_CASE(["${YJIT_SUPPORT}"],
|
||||
[yes|dev|stats|dev_nodebug], [
|
||||
AS_IF([test x"$RUSTC" = "xno"],
|
||||
AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
|
||||
)
|
||||
AS_IF([test x"$ZJIT_SUPPORT" != "xno"],
|
||||
AC_MSG_ERROR([YJIT cannot be enabled when ZJIT is enabled])
|
||||
)
|
||||
|
||||
AS_CASE(["${YJIT_SUPPORT}"],
|
||||
[yes], [
|
||||
rb_rust_target_subdir=release
|
||||
],
|
||||
[dev], [
|
||||
rb_rust_target_subdir=debug
|
||||
CARGO_BUILD_ARGS='--features disasm,runtime_checks'
|
||||
rb_cargo_features='disasm,runtime_checks'
|
||||
JIT_CARGO_SUPPORT=dev
|
||||
AC_DEFINE(RUBY_DEBUG, 1)
|
||||
],
|
||||
[dev_nodebug], [
|
||||
rb_rust_target_subdir=dev_nodebug
|
||||
CARGO_BUILD_ARGS='--profile dev_nodebug --features disasm'
|
||||
rb_cargo_features='disasm'
|
||||
JIT_CARGO_SUPPORT=dev_nodebug
|
||||
AC_DEFINE(YJIT_STATS, 1)
|
||||
],
|
||||
[stats], [
|
||||
rb_rust_target_subdir=stats
|
||||
CARGO_BUILD_ARGS='--profile stats'
|
||||
JIT_CARGO_SUPPORT=stats
|
||||
AC_DEFINE(YJIT_STATS, 1)
|
||||
])
|
||||
|
||||
AS_IF([test -n "${CARGO_BUILD_ARGS}"], [
|
||||
AC_CHECK_TOOL(CARGO, [cargo], [no])
|
||||
AS_IF([test x"$CARGO" = "xno"],
|
||||
AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install])
|
||||
]))
|
||||
|
||||
YJIT_LIBS="yjit/target/${rb_rust_target_subdir}/libyjit.a"
|
||||
AS_CASE(["$target_os"],[openbsd*],[
|
||||
# Link libc++abi (which requires libpthread) for _Unwind_* functions needed by yjit
|
||||
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
|
||||
])
|
||||
YJIT_LIBS="target/release/libyjit.a"
|
||||
RUST_LIB='$(YJIT_LIBS)'
|
||||
YJIT_OBJ='yjit.$(OBJEXT)'
|
||||
JIT_OBJ='jit.$(OBJEXT)'
|
||||
AS_IF([test x"$YJIT_SUPPORT" != "xyes" ], [
|
||||
|
@ -3974,38 +3973,28 @@ AS_CASE(["${YJIT_SUPPORT}"],
|
|||
AC_DEFINE(USE_YJIT, 0)
|
||||
])
|
||||
|
||||
ZJIT_CARGO_BUILD_ARGS=
|
||||
ZJIT_LIBS=
|
||||
AS_CASE(["${ZJIT_SUPPORT}"],
|
||||
[yes|dev], [
|
||||
[yes|dev|dev_nodebug], [
|
||||
AS_IF([test x"$RUSTC" = "xno"],
|
||||
AC_MSG_ERROR([rustc is required. Installation instructions available at https://www.rust-lang.org/tools/install])
|
||||
)
|
||||
AS_IF([test x"$YJIT_SUPPORT" != "xno"],
|
||||
AC_MSG_ERROR([ZJIT cannot be enabled when YJIT is enabled])
|
||||
)
|
||||
|
||||
AS_CASE(["${ZJIT_SUPPORT}"],
|
||||
[yes], [
|
||||
rb_rust_target_subdir=release
|
||||
],
|
||||
[dev], [
|
||||
rb_rust_target_subdir=debug
|
||||
ZJIT_CARGO_BUILD_ARGS='--profile dev --features disasm'
|
||||
rb_cargo_features="$rb_cargo_features,disasm"
|
||||
JIT_CARGO_SUPPORT=dev
|
||||
AC_DEFINE(RUBY_DEBUG, 1)
|
||||
],
|
||||
[dev_nodebug], [
|
||||
rb_cargo_features="$rb_cargo_features,disasm"
|
||||
JIT_CARGO_SUPPORT=dev_nodebug
|
||||
])
|
||||
|
||||
AS_IF([test -n "${ZJIT_CARGO_BUILD_ARGS}"], [
|
||||
AC_CHECK_TOOL(CARGO, [cargo], [no])
|
||||
AS_IF([test x"$CARGO" = "xno"],
|
||||
AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install])
|
||||
]))
|
||||
|
||||
ZJIT_LIBS="zjit/target/${rb_rust_target_subdir}/libzjit.a"
|
||||
AS_CASE(["$target_os"],[openbsd*],[
|
||||
# Link libc++abi (which requires libpthread) for _Unwind_* functions needed by yjit
|
||||
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
|
||||
])
|
||||
ZJIT_LIBS="target/release/libzjit.a"
|
||||
RUST_LIB='$(ZJIT_LIBS)'
|
||||
ZJIT_OBJ='zjit.$(OBJEXT)'
|
||||
JIT_OBJ='jit.$(OBJEXT)'
|
||||
AS_IF([test x"$ZJIT_SUPPORT" != "xyes" ], [
|
||||
|
@ -4016,18 +4005,63 @@ AS_CASE(["${ZJIT_SUPPORT}"],
|
|||
AC_DEFINE(USE_ZJIT, 0)
|
||||
])
|
||||
|
||||
# if YJIT+ZJIT release build, or any build that requires Cargo
|
||||
AS_IF([test x"$JIT_CARGO_SUPPORT" != "xno" -o \( x"$YJIT_SUPPORT" != "xno" -a x"$ZJIT_SUPPORT" != "xno" \)], [
|
||||
AC_CHECK_TOOL(CARGO, [cargo], [no])
|
||||
AS_IF([test x"$CARGO" = "xno"],
|
||||
AC_MSG_ERROR([cargo is required. Installation instructions available at https://www.rust-lang.org/tools/install]))
|
||||
|
||||
YJIT_LIBS=
|
||||
ZJIT_LIBS=
|
||||
|
||||
# There's more processing below to get the feature set for the
|
||||
# top-level crate, so capture at this point for feature set of
|
||||
# just the zjit crate.
|
||||
ZJIT_TEST_FEATURES="${rb_cargo_features}"
|
||||
|
||||
AS_IF([test x"${YJIT_SUPPORT}" != x"no"], [
|
||||
rb_cargo_features="$rb_cargo_features,yjit"
|
||||
])
|
||||
AS_IF([test x"${ZJIT_SUPPORT}" != x"no"], [
|
||||
AC_SUBST(ZJIT_TEST_FEATURES)
|
||||
rb_cargo_features="$rb_cargo_features,zjit"
|
||||
])
|
||||
# if YJIT and ZJIT release mode
|
||||
AS_IF([test "${YJIT_SUPPORT}:${ZJIT_SUPPORT}" = "yes:yes"], [
|
||||
JIT_CARGO_SUPPORT=release
|
||||
])
|
||||
CARGO_BUILD_ARGS="--profile ${JIT_CARGO_SUPPORT} --features ${rb_cargo_features}"
|
||||
AS_IF([test "${JIT_CARGO_SUPPORT}" = "dev"], [
|
||||
RUST_LIB="target/debug/libjit.a"
|
||||
], [
|
||||
RUST_LIB="target/${JIT_CARGO_SUPPORT}/libjit.a"
|
||||
])
|
||||
])
|
||||
|
||||
# In case either we're linking rust code
|
||||
AS_IF([test -n "$RUST_LIB"], [
|
||||
AS_CASE(["$target_os"],[openbsd*],[
|
||||
# Link libc++abi (which requires libpthread) for _Unwind_* functions needed by rust stdlib
|
||||
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
|
||||
])
|
||||
|
||||
# absolute path to stop the "target" dir in src dir from interfering through VPATH
|
||||
RUST_LIB="$(pwd)/${RUST_LIB}"
|
||||
])
|
||||
|
||||
dnl These variables end up in ::RbConfig::CONFIG
|
||||
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
|
||||
AC_SUBST(RUSTC)dnl Rust compiler command
|
||||
AC_SUBST(CARGO)dnl Cargo command for Rust builds
|
||||
AC_SUBST(CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
|
||||
AC_SUBST(ZJIT_CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
|
||||
AC_SUBST(YJIT_LIBS)dnl for optionally building the Rust parts of YJIT
|
||||
AC_SUBST(YJIT_SUPPORT)dnl what flavor of YJIT the Ruby build includes
|
||||
AC_SUBST(YJIT_LIBS)dnl the .a library of YJIT
|
||||
AC_SUBST(YJIT_OBJ)dnl for optionally building the C parts of YJIT
|
||||
AC_SUBST(ZJIT_SUPPORT)dnl what flavor of ZJIT the Ruby build includes
|
||||
AC_SUBST(ZJIT_LIBS)dnl for optionally building the Rust parts of ZJIT
|
||||
AC_SUBST(ZJIT_LIBS)dnl path to the .a library of ZJIT
|
||||
AC_SUBST(ZJIT_OBJ)dnl for optionally building the C parts of ZJIT
|
||||
AC_SUBST(JIT_OBJ)dnl for optionally building C glue code for Rust FFI
|
||||
AC_SUBST(RUST_LIB)dnl path to the rust .a library that contains either or both JITs
|
||||
AC_SUBST(JIT_CARGO_SUPPORT)dnl "no" or the cargo profile of the rust code
|
||||
}
|
||||
|
||||
[begin]_group "build section" && {
|
||||
|
|
19
cont.c
19
cont.c
|
@ -509,6 +509,9 @@ fiber_pool_allocate_memory(size_t * count, size_t stride)
|
|||
static struct fiber_pool_allocation *
|
||||
fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
|
||||
{
|
||||
struct fiber_pool_allocation * allocation;
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
STACK_GROW_DIR_DETECTION;
|
||||
|
||||
size_t size = fiber_pool->size;
|
||||
|
@ -522,7 +525,7 @@ fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
|
|||
}
|
||||
|
||||
struct fiber_pool_vacancy * vacancies = fiber_pool->vacancies;
|
||||
struct fiber_pool_allocation * allocation = RB_ALLOC(struct fiber_pool_allocation);
|
||||
allocation = RB_ALLOC(struct fiber_pool_allocation);
|
||||
|
||||
// Initialize fiber pool allocation:
|
||||
allocation->base = base;
|
||||
|
@ -543,7 +546,6 @@ fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
|
|||
for (size_t i = 0; i < count; i += 1) {
|
||||
void * base = (char*)allocation->base + (stride * i);
|
||||
void * page = (char*)base + STACK_DIR_UPPER(size, 0);
|
||||
|
||||
#if defined(_WIN32)
|
||||
DWORD old_protect;
|
||||
|
||||
|
@ -586,6 +588,8 @@ fiber_pool_expand(struct fiber_pool * fiber_pool, size_t count)
|
|||
fiber_pool->allocations = allocation;
|
||||
fiber_pool->vacancies = vacancies;
|
||||
fiber_pool->count += count;
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
|
||||
return allocation;
|
||||
}
|
||||
|
@ -659,7 +663,10 @@ fiber_pool_allocation_free(struct fiber_pool_allocation * allocation)
|
|||
static struct fiber_pool_stack
|
||||
fiber_pool_stack_acquire(struct fiber_pool * fiber_pool)
|
||||
{
|
||||
struct fiber_pool_vacancy * vacancy = fiber_pool_vacancy_pop(fiber_pool);
|
||||
struct fiber_pool_vacancy * vacancy ;
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
vacancy = fiber_pool_vacancy_pop(fiber_pool);
|
||||
|
||||
if (DEBUG) fprintf(stderr, "fiber_pool_stack_acquire: %p used=%"PRIuSIZE"\n", (void*)fiber_pool->vacancies, fiber_pool->used);
|
||||
|
||||
|
@ -694,6 +701,8 @@ fiber_pool_stack_acquire(struct fiber_pool * fiber_pool)
|
|||
#endif
|
||||
|
||||
fiber_pool_stack_reset(&vacancy->stack);
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
|
||||
return vacancy->stack;
|
||||
}
|
||||
|
@ -764,6 +773,8 @@ static void
|
|||
fiber_pool_stack_release(struct fiber_pool_stack * stack)
|
||||
{
|
||||
struct fiber_pool * pool = stack->pool;
|
||||
RB_VM_LOCK_ENTER();
|
||||
{
|
||||
struct fiber_pool_vacancy * vacancy = fiber_pool_vacancy_pointer(stack->base, stack->size);
|
||||
|
||||
if (DEBUG) fprintf(stderr, "fiber_pool_stack_release: %p used=%"PRIuSIZE"\n", stack->base, stack->pool->used);
|
||||
|
@ -798,6 +809,8 @@ fiber_pool_stack_release(struct fiber_pool_stack * stack)
|
|||
fiber_pool_stack_free(&vacancy->stack);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
RB_VM_LOCK_LEAVE();
|
||||
}
|
||||
|
||||
static inline void
|
||||
|
|
|
@ -315,6 +315,7 @@ RB_DEBUG_COUNTER(obj_imemo_parser_strterm)
|
|||
RB_DEBUG_COUNTER(obj_imemo_callinfo)
|
||||
RB_DEBUG_COUNTER(obj_imemo_callcache)
|
||||
RB_DEBUG_COUNTER(obj_imemo_constcache)
|
||||
RB_DEBUG_COUNTER(obj_imemo_fields)
|
||||
|
||||
RB_DEBUG_COUNTER(opt_new_hit)
|
||||
RB_DEBUG_COUNTER(opt_new_miss)
|
||||
|
|
|
@ -365,7 +365,7 @@ $(srcdir)/.bundle/.timestamp:
|
|||
define build-gem
|
||||
$(srcdir)/gems/src/$(1)/.git: | $(srcdir)/gems/src
|
||||
$(ECHO) Cloning $(4)
|
||||
$(Q) $(GIT) clone $(4) $$(@D)
|
||||
$(Q) $(GIT) clone --depth=1 --no-tags $(4) $$(@D)
|
||||
|
||||
$(bundled-gem-revision): \
|
||||
$(if $(if $(wildcard $$(@)),$(filter $(3),$(shell cat $$(@)))),,PHONY) \
|
||||
|
@ -443,6 +443,7 @@ endif
|
|||
|
||||
include $(top_srcdir)/yjit/yjit.mk
|
||||
include $(top_srcdir)/zjit/zjit.mk
|
||||
include $(top_srcdir)/defs/jit.mk
|
||||
|
||||
# Query on the generated rdoc
|
||||
#
|
||||
|
|
|
@ -63,6 +63,8 @@ firstline, predefined = __LINE__+1, %[\
|
|||
pack
|
||||
buffer
|
||||
include?
|
||||
aborted
|
||||
exited
|
||||
|
||||
_ UScore
|
||||
|
||||
|
|
64
defs/jit.mk
Normal file
64
defs/jit.mk
Normal file
|
@ -0,0 +1,64 @@
|
|||
# Make recipes that deal with the rust code of YJIT and ZJIT.
|
||||
|
||||
# Because of Cargo cache, if the actual binary is not changed from the
|
||||
# previous build, the mtime is preserved as the cached file.
|
||||
# This means the target is not updated actually, and it will need to
|
||||
# rebuild at the next build.
|
||||
RUST_LIB_TOUCH = touch $@
|
||||
|
||||
ifneq ($(JIT_CARGO_SUPPORT),no)
|
||||
|
||||
# Show Cargo progress when doing `make V=1`
|
||||
CARGO_VERBOSE_0 = -q
|
||||
CARGO_VERBOSE_1 =
|
||||
CARGO_VERBOSE = $(CARGO_VERBOSE_$(V))
|
||||
|
||||
# NOTE: MACOSX_DEPLOYMENT_TARGET to match `rustc --print deployment-target` to avoid the warning below.
|
||||
# ld: warning: object file (target/debug/libjit.a(<libcapstone object>)) was built for
|
||||
# newer macOS version (15.2) than being linked (15.0)
|
||||
# This limits us to an older set of macOS API in the rust code, but we don't use any.
|
||||
$(RUST_LIB): $(srcdir)/jit.rs
|
||||
$(Q)if [ '$(ZJIT_SUPPORT)' != no -a '$(YJIT_SUPPORT)' != no ]; then \
|
||||
echo 'building YJIT and ZJIT ($(JIT_CARGO_SUPPORT:yes=release) mode)'; \
|
||||
elif [ '$(ZJIT_SUPPORT)' != no ]; then \
|
||||
echo 'building ZJIT ($(JIT_CARGO_SUPPORT) mode)'; \
|
||||
elif [ '$(YJIT_SUPPORT)' != no ]; then \
|
||||
echo 'building YJIT ($(JIT_CARGO_SUPPORT) mode)'; \
|
||||
fi
|
||||
+$(Q)CARGO_TARGET_DIR='$(CARGO_TARGET_DIR)' \
|
||||
CARGO_TERM_PROGRESS_WHEN='never' \
|
||||
MACOSX_DEPLOYMENT_TARGET=11.0 \
|
||||
$(CARGO) $(CARGO_VERBOSE) build --manifest-path '$(top_srcdir)/Cargo.toml' $(CARGO_BUILD_ARGS)
|
||||
$(RUST_LIB_TOUCH)
|
||||
endif
|
||||
|
||||
RUST_LIB_SYMBOLS = $(RUST_LIB:.a=).symbols
|
||||
$(RUST_LIBOBJ): $(RUST_LIB)
|
||||
$(ECHO) 'partial linking $(RUST_LIB) into $@'
|
||||
ifneq ($(findstring darwin,$(target_os)),)
|
||||
$(Q) $(CC) -nodefaultlibs -r -o $@ -exported_symbols_list $(RUST_LIB_SYMBOLS) $(RUST_LIB)
|
||||
else
|
||||
$(Q) $(LD) -r -o $@ --whole-archive $(RUST_LIB)
|
||||
-$(Q) $(OBJCOPY) --wildcard --keep-global-symbol='$(SYMBOL_PREFIX)rb_*' $(@)
|
||||
endif
|
||||
|
||||
rust-libobj: $(RUST_LIBOBJ)
|
||||
rust-lib: $(RUST_LIB)
|
||||
|
||||
# For Darwin only: a list of symbols that we want the glommed Rust static lib to export.
|
||||
# Unfortunately, using wildcard like '_rb_*' with -exported-symbol does not work, at least
|
||||
# not on version 820.1. Assume llvm-nm, so XCode 8.0 (from 2016) or newer.
|
||||
#
|
||||
# The -exported_symbols_list pulls out the right archive members. Symbols not listed
|
||||
# in the list are made private extern, which are in turn made local as we're using `ld -r`.
|
||||
# Note, section about -keep_private_externs in ld's man page hints at this behavior on which
|
||||
# we rely.
|
||||
ifneq ($(findstring darwin,$(target_os)),)
|
||||
$(RUST_LIB_SYMBOLS): $(RUST_LIB)
|
||||
$(Q) $(tooldir)/darwin-ar $(NM) --defined-only --extern-only $(RUST_LIB) | \
|
||||
sed -n -e 's/.* //' -e '/^$(SYMBOL_PREFIX)rb_/p' \
|
||||
-e '/^$(SYMBOL_PREFIX)rust_eh_personality/p' \
|
||||
> $@
|
||||
|
||||
$(RUST_LIBOBJ): $(RUST_LIB_SYMBOLS)
|
||||
endif
|
4
dir.rb
4
dir.rb
|
@ -224,8 +224,8 @@ class Dir
|
|||
end
|
||||
|
||||
# call-seq:
|
||||
# Dir.glob(*patterns, flags: 0, base: nil, sort: true) -> array
|
||||
# Dir.glob(*patterns, flags: 0, base: nil, sort: true) {|entry_name| ... } -> nil
|
||||
# Dir.glob(patterns, flags: 0, base: nil, sort: true) -> array
|
||||
# Dir.glob(patterns, flags: 0, base: nil, sort: true) {|entry_name| ... } -> nil
|
||||
#
|
||||
# Forms an array _entry_names_ of the entry names selected by the arguments.
|
||||
#
|
||||
|
|
|
@ -439,6 +439,10 @@ without including the tags in the match:
|
|||
/(?<=<b>)\w+(?=<\/b>)/.match("Fortune favors the <b>bold</b>.")
|
||||
# => #<MatchData "bold">
|
||||
|
||||
The pattern in lookbehind must be fixed-width.
|
||||
But top-level alternatives can be of various lengths.
|
||||
ex. (?<=a|bc) is OK. (?<=aaa(?:b|cd)) is not allowed.
|
||||
|
||||
==== Match-Reset Anchor
|
||||
|
||||
- <tt>\K</tt>: Match reset:
|
||||
|
|
|
@ -37,7 +37,7 @@ Context-dependent case mapping as described in
|
|||
{Table 3-17 (Context Specification for Casing) of the Unicode standard}[https://www.unicode.org/versions/latest/ch03.pdf]
|
||||
is currently not supported.
|
||||
|
||||
In most cases, case conversions of a string have the same number of characters.
|
||||
In most cases, the case conversion of a string has the same number of characters as before.
|
||||
There are exceptions (see also +:fold+ below):
|
||||
|
||||
s = "\u00DF" # => "ß"
|
||||
|
@ -58,25 +58,18 @@ Case changes may not be reversible:
|
|||
s.downcase.upcase # => "HELLO WORLD!" # Different from original s.
|
||||
|
||||
Case changing methods may not maintain Unicode normalization.
|
||||
See String#unicode_normalize).
|
||||
See String#unicode_normalize.
|
||||
|
||||
== Options for Case Mapping
|
||||
== Case Mappings
|
||||
|
||||
Except for +casecmp+ and +casecmp?+,
|
||||
each of the case-mapping methods listed above
|
||||
accepts optional arguments, <tt>*options</tt>.
|
||||
accepts an optional argument, <tt>mapping</tt>.
|
||||
|
||||
The arguments may be:
|
||||
The argument is one of:
|
||||
|
||||
- +:ascii+ only.
|
||||
- +:fold+ only.
|
||||
- +:turkic+ or +:lithuanian+ or both.
|
||||
|
||||
The options:
|
||||
|
||||
- +:ascii+:
|
||||
ASCII-only mapping:
|
||||
uppercase letters ('A'..'Z') are mapped to lowercase letters ('a'..'z);
|
||||
- +:ascii+: ASCII-only mapping.
|
||||
Uppercase letters ('A'..'Z') are mapped to lowercase letters ('a'..'z);
|
||||
other characters are not changed
|
||||
|
||||
s = "Foo \u00D8 \u00F8 Bar" # => "Foo Ø ø Bar"
|
||||
|
@ -85,8 +78,8 @@ The options:
|
|||
s.upcase(:ascii) # => "FOO Ø ø BAR"
|
||||
s.downcase(:ascii) # => "foo Ø ø bar"
|
||||
|
||||
- +:turkic+:
|
||||
Full Unicode case mapping, adapted for the Turkic languages
|
||||
- +:turkic+: Full Unicode case mapping.
|
||||
For the Turkic languages
|
||||
that distinguish dotted and dotless I, for example Turkish and Azeri.
|
||||
|
||||
s = 'Türkiye' # => "Türkiye"
|
||||
|
@ -97,11 +90,8 @@ The options:
|
|||
s.downcase # => "türkiye"
|
||||
s.downcase(:turkic) # => "türkıye" # No dot above.
|
||||
|
||||
- +:lithuanian+:
|
||||
Not yet implemented.
|
||||
|
||||
- +:fold+ (available only for String#downcase, String#downcase!,
|
||||
and Symbol#downcase):
|
||||
and Symbol#downcase).
|
||||
Unicode case folding,
|
||||
which is more far-reaching than Unicode case mapping.
|
||||
|
||||
|
|
|
@ -260,11 +260,25 @@ This will add launch configurations for debugging Ruby itself by running `test.r
|
|||
|
||||
### Compiling for Debugging
|
||||
|
||||
You should configure Ruby without optimization and other flags that may
|
||||
interfere with debugging:
|
||||
You can compile Ruby with the `RUBY_DEBUG` macro to enable debugging on some
|
||||
features. One example is debugging object shapes in Ruby with
|
||||
`RubyVM::Shape.of(object)`.
|
||||
|
||||
Additionally Ruby can be compiled to support the `RUBY_DEBUG` environment
|
||||
variable to enable debugging on some features. An example is using
|
||||
`RUBY_DEBUG=gc_stress` to debug GC-related issues.
|
||||
|
||||
There is also support for the `RUBY_DEBUG_LOG` environment variable to log a
|
||||
lot of information about what the VM is doing, via the `USE_RUBY_DEBUG_LOG`
|
||||
macro.
|
||||
|
||||
You should also configure Ruby without optimization and other flags that may
|
||||
interfere with debugging by changing the optimization flags.
|
||||
|
||||
Bringing it all together:
|
||||
|
||||
```sh
|
||||
./configure --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"
|
||||
./configure cppflags="-DRUBY_DEBUG=1 -DUSE_RUBY_DEBUG_LOG=1" --enable-debug-env optflags="-O0 -fno-omit-frame-pointer"
|
||||
```
|
||||
|
||||
### Building with Address Sanitizer
|
||||
|
|
|
@ -7,7 +7,7 @@ in the Ruby core and in the Ruby standard library.
|
|||
## Generating documentation
|
||||
|
||||
Most Ruby documentation lives in the source files and is written in
|
||||
[RDoc format](rdoc-ref:RDoc::MarkupReference).
|
||||
[RDoc format](https://ruby.github.io/rdoc/RDoc/MarkupReference.html).
|
||||
|
||||
Some pages live under the `doc` folder and can be written in either
|
||||
`.rdoc` or `.md` format, determined by the file extension.
|
||||
|
@ -44,14 +44,13 @@ Use your judgment about what the user needs to know.
|
|||
- Group sentences into (ideally short) paragraphs,
|
||||
each covering a single topic.
|
||||
- Organize material with
|
||||
[headings](rdoc-ref:RDoc::MarkupReference@Headings).
|
||||
[headings].
|
||||
- Refer to authoritative and relevant sources using
|
||||
[links](rdoc-ref:RDoc::MarkupReference@Links).
|
||||
[links](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Links).
|
||||
- Use simple verb tenses: simple present, simple past, simple future.
|
||||
- Use simple sentence structure, not compound or complex structure.
|
||||
- Avoid:
|
||||
- Excessive comma-separated phrases;
|
||||
consider a [list](rdoc-ref:RDoc::MarkupReference@Lists).
|
||||
- Excessive comma-separated phrases; consider a [list].
|
||||
- Idioms and culture-specific references.
|
||||
- Overuse of headings.
|
||||
- Using US-ASCII-incompatible characters in C source files;
|
||||
|
@ -110,7 +109,7 @@ involving new files `doc/*.rdoc`:
|
|||
|
||||
Ruby is documented using RDoc.
|
||||
For information on \RDoc syntax and features, see the
|
||||
[RDoc Markup Reference](rdoc-ref:RDoc::MarkupReference).
|
||||
[RDoc Markup Reference](https://ruby.github.io/rdoc/RDoc/MarkupReference.html).
|
||||
|
||||
### Output from `irb`
|
||||
|
||||
|
@ -129,22 +128,21 @@ a #=> [2, 3, 1]
|
|||
|
||||
### Headings
|
||||
|
||||
Organize a long discussion for a class or module with [headings](rdoc-ref:RDoc::MarkupReference@Headings).
|
||||
Organize a long discussion for a class or module with [headings].
|
||||
|
||||
Do not use formal headings in the documentation for a method or constant.
|
||||
|
||||
In the rare case where heading-like structures are needed
|
||||
within the documentation for a method or constant, use
|
||||
[bold text](rdoc-ref:RDoc::MarkupReference@Bold)
|
||||
[bold text](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Bold)
|
||||
as pseudo-headings.
|
||||
|
||||
### Blank Lines
|
||||
|
||||
A blank line begins a new paragraph.
|
||||
|
||||
A [code block](rdoc-ref:RDoc::MarkupReference@Code+Blocks)
|
||||
or [list](rdoc-ref:RDoc::MarkupReference@Lists)
|
||||
should be preceded by and followed by a blank line.
|
||||
A [code block](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Code+Blocks)
|
||||
or [list] should be preceded by and followed by a blank line.
|
||||
This is unnecessary for the HTML output, but helps in the `ri` output.
|
||||
|
||||
### \Method Names
|
||||
|
@ -164,7 +162,7 @@ For a method name in text:
|
|||
|
||||
Code or commands embedded in running text (i.e., not in a code block)
|
||||
should marked up as
|
||||
[monofont](rdoc-ref:RDoc::MarkupReference@Monofont).
|
||||
[monofont].
|
||||
|
||||
Code that is a simple string should include the quote marks.
|
||||
|
||||
|
@ -214,7 +212,7 @@ refers to the current document
|
|||
(e.g., _Float_ in the documentation for class Float).
|
||||
|
||||
In this case you may consider forcing the name to
|
||||
[monofont](rdoc-ref:RDoc::MarkupReference@Monofont),
|
||||
[monofont],
|
||||
which suppresses auto-linking, and also emphasizes that the word is a class name:
|
||||
|
||||
```rdoc
|
||||
|
@ -276,7 +274,7 @@ Use the +rdoc-ref+ scheme for:
|
|||
- A link in a standard library package to other documentation in that same
|
||||
standard library package.
|
||||
|
||||
See section "+rdoc-ref+ Scheme" in {Links}[rdoc-ref:RDoc::MarkupReference@Links].
|
||||
See section "+rdoc-ref+ Scheme" in [links].
|
||||
|
||||
#### URL-Based Link
|
||||
|
||||
|
@ -296,7 +294,7 @@ Also use a full URL-based link for a link to an off-site document.
|
|||
### Variable Names
|
||||
|
||||
The name of a variable (as specified in its call-seq) should be marked up as
|
||||
[monofont](rdoc-ref:RDoc::MarkupReference@Monofont).
|
||||
[monofont].
|
||||
|
||||
Also, use monofont text for the name of a transient variable
|
||||
(i.e., one defined and used only in the discussion, such as +n+).
|
||||
|
@ -314,9 +312,9 @@ In particular, avoid building tables with HTML tags
|
|||
|
||||
Alternatives:
|
||||
|
||||
- A {verbatim text block}[rdoc-ref:RDoc::MarkupReference@Verbatim+Text+Blocks],
|
||||
- A {verbatim text block}[https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Verbatim+Text+Blocks],
|
||||
using spaces and punctuation to format the text;
|
||||
note that {text markup}[rdoc-ref:RDoc::MarkupReference@Text+Markup]
|
||||
note that {text markup}[https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Text+Markup]
|
||||
will not be honored:
|
||||
|
||||
- Example {source}[https://github.com/ruby/ruby/blob/34d802f32f00df1ac0220b62f72605827c16bad8/file.c#L6570-L6596].
|
||||
|
@ -356,8 +354,7 @@ Guidelines:
|
|||
|
||||
- The section title is `What's Here`.
|
||||
- Consider listing the parent class and any included modules; consider
|
||||
[links](rdoc-ref:RDoc::MarkupReference@Links)
|
||||
to their "What's Here" sections if those exist.
|
||||
[links] to their "What's Here" sections if those exist.
|
||||
- All methods mentioned in the left-pane table of contents
|
||||
should be listed (including any methods extended from another class).
|
||||
- Attributes (which are not included in the TOC) may also be listed.
|
||||
|
@ -369,7 +366,7 @@ Guidelines:
|
|||
(and do not list the aliases separately).
|
||||
- Check the rendered documentation to determine whether \RDoc has recognized
|
||||
the method and linked to it; if not, manually insert a
|
||||
[link](rdoc-ref:RDoc::MarkupReference@Links).
|
||||
[link](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Links).
|
||||
|
||||
- If there are numerous entries, consider grouping them into subsections with headings.
|
||||
- If there are more than a few such subsections,
|
||||
|
@ -395,7 +392,7 @@ For methods written in Ruby, \RDoc documents the calling sequence automatically.
|
|||
|
||||
For methods written in C, \RDoc cannot determine what arguments
|
||||
the method accepts, so those need to be documented using \RDoc directive
|
||||
[`call-seq:`](rdoc-ref:RDoc::MarkupReference@Directives+for+Method+Documentation).
|
||||
[`call-seq:`](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Directives+for+Method+Documentation).
|
||||
|
||||
For a singleton method, use the form:
|
||||
|
||||
|
@ -570,7 +567,7 @@ argument passed if it is not obvious, not explicitly mentioned in the
|
|||
details, and not implicitly shown in the examples.
|
||||
|
||||
If there is more than one argument or block argument, use a
|
||||
[labeled list](rdoc-ref:RDoc::MarkupReference@Labeled+Lists).
|
||||
[labeled list](https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Labeled+Lists).
|
||||
|
||||
### Corner Cases and Exceptions
|
||||
|
||||
|
@ -610,3 +607,7 @@ mention `Hash#fetch` as a related method, and `Hash#merge` might mention
|
|||
For methods that accept multiple argument types, in some cases it can
|
||||
be useful to document the different argument types separately. It's
|
||||
best to use a separate paragraph for each case you are discussing.
|
||||
|
||||
[headings]: https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Headings
|
||||
[list]: https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Lists
|
||||
[monofont]: https://ruby.github.io/rdoc/RDoc/MarkupReference.html#class-RDoc::MarkupReference-label-Monofont
|
||||
|
|
|
@ -8,6 +8,7 @@ Just a list of acronyms I've run across in the Ruby source code and their meanin
|
|||
| `bop` | Basic Operator. Relates to methods like `Integer` plus and minus which can be optimized as long as they haven't been redefined. |
|
||||
| `cc` | Call Cache. An inline cache structure for the call site. Stored in the `cd` |
|
||||
| `cd` | Call Data. A data structure that points at the `ci` and the `cc`. `iseq` objects points at the `cd`, and access call information and call caches via this structure |
|
||||
| CFG | Control Flow Graph. Representation of the program where all control-flow and data dependencies have been made explicit by unrolling the stack and local variables. |
|
||||
| `cfp`| Control Frame Pointer. Represents a Ruby stack frame. Calling a method pushes a new frame (cfp), returning pops a frame. Points at the `pc`, `sp`, `ep`, and the corresponding `iseq`|
|
||||
| `ci` | Call Information. Refers to an `rb_callinfo` struct. Contains call information about the call site, including number of parameters to be passed, whether it they are keyword arguments or not, etc. Used in conjunction with the `cc` and `cd`. |
|
||||
| `cref` | Class reference. A structure pointing to the class reference where `klass_or_self`, visibility scope, and refinements are stored. It also stores a pointer to the next class in the hierarchy referenced by `rb_cref_struct * next`. The Class reference is lexically scoped. |
|
||||
|
@ -25,10 +26,11 @@ Just a list of acronyms I've run across in the Ruby source code and their meanin
|
|||
| `insns` | Instructions. Usually an array of YARV instructions. |
|
||||
| `ivar` | Instance Variable. Refers to a Ruby instance variable like `@foo` |
|
||||
| `imemo` | Internal Memo. A tagged struct whose memory is managed by Ruby's GC, but contains internal information and isn't meant to be exposed to Ruby programs. Contains various information depending on the type. See the `imemo_type` enum for different types. |
|
||||
| `IVC` | Instance Variable Cache. Cache specifically for instance variable access |
|
||||
| JIT | Just In Time compiler |
|
||||
| `lep` | Local Environment Pointer. An `ep` which is tagged `VM_ENV_FLAG_LOCAL`. Usually this is the `ep` of a method (rather than a block, whose `ep` isn't "local") |
|
||||
| `local` | Local. Refers to a local variable. |
|
||||
| `me` | Method Entry. Refers to an `rb_method_entry_t` struct, the internal representation of a Ruby method.
|
||||
| `me` | Method Entry. Refers to an `rb_method_entry_t` struct, the internal representation of a Ruby method. |
|
||||
| MRI | Matz's Ruby Implementation |
|
||||
| `pc` | Program Counter. Usually the instruction that will be executed _next_ by the VM. Pointed to by the `cfp` and incremented by the VM |
|
||||
| `sp` | Stack Pointer. The top of the stack. The VM executes instructions in the `iseq` and instructions will push and pop values on the stack. The VM updates the `sp` on the `cfp` to point at the top of the stack|
|
||||
|
|
|
@ -8,7 +8,7 @@ This document outlines the expected way to distribute Ruby, with a specific focu
|
|||
|
||||
The tarball for official releases is created by the release manager. The release manager uploads the tarball to the [Ruby website](https://www.ruby-lang.org/en/downloads/).
|
||||
|
||||
Downstream distributors should use the official release tarballs as part of their build process. This ensures that the tarball is created in a consistent way, and that the tarball is crytographically verified.
|
||||
Downstream distributors should use the official release tarballs as part of their build process. This ensures that the tarball is created in a consistent way, and that the tarball is cryptographically verified.
|
||||
|
||||
### Using the nightly tarball for testing
|
||||
|
||||
|
|
58
doc/fiber.md
58
doc/fiber.md
|
@ -212,6 +212,64 @@ I/O. Windows is a notable example where socket I/O can be non-blocking but pipe
|
|||
I/O is blocking. Provided that there *is* a scheduler and the current thread *is
|
||||
non-blocking*, the operation will invoke the scheduler.
|
||||
|
||||
##### `IO#close`
|
||||
|
||||
Closing an IO interrupts all blocking operations on that IO. When a thread calls `IO#close`, it first attempts to interrupt any threads or fibers that are blocked on that IO. The closing thread waits until all blocked threads and fibers have been properly interrupted and removed from the IO's blocking list. Each interrupted thread or fiber receives an `IOError` and is cleanly removed from the blocking operation. Only after all blocking operations have been interrupted and cleaned up will the actual file descriptor be closed, ensuring proper resource cleanup and preventing potential race conditions.
|
||||
|
||||
For fibers managed by a scheduler, the interruption process involves calling `rb_fiber_scheduler_fiber_interrupt` on the scheduler. This allows the scheduler to handle the interruption in a way that's appropriate for its event loop implementation. The scheduler can then notify the fiber, which will receive an `IOError` and be removed from the blocking operation. This mechanism ensures that fiber-based concurrency works correctly with IO operations, even when those operations are interrupted by `IO#close`.
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant ThreadB
|
||||
participant ThreadA
|
||||
participant Scheduler
|
||||
participant IO
|
||||
participant Fiber1
|
||||
participant Fiber2
|
||||
|
||||
Note over ThreadA: Thread A has a fiber scheduler
|
||||
activate Scheduler
|
||||
ThreadA->>Fiber1: Schedule Fiber 1
|
||||
activate Fiber1
|
||||
Fiber1->>IO: IO.read
|
||||
IO->>Scheduler: rb_thread_io_blocking_region
|
||||
deactivate Fiber1
|
||||
|
||||
ThreadA->>Fiber2: Schedule Fiber 2
|
||||
activate Fiber2
|
||||
Fiber2->>IO: IO.read
|
||||
IO->>Scheduler: rb_thread_io_blocking_region
|
||||
deactivate Fiber2
|
||||
|
||||
Note over Fiber1,Fiber2: Both fibers blocked on same IO
|
||||
|
||||
Note over ThreadB: IO.close
|
||||
activate ThreadB
|
||||
ThreadB->>IO: thread_io_close_notify_all
|
||||
Note over ThreadB: rb_mutex_sleep
|
||||
|
||||
IO->>Scheduler: rb_fiber_scheduler_fiber_interrupt(Fiber1)
|
||||
Scheduler->>Fiber1: fiber_interrupt with IOError
|
||||
activate Fiber1
|
||||
Note over IO: fiber_interrupt causes removal from blocking list
|
||||
Fiber1->>IO: rb_io_blocking_operation_exit()
|
||||
IO-->>ThreadB: Wakeup thread
|
||||
deactivate Fiber1
|
||||
|
||||
IO->>Scheduler: rb_fiber_scheduler_fiber_interrupt(Fiber2)
|
||||
Scheduler->>Fiber2: fiber_interrupt with IOError
|
||||
activate Fiber2
|
||||
Note over IO: fiber_interrupt causes removal from blocking list
|
||||
Fiber2->>IO: rb_io_blocking_operation_exit()
|
||||
IO-->>ThreadB: Wakeup thread
|
||||
deactivate Fiber2
|
||||
deactivate Scheduler
|
||||
|
||||
Note over ThreadB: Blocking operations list empty
|
||||
ThreadB->>IO: close(fd)
|
||||
deactivate ThreadB
|
||||
```
|
||||
|
||||
#### Mutex
|
||||
|
||||
The `Mutex` class can be used in a non-blocking context and is fiber specific.
|
||||
|
|
|
@ -137,7 +137,7 @@ English - <tt>$DEFAULT_INPUT</tt>.
|
|||
|
||||
An output stream, initially <tt>$stdout</tt>.
|
||||
|
||||
English - <tt>$DEFAULT_OUTPUT
|
||||
English - <tt>$DEFAULT_OUTPUT</tt>
|
||||
|
||||
=== <tt>$.</tt> (Input Position)
|
||||
|
||||
|
|
|
@ -107,11 +107,9 @@ have commit right, others don't.
|
|||
* https://github.com/rubygems/rubygems
|
||||
* https://rubygems.org/gems/bundler
|
||||
|
||||
#### lib/cgi.rb, lib/cgi/*
|
||||
#### lib/cgi/escape.rb
|
||||
|
||||
* *unmaintained*
|
||||
* https://github.com/ruby/cgi
|
||||
* https://rubygems.org/gems/cgi
|
||||
|
||||
#### lib/English.rb
|
||||
|
||||
|
@ -234,12 +232,6 @@ have commit right, others don't.
|
|||
* https://github.com/ruby/securerandom
|
||||
* https://rubygems.org/gems/securerandom
|
||||
|
||||
#### lib/set.rb
|
||||
|
||||
* Akinori MUSHA ([knu])
|
||||
* https://github.com/ruby/set
|
||||
* https://rubygems.org/gems/set
|
||||
|
||||
#### lib/shellwords.rb
|
||||
|
||||
* Akinori MUSHA ([knu])
|
||||
|
@ -318,8 +310,6 @@ have commit right, others don't.
|
|||
#### ext/cgi
|
||||
|
||||
* Nobuyoshi Nakada ([nobu])
|
||||
* https://github.com/ruby/cgi
|
||||
* https://rubygems.org/gems/cgi
|
||||
|
||||
#### ext/date
|
||||
|
||||
|
|
363
doc/ractor.md
363
doc/ractor.md
|
@ -10,9 +10,9 @@ You can make multiple Ractors and they run in parallel.
|
|||
|
||||
* `Ractor.new{ expr }` creates a new Ractor and `expr` is run in parallel on a parallel computer.
|
||||
* Interpreter invokes with the first Ractor (called *main Ractor*).
|
||||
* If main Ractor terminated, all Ractors receive terminate request like Threads (if main thread (first invoked Thread), Ruby interpreter sends all running threads to terminate execution).
|
||||
* Each Ractor has 1 or more Threads.
|
||||
* Threads in a Ractor shares a Ractor-wide global lock like GIL (GVL in MRI terminology), so they can't run in parallel (without releasing GVL explicitly in C-level). Threads in different ractors run in parallel.
|
||||
* If the main Ractor terminates, all other Ractors receive termination requests, similar to how threads behave. (if main thread (first invoked Thread), Ruby interpreter sends all running threads to terminate execution).
|
||||
* Each Ractor contains one or more Threads.
|
||||
* Threads within the same Ractor share a Ractor-wide global lock like GIL (GVL in MRI terminology), so they can't run in parallel (without releasing GVL explicitly in C-level). Threads in different ractors run in parallel.
|
||||
* The overhead of creating a Ractor is similar to overhead of one Thread creation.
|
||||
|
||||
### Limited sharing between multiple ractors
|
||||
|
@ -31,20 +31,23 @@ Ractors don't share everything, unlike threads.
|
|||
* Ractor object itself.
|
||||
* And more...
|
||||
|
||||
### Two-types communication between Ractors
|
||||
### Communication between Ractors with `Ractor::Port`
|
||||
|
||||
Ractors communicate with each other and synchronize the execution by message exchanging between Ractors. There are two message exchange protocols: push type (message passing) and pull type.
|
||||
Ractors communicate with each other and synchronize the execution by message exchanging between Ractors. `Ractor::Port` is provided for this communication.
|
||||
|
||||
* Push type message passing: `Ractor#send(obj)` and `Ractor.receive()` pair.
|
||||
* Sender ractor passes the `obj` to the ractor `r` by `r.send(obj)` and receiver ractor receives the message with `Ractor.receive`.
|
||||
* Sender knows the destination Ractor `r` and the receiver does not know the sender (accept all messages from any ractors).
|
||||
* Receiver has infinite queue and sender enqueues the message. Sender doesn't block to put message into this queue.
|
||||
* This type of message exchanging is employed by many other Actor-based languages.
|
||||
* `Ractor.receive_if{ filter_expr }` is a variant of `Ractor.receive` to select a message.
|
||||
* Pull type communication: `Ractor.yield(obj)` and `Ractor#take()` pair.
|
||||
* Sender ractor declare to yield the `obj` by `Ractor.yield(obj)` and receiver Ractor take it with `r.take`.
|
||||
* Sender doesn't know a destination Ractor and receiver knows the sender Ractor `r`.
|
||||
* Sender or receiver will block if there is no other side.
|
||||
```ruby
|
||||
port = Ractor::Port.new
|
||||
|
||||
Ractor.new port do |port|
|
||||
# Other ractors can send to the port
|
||||
port << 42
|
||||
end
|
||||
|
||||
port.receive # get a message to the port. Only the creator Ractor can receive from the port
|
||||
#=> 42
|
||||
```
|
||||
|
||||
Ractors have its own deafult port and `Ractor#send`, `Ractor.receive` will use it.
|
||||
|
||||
### Copy & Move semantics to send messages
|
||||
|
||||
|
@ -66,7 +69,7 @@ Ractor helps to write a thread-safe concurrent program, but we can make thread-u
|
|||
* To make it compatible with old behavior, classes and modules can introduce data-race and so on.
|
||||
* Ruby programmers should take care if they modify class/module objects on multi Ractor programs.
|
||||
* BAD: Ractor can't solve all thread-safety problems
|
||||
* There are several blocking operations (waiting send, waiting yield and waiting take) so you can make a program which has dead-lock and live-lock issues.
|
||||
* There are several blocking operations (waiting send) so you can make a program which has dead-lock and live-lock issues.
|
||||
* Some kind of shareable objects can introduce transactions (STM, for example). However, misusing transactions will generate inconsistent state.
|
||||
|
||||
Without Ractor, we need to trace all state-mutations to debug thread-safety issues.
|
||||
|
@ -105,7 +108,7 @@ begin
|
|||
r = Ractor.new do
|
||||
a #=> ArgumentError because this block accesses `a`.
|
||||
end
|
||||
r.take # see later
|
||||
r.join # see later
|
||||
rescue ArgumentError
|
||||
end
|
||||
```
|
||||
|
@ -117,7 +120,7 @@ r = Ractor.new do
|
|||
p self.class #=> Ractor
|
||||
self.object_id
|
||||
end
|
||||
r.take == self.object_id #=> false
|
||||
r.value == self.object_id #=> false
|
||||
```
|
||||
|
||||
Passed arguments to `Ractor.new()` becomes block parameters for the given block. However, an interpreter does not pass the parameter object references, but send them as messages (see below for details).
|
||||
|
@ -126,7 +129,7 @@ Passed arguments to `Ractor.new()` becomes block parameters for the given block.
|
|||
r = Ractor.new 'ok' do |msg|
|
||||
msg #=> 'ok'
|
||||
end
|
||||
r.take #=> 'ok'
|
||||
r.value #=> 'ok'
|
||||
```
|
||||
|
||||
```ruby
|
||||
|
@ -136,7 +139,7 @@ r = Ractor.new do
|
|||
msg
|
||||
end
|
||||
r.send 'ok'
|
||||
r.take #=> 'ok'
|
||||
r.value #=> 'ok'
|
||||
```
|
||||
|
||||
### An execution result of given block
|
||||
|
@ -147,15 +150,7 @@ Return value of the given block becomes an outgoing message (see below for detai
|
|||
r = Ractor.new do
|
||||
'ok'
|
||||
end
|
||||
r.take #=> `ok`
|
||||
```
|
||||
|
||||
```ruby
|
||||
# almost similar to the last example
|
||||
r = Ractor.new do
|
||||
Ractor.yield 'ok'
|
||||
end
|
||||
r.take #=> 'ok'
|
||||
r.value #=> `ok`
|
||||
```
|
||||
|
||||
Error in the given block will be propagated to the receiver of an outgoing message.
|
||||
|
@ -166,7 +161,7 @@ r = Ractor.new do
|
|||
end
|
||||
|
||||
begin
|
||||
r.take
|
||||
r.value
|
||||
rescue Ractor::RemoteError => e
|
||||
e.cause.class #=> RuntimeError
|
||||
e.cause.message #=> 'ok'
|
||||
|
@ -178,9 +173,7 @@ end
|
|||
|
||||
Communication between Ractors is achieved by sending and receiving messages. There are two ways to communicate with each other.
|
||||
|
||||
* (1) Message sending/receiving
|
||||
* (1-1) push type send/receive (sender knows receiver). Similar to the Actor model.
|
||||
* (1-2) pull type yield/take (receiver knows sender).
|
||||
* (1) Message sending/receiving via `Ractor::Port`
|
||||
* (2) Using shareable container objects
|
||||
* Ractor::TVar gem ([ko1/ractor-tvar](https://github.com/ko1/ractor-tvar))
|
||||
* more?
|
||||
|
@ -189,18 +182,12 @@ Users can control program execution timing with (1), but should not control with
|
|||
|
||||
For message sending and receiving, there are two types of APIs: push type and pull type.
|
||||
|
||||
* (1-1) send/receive (push type)
|
||||
* `Ractor#send(obj)` (`Ractor#<<(obj)` is an alias) send a message to the Ractor's incoming port. Incoming port is connected to the infinite size incoming queue so `Ractor#send` will never block.
|
||||
* `Ractor.receive` dequeue a message from its own incoming queue. If the incoming queue is empty, `Ractor.receive` calling will block.
|
||||
* `Ractor.receive_if{|msg| filter_expr }` is variant of `Ractor.receive`. `receive_if` only receives a message which `filter_expr` is true (So `Ractor.receive` is the same as `Ractor.receive_if{ true }`.
|
||||
* (1-2) yield/take (pull type)
|
||||
* `Ractor.yield(obj)` send an message to a Ractor which are calling `Ractor#take` via outgoing port . If no Ractors are waiting for it, the `Ractor.yield(obj)` will block. If multiple Ractors are waiting for `Ractor.yield(obj)`, only one Ractor can receive the message.
|
||||
* `Ractor#take` receives a message which is waiting by `Ractor.yield(obj)` method from the specified Ractor. If the Ractor does not call `Ractor.yield` yet, the `Ractor#take` call will block.
|
||||
* `Ractor.select()` can wait for the success of `take`, `yield` and `receive`.
|
||||
* You can close the incoming port or outgoing port.
|
||||
* You can close then with `Ractor#close_incoming` and `Ractor#close_outgoing`.
|
||||
* If the incoming port is closed for a Ractor, you can't `send` to the Ractor. If `Ractor.receive` is blocked for the closed incoming port, then it will raise an exception.
|
||||
* If the outgoing port is closed for a Ractor, you can't call `Ractor#take` and `Ractor.yield` on the Ractor. If ractors are blocking by `Ractor#take` or `Ractor.yield`, closing outgoing port will raise an exception on these blocking ractors.
|
||||
* (1) send/receive via `Ractor::Port`.
|
||||
* `Ractor::Port#send(obj)` (`Ractor::Port#<<(obj)` is an alias) send a message to the port. Ports are connected to the infinite size incoming queue so `Ractor::Port#send` will never block.
|
||||
* `Ractor::Port#receive` dequeue a message from its own incoming queue. If the incoming queue is empty, `Ractor::Port#receive` calling will block the execution of a thread.
|
||||
* `Ractor.select()` can wait for the success of `Ractor::Port#receive`.
|
||||
* You can close `Ractor::Port` by `Ractor::Port#close` only by the creator Ractor of the port.
|
||||
* If the port is closed, you can't `send` to the port. If `Ractor::Port#receive` is blocked for the closed port, then it will raise an exception.
|
||||
* When a Ractor is terminated, the Ractor's ports are closed.
|
||||
* There are 3 ways to send an object as a message
|
||||
* (1) Send a reference: Sending a shareable object, send only a reference to the object (fast)
|
||||
|
@ -208,104 +195,15 @@ For message sending and receiving, there are two types of APIs: push type and pu
|
|||
* (3) Move an object: Sending an unshareable object reference with a membership. Sender Ractor can not access moved objects anymore (raise an exception) after moving it. Current implementation makes new object as a moved object for receiver Ractor and copies references of sending object to moved object. `T_DATA` objects are not supported.
|
||||
* You can choose "Copy" and "Move" by the `move:` keyword, `Ractor#send(obj, move: true/false)` and `Ractor.yield(obj, move: true/false)` (default is `false` (COPY)).
|
||||
|
||||
### Sending/Receiving ports
|
||||
|
||||
Each Ractor has _incoming-port_ and _outgoing-port_. Incoming-port is connected to the infinite sized incoming queue.
|
||||
|
||||
```
|
||||
Ractor r
|
||||
+-------------------------------------------+
|
||||
| incoming outgoing |
|
||||
| port port |
|
||||
r.send(obj) ->*->[incoming queue] Ractor.yield(obj) ->*-> r.take
|
||||
| | |
|
||||
| v |
|
||||
| Ractor.receive |
|
||||
+-------------------------------------------+
|
||||
|
||||
|
||||
Connection example: r2.send obj on r1、Ractor.receive on r2
|
||||
+----+ +----+
|
||||
* r1 |---->* r2 *
|
||||
+----+ +----+
|
||||
|
||||
|
||||
Connection example: Ractor.yield(obj) on r1, r1.take on r2
|
||||
+----+ +----+
|
||||
* r1 *---->- r2 *
|
||||
+----+ +----+
|
||||
|
||||
Connection example: Ractor.yield(obj) on r1 and r2,
|
||||
and waiting for both simultaneously by Ractor.select(r1, r2)
|
||||
|
||||
+----+
|
||||
* r1 *------+
|
||||
+----+ |
|
||||
+----> Ractor.select(r1, r2)
|
||||
+----+ |
|
||||
* r2 *------|
|
||||
+----+
|
||||
```
|
||||
|
||||
```ruby
|
||||
r = Ractor.new do
|
||||
msg = Ractor.receive # Receive from r's incoming queue
|
||||
msg # send back msg as block return value
|
||||
end
|
||||
r.send 'ok' # Send 'ok' to r's incoming port -> incoming queue
|
||||
r.take # Receive from r's outgoing port
|
||||
```
|
||||
|
||||
The last example shows the following ractor network.
|
||||
|
||||
```
|
||||
+------+ +---+
|
||||
* main |------> * r *---+
|
||||
+------+ +---+ |
|
||||
^ |
|
||||
+-------------------+
|
||||
```
|
||||
|
||||
And this code can be simplified by using an argument for `Ractor.new`.
|
||||
|
||||
```ruby
|
||||
# Actual argument 'ok' for `Ractor.new()` will be sent to created Ractor.
|
||||
r = Ractor.new 'ok' do |msg|
|
||||
# Values for formal parameters will be received from incoming queue.
|
||||
# Similar to: msg = Ractor.receive
|
||||
|
||||
msg # Return value of the given block will be sent via outgoing port
|
||||
end
|
||||
|
||||
# receive from the r's outgoing port.
|
||||
r.take #=> `ok`
|
||||
```
|
||||
|
||||
### Return value of a block for `Ractor.new`
|
||||
|
||||
As already explained, the return value of `Ractor.new` (an evaluated value of `expr` in `Ractor.new{ expr }`) can be taken by `Ractor#take`.
|
||||
|
||||
```ruby
|
||||
Ractor.new{ 42 }.take #=> 42
|
||||
```
|
||||
|
||||
When the block return value is available, the Ractor is dead so that no ractors except taken Ractor can touch the return value, so any values can be sent with this communication path without any modification.
|
||||
|
||||
```ruby
|
||||
r = Ractor.new do
|
||||
a = "hello"
|
||||
binding
|
||||
end
|
||||
|
||||
r.take.eval("p a") #=> "hello" (other communication path can not send a Binding object directly)
|
||||
```
|
||||
|
||||
### Wait for multiple Ractors with `Ractor.select`
|
||||
|
||||
You can wait multiple Ractor's `yield` with `Ractor.select(*ractors)`.
|
||||
The return value of `Ractor.select()` is `[r, msg]` where `r` is yielding Ractor and `msg` is yielded message.
|
||||
You can wait multiple Ractor port's receiving.
|
||||
The return value of `Ractor.select()` is `[port, msg]` where `port` is a ready port and `msg` is received message.
|
||||
|
||||
Wait for a single ractor (same as `Ractor.take`):
|
||||
To make convenient, `Ractor.select` can also accept Ractors to wait the termination of Ractors.
|
||||
The return value of `Ractor.select()` is `[r, msg]` where `r` is a terminated Ractor and `msg` is the value of Ractor's blcok.
|
||||
|
||||
Wait for a single ractor (same as `Ractor#value`):
|
||||
|
||||
```ruby
|
||||
r1 = Ractor.new{'r1'}
|
||||
|
@ -314,7 +212,7 @@ r, obj = Ractor.select(r1)
|
|||
r == r1 and obj == 'r1' #=> true
|
||||
```
|
||||
|
||||
Wait for two ractors:
|
||||
Waiting for two ractors:
|
||||
|
||||
```ruby
|
||||
r1 = Ractor.new{'r1'}
|
||||
|
@ -334,85 +232,29 @@ as << obj
|
|||
as.sort == ['r1', 'r2'] #=> true
|
||||
```
|
||||
|
||||
\Complex example:
|
||||
|
||||
```ruby
|
||||
pipe = Ractor.new do
|
||||
loop do
|
||||
Ractor.yield Ractor.receive
|
||||
end
|
||||
end
|
||||
|
||||
RN = 10
|
||||
rs = RN.times.map{|i|
|
||||
Ractor.new pipe, i do |pipe, i|
|
||||
msg = pipe.take
|
||||
msg # ping-pong
|
||||
end
|
||||
}
|
||||
RN.times{|i|
|
||||
pipe << i
|
||||
}
|
||||
RN.times.map{
|
||||
r, n = Ractor.select(*rs)
|
||||
rs.delete r
|
||||
n
|
||||
}.sort #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
```
|
||||
|
||||
Multiple Ractors can send to one Ractor.
|
||||
|
||||
```ruby
|
||||
# Create 10 ractors and they send objects to pipe ractor.
|
||||
# pipe ractor yield received objects
|
||||
|
||||
pipe = Ractor.new do
|
||||
loop do
|
||||
Ractor.yield Ractor.receive
|
||||
end
|
||||
end
|
||||
|
||||
RN = 10
|
||||
rs = RN.times.map{|i|
|
||||
Ractor.new pipe, i do |pipe, i|
|
||||
pipe << i
|
||||
end
|
||||
}
|
||||
|
||||
RN.times.map{
|
||||
pipe.take
|
||||
}.sort #=> [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
|
||||
```
|
||||
|
||||
TODO: Current `Ractor.select()` has the same issue of `select(2)`, so this interface should be refined.
|
||||
|
||||
TODO: `select` syntax of go-language uses round-robin technique to make fair scheduling. Now `Ractor.select()` doesn't use it.
|
||||
|
||||
### Closing Ractor's ports
|
||||
|
||||
* `Ractor#close_incoming/outgoing` close incoming/outgoing ports (similar to `Queue#close`).
|
||||
* `Ractor#close_incoming`
|
||||
* `r.send(obj)` where `r`'s incoming port is closed, will raise an exception.
|
||||
* When the incoming queue is empty and incoming port is closed, `Ractor.receive` raises an exception. If the incoming queue is not empty, it dequeues an object without exceptions.
|
||||
* `Ractor#close_outgoing`
|
||||
* `Ractor.yield` on a Ractor which closed the outgoing port, it will raise an exception.
|
||||
* `Ractor#take` for a Ractor which closed the outgoing port, it will raise an exception. If `Ractor#take` is blocking, it will raise an exception.
|
||||
* `Ractor::Port#close` close the ports (similar to `Queue#close`).
|
||||
* `port.send(obj)` where `port` is closed, will raise an exception.
|
||||
* When the queue connected to the port is empty and port is closed, `Ractor::Port#receive` raises an exception. If the queue is not empty, it dequeues an object without exceptions.
|
||||
* When a Ractor terminates, the ports are closed automatically.
|
||||
* Return value of the Ractor's block will be yielded as `Ractor.yield(ret_val)`, even if the implementation terminates the based native thread.
|
||||
|
||||
Example (try to take from closed Ractor):
|
||||
Example (try to get a result from closed Ractor):
|
||||
|
||||
```ruby
|
||||
r = Ractor.new do
|
||||
'finish'
|
||||
end
|
||||
r.take # success (will return 'finish')
|
||||
begin
|
||||
o = r.take # try to take from closed Ractor
|
||||
rescue Ractor::ClosedError
|
||||
'ok'
|
||||
else
|
||||
"ng: #{o}"
|
||||
r.join # success (wait for the termination)
|
||||
r.value # success (will return 'finish')
|
||||
|
||||
# the first Ractor which success the `Ractor#value` can get the result
|
||||
Ractor.new r do |r|
|
||||
r.value #=> Ractor::Error
|
||||
end
|
||||
```
|
||||
|
||||
|
@ -422,7 +264,7 @@ Example (try to send to closed (terminated) Ractor):
|
|||
r = Ractor.new do
|
||||
end
|
||||
|
||||
r.take # wait terminate
|
||||
r.join # wait terminate
|
||||
|
||||
begin
|
||||
r.send(1)
|
||||
|
@ -433,11 +275,9 @@ else
|
|||
end
|
||||
```
|
||||
|
||||
When multiple Ractors are waiting for `Ractor.yield()`, `Ractor#close_outgoing` will cancel all blocking by raising an exception (`ClosedError`).
|
||||
|
||||
### Send a message by copying
|
||||
|
||||
`Ractor#send(obj)` or `Ractor.yield(obj)` copy `obj` deeply if `obj` is an unshareable object.
|
||||
`Ractor::Port#send(obj)` copy `obj` deeply if `obj` is an unshareable object.
|
||||
|
||||
```ruby
|
||||
obj = 'str'.dup
|
||||
|
@ -446,7 +286,7 @@ r = Ractor.new obj do |msg|
|
|||
msg.object_id
|
||||
end
|
||||
|
||||
obj.object_id == r.take #=> false
|
||||
obj.object_id == r.value #=> false
|
||||
```
|
||||
|
||||
Some objects are not supported to copy the value, and raise an exception.
|
||||
|
@ -466,7 +306,7 @@ end
|
|||
|
||||
### Send a message by moving
|
||||
|
||||
`Ractor#send(obj, move: true)` or `Ractor.yield(obj, move: true)` move `obj` to the destination Ractor.
|
||||
`Ractor::Port#send(obj, move: true)` moves `obj` to the destination Ractor.
|
||||
If the source Ractor touches the moved object (for example, call the method like `obj.foo()`), it will be an error.
|
||||
|
||||
```ruby
|
||||
|
@ -478,7 +318,7 @@ end
|
|||
|
||||
str = 'hello'
|
||||
r.send str, move: true
|
||||
modified = r.take #=> 'hello world'
|
||||
modified = r.value #=> 'hello world'
|
||||
|
||||
# str is moved, and accessing str from this Ractor is prohibited
|
||||
|
||||
|
@ -492,22 +332,6 @@ else
|
|||
end
|
||||
```
|
||||
|
||||
```ruby
|
||||
# move with Ractor.yield
|
||||
r = Ractor.new do
|
||||
obj = 'hello'
|
||||
Ractor.yield obj, move: true
|
||||
obj << 'world' # raise Ractor::MovedError
|
||||
end
|
||||
|
||||
str = r.take
|
||||
begin
|
||||
r.take
|
||||
rescue Ractor::RemoteError
|
||||
p str #=> "hello"
|
||||
end
|
||||
```
|
||||
|
||||
Some objects are not supported to move, and an exception will be raised.
|
||||
|
||||
```ruby
|
||||
|
@ -554,13 +378,13 @@ r = Ractor.new do
|
|||
end
|
||||
|
||||
begin
|
||||
r.take
|
||||
r.join
|
||||
rescue Ractor::RemoteError => e
|
||||
e.cause.message #=> 'can not access global variables from non-main Ractors'
|
||||
end
|
||||
```
|
||||
|
||||
Note that some special global variables are ractor-local, like `$stdin`, `$stdout`, `$stderr`. See [[Bug #17268]](https://bugs.ruby-lang.org/issues/17268) for more details.
|
||||
Note that some special global variables, such as `$stdin`, `$stdout` and `$stderr` are Ractor-lcoal. See [[Bug #17268]](https://bugs.ruby-lang.org/issues/17268) for more details.
|
||||
|
||||
### Instance variables of shareable objects
|
||||
|
||||
|
@ -575,7 +399,7 @@ p Ractor.new do
|
|||
class C
|
||||
@iv
|
||||
end
|
||||
end.take #=> 1
|
||||
end.value #=> 1
|
||||
```
|
||||
|
||||
Otherwise, only the main Ractor can access instance variables of shareable objects.
|
||||
|
@ -601,7 +425,7 @@ Ractor.new do
|
|||
#=> "can not set instance variables of classes/modules by non-main Ractors"
|
||||
end
|
||||
end
|
||||
end.take
|
||||
end.join
|
||||
```
|
||||
|
||||
|
||||
|
@ -615,7 +439,7 @@ r = Ractor.new shared do |shared|
|
|||
end
|
||||
|
||||
begin
|
||||
r.take
|
||||
r.join
|
||||
rescue Ractor::RemoteError => e
|
||||
e.cause.message #=> can not access instance variables of shareable objects from non-main Ractors (Ractor::IsolationError)
|
||||
end
|
||||
|
@ -640,7 +464,7 @@ end
|
|||
|
||||
|
||||
begin
|
||||
r.take
|
||||
r.join
|
||||
rescue => e
|
||||
e.class #=> Ractor::IsolationError
|
||||
end
|
||||
|
@ -658,7 +482,7 @@ r = Ractor.new do
|
|||
C::CONST
|
||||
end
|
||||
begin
|
||||
r.take
|
||||
r.join
|
||||
rescue => e
|
||||
e.class #=> Ractor::IsolationError
|
||||
end
|
||||
|
@ -673,7 +497,7 @@ r = Ractor.new do
|
|||
C::CONST = 'str'
|
||||
end
|
||||
begin
|
||||
r.take
|
||||
r.join
|
||||
rescue => e
|
||||
e.class #=> Ractor::IsolationError
|
||||
end
|
||||
|
@ -770,54 +594,51 @@ end
|
|||
|
||||
### Worker pool
|
||||
|
||||
(1) One ractor has a pool
|
||||
|
||||
```ruby
|
||||
require 'prime'
|
||||
|
||||
pipe = Ractor.new do
|
||||
loop do
|
||||
Ractor.yield Ractor.receive
|
||||
end
|
||||
end
|
||||
|
||||
N = 1000
|
||||
RN = 10
|
||||
|
||||
# make RN workers
|
||||
workers = (1..RN).map do
|
||||
Ractor.new pipe do |pipe|
|
||||
while n = pipe.take
|
||||
Ractor.yield [n, n.prime?]
|
||||
Ractor.new do |; result_port|
|
||||
loop do
|
||||
n, result_port = Ractor.receive
|
||||
result_port << [n, n.prime?, Ractor.current]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
(1..N).each{|i|
|
||||
pipe << i
|
||||
}
|
||||
result_port = Ractor::Port.new
|
||||
results = []
|
||||
|
||||
pp (1..N).map{
|
||||
_r, (n, b) = Ractor.select(*workers)
|
||||
[n, b]
|
||||
}.sort_by{|(n, b)| n}
|
||||
(1..N).each do |i|
|
||||
if workers.empty?
|
||||
# receive a result
|
||||
n, result, w = result_port.receive
|
||||
results << [n, result]
|
||||
else
|
||||
w = workers.pop
|
||||
end
|
||||
|
||||
# send a task to the idle worker ractor
|
||||
w << [i, result_port]
|
||||
end
|
||||
|
||||
# receive a result
|
||||
while results.size != N
|
||||
n, result, _w = result_port.receive
|
||||
results << [n, result]
|
||||
end
|
||||
|
||||
pp results.sort_by{|n, result| n}
|
||||
```
|
||||
|
||||
### Pipeline
|
||||
|
||||
```ruby
|
||||
# pipeline with yield/take
|
||||
r1 = Ractor.new do
|
||||
'r1'
|
||||
end
|
||||
|
||||
r2 = Ractor.new r1 do |r1|
|
||||
r1.take + 'r2'
|
||||
end
|
||||
|
||||
r3 = Ractor.new r2 do |r2|
|
||||
r2.take + 'r3'
|
||||
end
|
||||
|
||||
p r3.take #=> 'r1r2r3'
|
||||
```
|
||||
|
||||
```ruby
|
||||
# pipeline with send/receive
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,7 +37,7 @@ programs for configuration and database persistence of Ruby object trees.
|
|||
|
||||
Similar to +Marshal+, it is able to deserialize into arbitrary Ruby classes.
|
||||
For example, the following YAML data will create an +ERB+ object when
|
||||
deserialized, using the `unsafe_load` method:
|
||||
deserialized, using the +unsafe_load+ method:
|
||||
|
||||
!ruby/object:ERB
|
||||
src: puts `uname`
|
||||
|
@ -53,19 +53,16 @@ method, variable and constant names. The reason for this is that symbols are
|
|||
simply integers with names attached to them, so they are faster to look up in
|
||||
hashtables.
|
||||
|
||||
Starting in version 2.2, most symbols can be garbage collected; these are
|
||||
called <i>mortal</i> symbols. Most symbols you create (e.g. by calling
|
||||
+to_sym+) are mortal.
|
||||
Most symbols can be garbage collected; these are called _mortal_
|
||||
symbols. Most symbols you create (e.g. by calling +to_sym+) are mortal.
|
||||
|
||||
<i>Immortal</i> symbols on the other hand will never be garbage collected.
|
||||
_Immortal_ symbols on the other hand will never be garbage collected.
|
||||
They are created when modifying code:
|
||||
* defining a method (e.g. with +define_method+),
|
||||
* setting an instance variable (e.g. with +instance_variable_set+),
|
||||
* creating a variable or constant (e.g. with +const_set+)
|
||||
C extensions that have not been updated and are still calling `SYM2ID`
|
||||
C extensions that have not been updated and are still calling +SYM2ID+
|
||||
will create immortal symbols.
|
||||
Bugs in 2.2.0: +send+ and +__send__+ also created immortal symbols,
|
||||
and calling methods with keyword arguments could also create some.
|
||||
|
||||
Don't create immortal symbols from user inputs. Otherwise, this would
|
||||
allow a user to mount a denial of service attack against your application by
|
||||
|
@ -128,12 +125,3 @@ Note that the use of +public_send+ is also dangerous, as +send+ itself is
|
|||
public:
|
||||
|
||||
1.public_send("send", "eval", "...ruby code to be executed...")
|
||||
|
||||
== DRb
|
||||
|
||||
As DRb allows remote clients to invoke arbitrary methods, it is not suitable to
|
||||
expose to untrusted clients.
|
||||
|
||||
When using DRb, try to avoid exposing it over the network if possible. If this
|
||||
isn't possible and you need to expose DRb to the world, you *must* configure an
|
||||
appropriate security policy with <code>DRb::ACL</code>.
|
||||
|
|
|
@ -34,7 +34,6 @@ of each.
|
|||
## Libraries
|
||||
|
||||
- Bundler ([GitHub][bundler]): Manage your Ruby application's gem dependencies
|
||||
- CGI ([GitHub][cgi]): Support for the Common Gateway Interface protocol
|
||||
- Delegator ([GitHub][delegate]): Provides three abilities to delegate method calls to an object
|
||||
- DidYouMean ([GitHub][did_you_mean]): "Did you mean?" experience in Ruby
|
||||
- English ([GitHub][English]): Provides references to special global variables with less cryptic names
|
||||
|
@ -53,12 +52,12 @@ of each.
|
|||
- Prism ([GitHub][prism]): A portable, error-tolerant Ruby parser
|
||||
- Resolv ([GitHub][resolv]): Thread-aware DNS resolver library in Ruby
|
||||
- SecureRandom ([GitHub][securerandom]): Interface for a secure random number generator
|
||||
- [Set](rdoc-ref:Set) ([GitHub][set]): Provides a class to deal with collections of unordered, unique values
|
||||
- Shellwords ([GitHub][shellwords]): Manipulates strings with the word parsing rules of the UNIX Bourne shell
|
||||
- Singleton ([GitHub][singleton]): Implementation of the Singleton pattern for Ruby
|
||||
- Tempfile ([GitHub][tempfile]): A utility class for managing temporary files
|
||||
- Time ([GitHub][time]): Extends the Time class with methods for parsing and conversion
|
||||
- Timeout ([GitHub][timeout]): Auto-terminate potentially long-running operations in Ruby
|
||||
- TmpDir ([GitHub][tmpdir]): Extends the Dir class to manage the OS temporary file path
|
||||
- TSort ([GitHub][tsort]): Topological sorting using Tarjan's algorithm
|
||||
- UN ([GitHub][un]): Utilities to replace common UNIX commands
|
||||
- URI ([GitHub][uri]): A Ruby module providing support for Uniform Resource Identifiers
|
||||
|
@ -72,13 +71,14 @@ of each.
|
|||
- Etc ([GitHub][etc]): Provides access to information typically stored in the UNIX /etc directory
|
||||
- Fcntl ([GitHub][fcntl]): Loads constants defined in the OS fcntl.h C header file
|
||||
- IO.console ([GitHub][io-console]): Extensions for the IO class, including `IO.console`, `IO.winsize`, etc.
|
||||
- IO#nonblock ([GitHub][io-nonblock]): Enable non-blocking mode with IO class.
|
||||
- IO#wait ([GitHub][io-wait]): Provides the feature for waiting until IO is readable or writable without blocking.
|
||||
- JSON ([GitHub][json]): Implements JavaScript Object Notation for Ruby
|
||||
- OpenSSL ([GitHub][openssl]): Provides SSL, TLS, and general-purpose cryptography for Ruby
|
||||
- Pathname ([GitHub][pathname]): Representation of the name of a file or directory on the filesystem
|
||||
- Psych ([GitHub][psych]): A YAML parser and emitter for Ruby
|
||||
- StringIO ([GitHub][stringio]): Pseudo-I/O on String objects
|
||||
- StringScanner ([GitHub][strscan]): Provides lexical scanning operations on a String
|
||||
- TmpDir ([GitHub][tmpdir]): Extends the Dir class to manage the OS temporary file path
|
||||
- Zlib ([GitHub][zlib]): Ruby interface for the zlib compression/decompression library
|
||||
|
||||
# Bundled gems
|
||||
|
@ -92,9 +92,9 @@ of each.
|
|||
|
||||
- [minitest]: A test library supporting TDD, BDD, mocking, and benchmarking
|
||||
- [power_assert]: Power Assert for Ruby
|
||||
- [rake]: Ruby build program with capabilities similar to make
|
||||
- [rake][rake-doc] ([GitHub][rake]): Ruby build program with capabilities similar to make
|
||||
- [test-unit]: A compatibility layer for MiniTest
|
||||
- [rexml]: An XML toolkit for Ruby
|
||||
- [rexml][rexml-doc] ([GitHub][rexml]): An XML toolkit for Ruby
|
||||
- [rss]: A family of libraries supporting various XML-based "feeds"
|
||||
- [net-ftp]: Support for the File Transfer Protocol
|
||||
- [net-imap]: Ruby client API for the Internet Message Access Protocol
|
||||
|
@ -105,7 +105,7 @@ of each.
|
|||
- [rbs]: RBS is a language to describe the structure of Ruby programs
|
||||
- [typeprof]: A type analysis tool for Ruby code based on abstract interpretation
|
||||
- [debug]: Debugging functionality for Ruby
|
||||
- [racc]: A LALR(1) parser generator written in Ruby
|
||||
- [racc][racc-doc] ([GitHub][racc]): A LALR(1) parser generator written in Ruby
|
||||
- [mutex_m]: Mixin to extend objects to be handled like a Mutex
|
||||
- [getoptlong]: Parse command line options similar to the GNU C getopt_long()
|
||||
- [base64]: Support for encoding and decoding binary data using a Base64 representation
|
||||
|
@ -117,13 +117,13 @@ of each.
|
|||
- [drb]: Distributed object system for Ruby
|
||||
- [nkf]: Ruby extension for the Network Kanji Filter
|
||||
- [syslog]: Ruby interface for the POSIX system logging facility
|
||||
- [csv]: Provides an interface to read and write CSV files and data
|
||||
- [csv][csv-doc] ([GitHub][csv]): Provides an interface to read and write CSV files and data
|
||||
- [ostruct]: A class to build custom data structures, similar to a Hash
|
||||
- [benchmark]: Provides methods to measure and report the time used to execute code
|
||||
- [logger]: Provides a simple logging utility for outputting messages
|
||||
- [logger][logger-doc] ([GitHub][logger]): Provides a simple logging utility for outputting messages
|
||||
- [pstore]: Implements a file-based persistence mechanism based on a Hash
|
||||
- [win32ole]: Provides an interface for OLE Automation in Ruby
|
||||
- [reline]: GNU Readline and Editline in a pure Ruby implementation
|
||||
- [reline][reline-doc] ([GitHub][reline]): GNU Readline and Editline in a pure Ruby implementation
|
||||
- [readline]: Wrapper for the Readline extension and Reline
|
||||
- [fiddle]: A libffi wrapper for Ruby
|
||||
|
||||
|
@ -137,7 +137,6 @@ of each.
|
|||
[benchmark]: https://github.com/ruby/benchmark
|
||||
[bigdecimal]: https://github.com/ruby/bigdecimal
|
||||
[bundler]: https://github.com/rubygems/rubygems
|
||||
[cgi]: https://github.com/ruby/cgi
|
||||
[csv]: https://github.com/ruby/csv
|
||||
[date]: https://github.com/ruby/date
|
||||
[debug]: https://github.com/ruby/debug
|
||||
|
@ -156,6 +155,8 @@ of each.
|
|||
[forwardable]: https://github.com/ruby/forwardable
|
||||
[getoptlong]: https://github.com/ruby/getoptlong
|
||||
[io-console]: https://github.com/ruby/io-console
|
||||
[io-nonblock]: https://github.com/ruby/io-nonblock
|
||||
[io-wait]: https://github.com/ruby/io-wait
|
||||
[ipaddr]: https://github.com/ruby/ipaddr
|
||||
[irb]: https://github.com/ruby/irb
|
||||
[json]: https://github.com/ruby/json
|
||||
|
@ -195,7 +196,6 @@ of each.
|
|||
[rinda]: https://github.com/ruby/rinda
|
||||
[rss]: https://github.com/ruby/rss
|
||||
[securerandom]: https://github.com/ruby/securerandom
|
||||
[set]: https://github.com/ruby/set
|
||||
[shellwords]: https://github.com/ruby/shellwords
|
||||
[singleton]: https://github.com/ruby/singleton
|
||||
[stringio]: https://github.com/ruby/stringio
|
||||
|
@ -215,5 +215,11 @@ of each.
|
|||
[yaml]: https://github.com/ruby/yaml
|
||||
[zlib]: https://github.com/ruby/zlib
|
||||
|
||||
[reline-doc]: https://ruby.github.io/reline/
|
||||
[rake-doc]: https://ruby.github.io/rake/
|
||||
[irb-doc]: https://ruby.github.io/irb/
|
||||
[rdoc-doc]: https://ruby.github.io/rdoc/
|
||||
[logger-doc]: https://ruby.github.io/logger/
|
||||
[racc-doc]: https://ruby.github.io/racc/
|
||||
[csv-doc]: https://ruby.github.io/csv/
|
||||
[rexml-doc]: https://ruby.github.io/rexml/
|
||||
|
|
|
@ -342,6 +342,8 @@
|
|||
#
|
||||
# - #=~: Returns the index of the first substring that matches a given
|
||||
# Regexp or other object; returns +nil+ if no match is found.
|
||||
# - #byteindex: Returns the byte index of the first occurrence of a given substring.
|
||||
# - #byterindex: Returns the byte index of the last occurrence of a given substring.
|
||||
# - #index: Returns the index of the _first_ occurrence of a given substring;
|
||||
# returns +nil+ if none found.
|
||||
# - #rindex: Returns the index of the _last_ occurrence of a given substring;
|
||||
|
@ -371,10 +373,9 @@
|
|||
# - #eql?: Returns +true+ if the content is the same as the given other string.
|
||||
# - #<=>: Returns -1, 0, or 1 as a given other string is smaller than,
|
||||
# equal to, or larger than +self+.
|
||||
# - #casecmp: Ignoring case, returns -1, 0, or 1 as a given
|
||||
# other string is smaller than, equal to, or larger than +self+.
|
||||
# - #casecmp?: Returns +true+ if the string is equal to a given string after Unicode case folding;
|
||||
# +false+ otherwise.
|
||||
# - #casecmp: Ignoring case, returns -1, 0, or 1 as
|
||||
# +self+ is smaller than, equal to, or larger than a given other string.
|
||||
# - #casecmp?: Ignoring case, returns whether a given other string is equal to +self+.
|
||||
#
|
||||
# === Modifying
|
||||
#
|
||||
|
@ -389,6 +390,7 @@
|
|||
#
|
||||
# _Substitution_
|
||||
#
|
||||
# - #bytesplice: Replaces bytes of +self+ with bytes from a given string; returns +self+.
|
||||
# - #sub!: Replaces the first substring that matches a given pattern with a given replacement string;
|
||||
# returns +self+ if any changes, +nil+ otherwise.
|
||||
# - #gsub!: Replaces each substring that matches a given pattern with a given replacement string;
|
||||
|
@ -425,6 +427,8 @@
|
|||
# - #slice!, #[]=: Removes a substring determined by a given index, start/length, range, regexp, or substring.
|
||||
# - #squeeze!: Removes contiguous duplicate characters; returns +self+.
|
||||
# - #delete!: Removes characters as determined by the intersection of substring arguments.
|
||||
# - #delete_prefix!: Removes leading prefix; returns +self+ if any changes, +nil+ otherwise.
|
||||
# - #delete_suffix!: Removes trailing suffix; returns +self+ if any changes, +nil+ otherwise.
|
||||
# - #lstrip!: Removes leading whitespace; returns +self+ if any changes, +nil+ otherwise.
|
||||
# - #rstrip!: Removes trailing whitespace; returns +self+ if any changes, +nil+ otherwise.
|
||||
# - #strip!: Removes leading and trailing whitespace; returns +self+ if any changes, +nil+ otherwise.
|
||||
|
@ -441,7 +445,7 @@
|
|||
#
|
||||
# - #*: Returns the concatenation of multiple copies of +self+.
|
||||
# - #+: Returns the concatenation of +self+ and a given other string.
|
||||
# - #center: Returns a copy of +self+ centered between pad substrings.
|
||||
# - #center: Returns a copy of +self+, centered by specified padding.
|
||||
# - #concat: Returns the concatenation of +self+ with given other strings.
|
||||
# - #prepend: Returns the concatenation of a given other string with +self+.
|
||||
# - #ljust: Returns a copy of +self+ of a given length, right-padded with a given other string.
|
|
@ -12,3 +12,5 @@ the underlying bytes are not modified:
|
|||
t = s.b # => "\xE4\x82\x95"
|
||||
t.encoding # => #<Encoding:ASCII-8BIT>
|
||||
t.bytes # => [228, 130, 149]
|
||||
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
||||
|
|
|
@ -4,3 +4,5 @@ Returns an array of the bytes in +self+:
|
|||
'тест'.bytes # => [209, 130, 208, 181, 209, 129, 209, 130]
|
||||
'こんにちは'.bytes
|
||||
# => [227, 129, 147, 227, 130, 147, 227, 129, 171, 227, 129, 161, 227, 129, 175]
|
||||
|
||||
Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
|
||||
|
|
|
@ -1,11 +1,15 @@
|
|||
Returns the count of bytes (not characters) in +self+:
|
||||
Returns the count of bytes in +self+.
|
||||
|
||||
'foo'.bytesize # => 3
|
||||
'тест'.bytesize # => 8
|
||||
'こんにちは'.bytesize # => 15
|
||||
Note that the byte count may be different from the character count (returned by #size):
|
||||
|
||||
Contrast with String#length:
|
||||
s = 'foo'
|
||||
s.bytesize # => 3
|
||||
s.size # => 3
|
||||
s = 'тест'
|
||||
s.bytesize # => 8
|
||||
s.size # => 4
|
||||
s = 'こんにちは'
|
||||
s.bytesize # => 15
|
||||
s.size # => 5
|
||||
|
||||
'foo'.length # => 3
|
||||
'тест'.length # => 4
|
||||
'こんにちは'.length # => 5
|
||||
Related: see {Querying}[rdoc-ref:String@Querying].
|
||||
|
|
54
doc/string/byteslice.rdoc
Normal file
54
doc/string/byteslice.rdoc
Normal file
|
@ -0,0 +1,54 @@
|
|||
Returns a substring of +self+, or +nil+ if the substring cannot be constructed.
|
||||
|
||||
With integer arguments +offset+ and +length+ given,
|
||||
returns the substring beginning at the given +offset+
|
||||
and of the given +length+ (as available):
|
||||
|
||||
s = '0123456789' # => "0123456789"
|
||||
s.byteslice(2) # => "2"
|
||||
s.byteslice(200) # => nil
|
||||
s.byteslice(4, 3) # => "456"
|
||||
s.byteslice(4, 30) # => "456789"
|
||||
|
||||
Returns +nil+ if +length+ is negative or +offset+ falls outside of +self+:
|
||||
|
||||
s.byteslice(4, -1) # => nil
|
||||
s.byteslice(40, 2) # => nil
|
||||
|
||||
Counts backwards from the end of +self+
|
||||
if +offset+ is negative:
|
||||
|
||||
s = '0123456789' # => "0123456789"
|
||||
s.byteslice(-4) # => "6"
|
||||
s.byteslice(-4, 3) # => "678"
|
||||
|
||||
With Range argument +range+ given, returns
|
||||
<tt>byteslice(range.begin, range.size)</tt>:
|
||||
|
||||
s = '0123456789' # => "0123456789"
|
||||
s.byteslice(4..6) # => "456"
|
||||
s.byteslice(-6..-4) # => "456"
|
||||
s.byteslice(5..2) # => "" # range.size is zero.
|
||||
s.byteslice(40..42) # => nil
|
||||
|
||||
The starting and ending offsets need not be on character boundaries:
|
||||
|
||||
s = 'こんにちは'
|
||||
s.byteslice(0, 3) # => "こ"
|
||||
s.byteslice(1, 3) # => "\x81\x93\xE3"
|
||||
|
||||
The encodings of +self+ and the returned substring
|
||||
are always the same:
|
||||
|
||||
s.encoding # => #<Encoding:UTF-8>
|
||||
s.byteslice(0, 3).encoding # => #<Encoding:UTF-8>
|
||||
s.byteslice(1, 3).encoding # => #<Encoding:UTF-8>
|
||||
|
||||
But, depending on the character boundaries,
|
||||
the encoding of the returned substring may not be valid:
|
||||
|
||||
s.valid_encoding? # => true
|
||||
s.byteslice(0, 3).valid_encoding? # => true
|
||||
s.byteslice(1, 3).valid_encoding? # => false
|
||||
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
66
doc/string/bytesplice.rdoc
Normal file
66
doc/string/bytesplice.rdoc
Normal file
|
@ -0,0 +1,66 @@
|
|||
Replaces <i>target bytes</i> in +self+ with <i>source bytes</i> from the given string +str+;
|
||||
returns +self+.
|
||||
|
||||
In the first form, arguments +offset+ and +length+ determine the target bytes,
|
||||
and the source bytes are all of the given +str+:
|
||||
|
||||
'0123456789'.bytesplice(0, 3, 'abc') # => "abc3456789"
|
||||
'0123456789'.bytesplice(3, 3, 'abc') # => "012abc6789"
|
||||
'0123456789'.bytesplice(0, 50, 'abc') # => "abc"
|
||||
'0123456789'.bytesplice(50, 3, 'abc') # Raises IndexError.
|
||||
|
||||
The counts of the target bytes and source source bytes may be different:
|
||||
|
||||
'0123456789'.bytesplice(0, 6, 'abc') # => "abc6789" # Shorter source.
|
||||
'0123456789'.bytesplice(0, 1, 'abc') # => "abc123456789" # Shorter target.
|
||||
|
||||
And either count may be zero (i.e., specifying an empty string):
|
||||
|
||||
'0123456789'.bytesplice(0, 3, '') # => "3456789" # Empty source.
|
||||
'0123456789'.bytesplice(0, 0, 'abc') # => "abc0123456789" # Empty target.
|
||||
|
||||
In the second form, just as in the first,
|
||||
arugments +offset+ and +length+ determine the target bytes;
|
||||
argument +str+ _contains_ the source bytes,
|
||||
and the additional arguments +str_offset+ and +str_length+
|
||||
determine the actual source bytes:
|
||||
|
||||
'0123456789'.bytesplice(0, 3, 'abc', 0, 3) # => "abc3456789"
|
||||
'0123456789'.bytesplice(0, 3, 'abc', 1, 1) # => "b3456789" # Shorter source.
|
||||
'0123456789'.bytesplice(0, 1, 'abc', 0, 3) # => "abc123456789" # Shorter target.
|
||||
'0123456789'.bytesplice(0, 3, 'abc', 1, 0) # => "3456789" # Empty source.
|
||||
'0123456789'.bytesplice(0, 0, 'abc', 0, 3) # => "abc0123456789" # Empty target.
|
||||
|
||||
In the third form, argument +range+ determines the target bytes
|
||||
and the source bytes are all of the given +str+:
|
||||
|
||||
'0123456789'.bytesplice(0..2, 'abc') # => "abc3456789"
|
||||
'0123456789'.bytesplice(3..5, 'abc') # => "012abc6789"
|
||||
'0123456789'.bytesplice(0..5, 'abc') # => "abc6789" # Shorter source.
|
||||
'0123456789'.bytesplice(0..0, 'abc') # => "abc123456789" # Shorter target.
|
||||
'0123456789'.bytesplice(0..2, '') # => "3456789" # Empty source.
|
||||
'0123456789'.bytesplice(0...0, 'abc') # => "abc0123456789" # Empty target.
|
||||
|
||||
In the fourth form, just as in the third,
|
||||
arugment +range+ determines the target bytes;
|
||||
argument +str+ _contains_ the source bytes,
|
||||
and the additional argument +str_range+
|
||||
determines the actual source bytes:
|
||||
|
||||
'0123456789'.bytesplice(0..2, 'abc', 0..2) # => "abc3456789"
|
||||
'0123456789'.bytesplice(3..5, 'abc', 0..2) # => "012abc6789"
|
||||
'0123456789'.bytesplice(0..2, 'abc', 0..1) # => "ab3456789" # Shorter source.
|
||||
'0123456789'.bytesplice(0..1, 'abc', 0..2) # => "abc23456789" # Shorter target.
|
||||
'0123456789'.bytesplice(0..2, 'abc', 0...0) # => "3456789" # Empty source.
|
||||
'0123456789'.bytesplice(0...0, 'abc', 0..2) # => "abc0123456789" # Empty target.
|
||||
|
||||
In any of the forms, the beginnings and endings of both source and target
|
||||
must be on character boundaries.
|
||||
|
||||
In these examples, +self+ has five 3-byte characters,
|
||||
and so has character boundaries at offsets 0, 3, 6, 9, 12, and 15.
|
||||
|
||||
'こんにちは'.bytesplice(0, 3, 'abc') # => "abcんにちは"
|
||||
'こんにちは'.bytesplice(1, 3, 'abc') # Raises IndexError.
|
||||
'こんにちは'.bytesplice(0, 2, 'abc') # Raises IndexError.
|
||||
|
|
@ -2,15 +2,19 @@ Returns a centered copy of +self+.
|
|||
|
||||
If integer argument +size+ is greater than the size (in characters) of +self+,
|
||||
returns a new string of length +size+ that is a copy of +self+,
|
||||
centered and padded on both ends with +pad_string+:
|
||||
centered and padded on one or both ends with +pad_string+:
|
||||
|
||||
'hello'.center(10) # => " hello "
|
||||
' hello'.center(10) # => " hello "
|
||||
'hello'.center(10, 'ab') # => "abhelloaba"
|
||||
'hello'.center(6) # => "hello " # Padded on one end.
|
||||
'hello'.center(10) # => " hello " # Padded on both ends.
|
||||
'hello'.center(20, '-|') # => "-|-|-|-hello-|-|-|-|" # Some padding repeated.
|
||||
'hello'.center(10, 'abcdefg') # => "abhelloabc" # Some padding not used.
|
||||
' hello '.center(13) # => " hello "
|
||||
'тест'.center(10) # => " тест "
|
||||
'こんにちは'.center(10) # => " こんにちは "
|
||||
'こんにちは'.center(10) # => " こんにちは " # Multi-byte characters.
|
||||
|
||||
If +size+ is not greater than the size of +self+, returns a copy of +self+:
|
||||
If +size+ is less than or equal to the size of +self+, returns an unpadded copy of +self+:
|
||||
|
||||
'hello'.center(5) # => "hello"
|
||||
'hello'.center(1) # => "hello"
|
||||
'hello'.center(-10) # => "hello"
|
||||
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
||||
|
|
|
@ -3,3 +3,6 @@ Returns an array of the characters in +self+:
|
|||
'hello'.chars # => ["h", "e", "l", "l", "o"]
|
||||
'тест'.chars # => ["т", "е", "с", "т"]
|
||||
'こんにちは'.chars # => ["こ", "ん", "に", "ち", "は"]
|
||||
''.chars # => []
|
||||
|
||||
Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
|
||||
|
|
|
@ -25,5 +25,8 @@ removes multiple trailing occurrences of <tt>"\n"</tt> or <tt>"\r\n"</tt>
|
|||
When +line_sep+ is neither <tt>"\n"</tt> nor <tt>''</tt>,
|
||||
removes a single trailing line separator if there is one:
|
||||
|
||||
'abcd'.chomp('d') # => "abc"
|
||||
'abcdd'.chomp('d') # => "abcd"
|
||||
'abcd'.chomp('cd') # => "ab"
|
||||
'abcdcd'.chomp('cd') # => "abcd"
|
||||
'abcd'.chomp('xx') # => "abcd"
|
||||
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
||||
|
|
|
@ -13,4 +13,7 @@ Otherwise removes the last character if it exists.
|
|||
'こんにちは'.chop # => "こんにち"
|
||||
''.chop # => ""
|
||||
|
||||
If you only need to remove the newline separator at the end of the string, String#chomp is a better alternative.
|
||||
If you only need to remove the newline separator at the end of the string,
|
||||
String#chomp is a better alternative.
|
||||
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
||||
|
|
8
doc/string/chr.rdoc
Normal file
8
doc/string/chr.rdoc
Normal file
|
@ -0,0 +1,8 @@
|
|||
Returns a string containing the first character of +self+:
|
||||
|
||||
'hello'.chr # => "h"
|
||||
'тест'.chr # => "т"
|
||||
'こんにちは'.chr # => "こ"
|
||||
''.chr # => ""
|
||||
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
|
@ -4,3 +4,6 @@ each codepoint is the integer value for a character:
|
|||
'hello'.codepoints # => [104, 101, 108, 108, 111]
|
||||
'тест'.codepoints # => [1090, 1077, 1089, 1090]
|
||||
'こんにちは'.codepoints # => [12371, 12435, 12395, 12385, 12399]
|
||||
''.codepoints # => []
|
||||
|
||||
Related: see {Converting to Non-String}[rdoc-ref:String@Converting+to+Non--5CString].
|
||||
|
|
12
doc/string/concat.rdoc
Normal file
12
doc/string/concat.rdoc
Normal file
|
@ -0,0 +1,12 @@
|
|||
Concatenates each object in +objects+ to +self+; returns +self+:
|
||||
|
||||
'foo'.concat('bar', 'baz') # => "foobarbaz"
|
||||
|
||||
For each given object +object+ that is an integer,
|
||||
the value is considered a codepoint and converted to a character before concatenation:
|
||||
|
||||
'foo'.concat(32, 'bar', 32, 'baz') # => "foo bar baz" # Embeds spaces.
|
||||
'те'.concat(1089, 1090) # => "тест"
|
||||
'こん'.concat(12395, 12385, 12399) # => "こんにちは"
|
||||
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
78
doc/string/count.rdoc
Normal file
78
doc/string/count.rdoc
Normal file
|
@ -0,0 +1,78 @@
|
|||
Returns the total number of characters in +self+ that are specified by the given selectors.
|
||||
|
||||
For one 1-character selector,
|
||||
returns the count of instances of that character:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.count('a') # => 5
|
||||
s.count('b') # => 2
|
||||
s.count('x') # => 0
|
||||
s.count('') # => 0
|
||||
|
||||
s = 'тест'
|
||||
s.count('т') # => 2
|
||||
s.count('е') # => 1
|
||||
|
||||
s = 'よろしくお願いします'
|
||||
s.count('よ') # => 1
|
||||
s.count('し') # => 2
|
||||
|
||||
For one multi-character selector,
|
||||
returns the count of instances for all specified characters:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.count('ab') # => 7
|
||||
s.count('abc') # => 8
|
||||
s.count('abcd') # => 9
|
||||
s.count('abcdr') # => 11
|
||||
s.count('abcdrx') # => 11
|
||||
|
||||
Order and repetition do not matter:
|
||||
|
||||
s.count('ba') == s.count('ab') # => true
|
||||
s.count('baab') == s.count('ab') # => true
|
||||
|
||||
For multiple selectors,
|
||||
forms a single selector that is the intersection of characters in all selectors
|
||||
and returns the count of instances for that selector:
|
||||
|
||||
s = 'abcdefg'
|
||||
s.count('abcde', 'dcbfg') == s.count('bcd') # => true
|
||||
s.count('abc', 'def') == s.count('') # => true
|
||||
|
||||
In a character selector, three characters get special treatment:
|
||||
|
||||
- A caret (<tt>'^'</tt>) functions as a _negation_ operator
|
||||
for the immediately following characters:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.count('^bc') # => 8 # Count of all except 'b' and 'c'.
|
||||
|
||||
- A hyphen (<tt>'-'</tt>) between two other characters defines a _range_ of characters:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.count('a-c') # => 8 # Count of all 'a', 'b', and 'c'.
|
||||
|
||||
- A backslash (<tt>'\'</tt>) acts as an escape for a caret, a hyphen,
|
||||
or another backslash:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.count('\^bc') # => 3 # Count of '^', 'b', and 'c'.
|
||||
s.count('a\-c') # => 6 # Count of 'a', '-', and 'c'.
|
||||
'foo\bar\baz'.count('\\') # => 2 # Count of '\'.
|
||||
|
||||
These usages may be mixed:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.count('a-cq-t') # => 10 # Multiple ranges.
|
||||
s.count('ac-d') # => 7 # Range mixed with plain characters.
|
||||
s.count('^a-c') # => 3 # Range mixed with negation.
|
||||
|
||||
For multiple selectors, all forms may be used, including negations, ranges, and escapes.
|
||||
|
||||
s = 'abracadabra'
|
||||
s.count('^abc', '^def') == s.count('^abcdef') # => true
|
||||
s.count('a-e', 'c-g') == s.count('cde') # => true
|
||||
s.count('^abc', 'c-g') == s.count('defg') # => true
|
||||
|
||||
Related: see {Querying}[rdoc-ref:String@Querying].
|
79
doc/string/delete.rdoc
Normal file
79
doc/string/delete.rdoc
Normal file
|
@ -0,0 +1,79 @@
|
|||
Returns a new string that is a copy of +self+ with certain characters removed;
|
||||
the removed characters are all instances of those specified by the given string +selectors+.
|
||||
|
||||
For one 1-character selector,
|
||||
removes all instances of that character:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.delete('a') # => "brcdbr"
|
||||
s.delete('b') # => "aracadara"
|
||||
s.delete('x') # => "abracadabra"
|
||||
s.delete('') # => "abracadabra"
|
||||
|
||||
s = 'тест'
|
||||
s.delete('т') # => "ес"
|
||||
s.delete('е') # => "тст"
|
||||
|
||||
s = 'よろしくお願いします'
|
||||
s.delete('よ') # => "ろしくお願いします"
|
||||
s.delete('し') # => "よろくお願います"
|
||||
|
||||
For one multi-character selector,
|
||||
removes all instances of the specified characters:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.delete('ab') # => "rcdr"
|
||||
s.delete('abc') # => "rdr"
|
||||
s.delete('abcd') # => "rr"
|
||||
s.delete('abcdr') # => ""
|
||||
s.delete('abcdrx') # => ""
|
||||
|
||||
Order and repetition do not matter:
|
||||
|
||||
s.delete('ba') == s.delete('ab') # => true
|
||||
s.delete('baab') == s.delete('ab') # => true
|
||||
|
||||
For multiple selectors,
|
||||
forms a single selector that is the intersection of characters in all selectors
|
||||
and removes all instances of characters specified by that selector:
|
||||
|
||||
s = 'abcdefg'
|
||||
s.delete('abcde', 'dcbfg') == s.delete('bcd') # => true
|
||||
s.delete('abc', 'def') == s.delete('') # => true
|
||||
|
||||
In a character selector, three characters get special treatment:
|
||||
|
||||
- A caret (<tt>'^'</tt>) functions as a _negation_ operator
|
||||
for the immediately following characters:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.delete('^bc') # => "bcb" # Deletes all except 'b' and 'c'.
|
||||
|
||||
- A hyphen (<tt>'-'</tt>) between two other characters defines a _range_ of characters:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.delete('a-c') # => "rdr" # Deletes all 'a', 'b', and 'c'.
|
||||
|
||||
- A backslash (<tt>'\'</tt>) acts as an escape for a caret, a hyphen,
|
||||
or another backslash:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.delete('\^bc') # => "araadara" # Deletes all '^', 'b', and 'c'.
|
||||
s.delete('a\-c') # => "brdbr" # Deletes all 'a', '-', and 'c'.
|
||||
'foo\bar\baz'.delete('\\') # => "foobarbaz" # Deletes all '\'.
|
||||
|
||||
These usages may be mixed:
|
||||
|
||||
s = 'abracadabra'
|
||||
s.delete('a-cq-t') # => "d" # Multiple ranges.
|
||||
s.delete('ac-d') # => "brbr" # Range mixed with plain characters.
|
||||
s.delete('^a-c') # => "abacaaba" # Range mixed with negation.
|
||||
|
||||
For multiple selectors, all forms may be used, including negations, ranges, and escapes.
|
||||
|
||||
s = 'abracadabra'
|
||||
s.delete('^abc', '^def') == s.delete('^abcdef') # => true
|
||||
s.delete('a-e', 'c-g') == s.delete('cde') # => true
|
||||
s.delete('^abc', 'c-g') == s.delete('defg') # => true
|
||||
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
|
@ -1,8 +1,10 @@
|
|||
Returns a copy of +self+ with leading substring <tt>prefix</tt> removed:
|
||||
Returns a copy of +self+ with leading substring +prefix+ removed:
|
||||
|
||||
'hello'.delete_prefix('hel') # => "lo"
|
||||
'hello'.delete_prefix('llo') # => "hello"
|
||||
'oof'.delete_prefix('o') # => "of"
|
||||
'oof'.delete_prefix('oo') # => "f"
|
||||
'oof'.delete_prefix('oof') # => ""
|
||||
'oof'.delete_prefix('x') # => "oof"
|
||||
'тест'.delete_prefix('те') # => "ст"
|
||||
'こんにちは'.delete_prefix('こん') # => "にちは"
|
||||
|
||||
Related: String#delete_prefix!, String#delete_suffix.
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
Returns a copy of +self+ with trailing substring <tt>suffix</tt> removed:
|
||||
|
||||
'hello'.delete_suffix('llo') # => "he"
|
||||
'hello'.delete_suffix('hel') # => "hello"
|
||||
'foo'.delete_suffix('o') # => "fo"
|
||||
'foo'.delete_suffix('oo') # => "f"
|
||||
'foo'.delete_suffix('foo') # => ""
|
||||
'foo'.delete_suffix('f') # => "foo"
|
||||
'foo'.delete_suffix('x') # => "foo"
|
||||
'тест'.delete_suffix('ст') # => "те"
|
||||
'こんにちは'.delete_suffix('ちは') # => "こんに"
|
||||
|
||||
Related: String#delete_suffix!, String#delete_prefix.
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
||||
|
|
12
doc/string/downcase.rdoc
Normal file
12
doc/string/downcase.rdoc
Normal file
|
@ -0,0 +1,12 @@
|
|||
Returns a new string containing the downcased characters in +self+:
|
||||
|
||||
'Hello, World!'.downcase # => "hello, world!"
|
||||
'ТЕСТ'.downcase # => "тест"
|
||||
'よろしくお願いします'.downcase # => "よろしくお願いします"
|
||||
|
||||
Some characters do not have upcased and downcased versions.
|
||||
|
||||
The casing may be affected by the given +mapping+;
|
||||
see {Case Mapping}[rdoc-ref:case_mapping.rdoc].
|
||||
|
||||
Related: see {Converting to New String}[rdoc-ref:String@Converting+to+New+String].
|
|
@ -17,6 +17,7 @@ editor.
|
|||
Ruby core development can be done either in Windows `cmd` like:
|
||||
|
||||
```batch
|
||||
ridk install
|
||||
ridk enable ucrt64
|
||||
|
||||
pacman -S --needed %MINGW_PACKAGE_PREFIX%-openssl %MINGW_PACKAGE_PREFIX%-libyaml %MINGW_PACKAGE_PREFIX%-libffi
|
||||
|
@ -37,6 +38,7 @@ make
|
|||
or in MSYS2 `bash` like:
|
||||
|
||||
```bash
|
||||
ridk install
|
||||
ridk enable ucrt64
|
||||
bash
|
||||
|
||||
|
@ -76,14 +78,37 @@ sh ../../ruby/configure -C --disable-install-doc --with-opt-dir=C:\Users\usernam
|
|||
x64.
|
||||
|
||||
The minimum requirement is here:
|
||||
* VC++/MSVC on VS 2017/2019 version build tools.
|
||||
* Visual Studio 2022 17.13.x is broken. see https://bugs.ruby-lang.org/issues/21167
|
||||
* VC++/MSVC on VS 2017/2019/2022 version build tools.
|
||||
* Windows 10/11 SDK
|
||||
* 10.0.26100 is broken, 10.0.22621 is recommended. see https://bugs.ruby-lang.org/issues/21255
|
||||
|
||||
3. Please set environment variable `INCLUDE`, `LIB`, `PATH`
|
||||
to run required commands properly from the command line.
|
||||
These are set properly by `vcvarall*.bat` usually.
|
||||
You can install Visual Studio Build Tools with `winget`.
|
||||
`win32\install-buildtools.cmd` is a batch file to install the
|
||||
minimum requirements excluding the IDE etc.
|
||||
|
||||
3. Please set environment variable `INCLUDE`, `LIB`, `PATH` to run
|
||||
required commands properly from the command line. These are set
|
||||
properly by `vsdevcmd.bat` or `vcvarall*.bat` usually. You can run
|
||||
the following command to set them in your command line.
|
||||
|
||||
To native build:
|
||||
|
||||
```
|
||||
cmd /k win32\vssetup.cmd
|
||||
```
|
||||
|
||||
To cross build arm64 binary:
|
||||
|
||||
```
|
||||
cmd /k win32\vssetup.cmd -arch arm64
|
||||
```
|
||||
|
||||
To cross build x64 binary:
|
||||
|
||||
```
|
||||
cmd /k win32\vssetup.cmd -arch x64
|
||||
```
|
||||
|
||||
See `win32\vssetup.cmd -help` for other command line options.
|
||||
|
||||
**Note** building ruby requires following commands.
|
||||
|
||||
|
|
44
doc/zjit.md
44
doc/zjit.md
|
@ -28,12 +28,12 @@ in a way that can be easily shared with other team members.
|
|||
|
||||
Make sure you have a `--enable-zjit=dev` build, and run `brew install cargo-nextest` first.
|
||||
|
||||
### make zjit-test-all
|
||||
### make zjit-check
|
||||
|
||||
This command runs all ZJIT tests: `make zjit-test` and `test/ruby/test_zjit.rb`.
|
||||
|
||||
```
|
||||
make zjit-test-all
|
||||
make zjit-check
|
||||
```
|
||||
|
||||
### make zjit-test
|
||||
|
@ -78,6 +78,16 @@ use `make`.
|
|||
|
||||
</details>
|
||||
|
||||
### make zjit-test-all
|
||||
|
||||
```
|
||||
make zjit-test-all
|
||||
```
|
||||
|
||||
This command runs all Ruby tests under `/test/ruby/` with ZJIT enabled.
|
||||
|
||||
Certain tests are excluded under `/test/.excludes-zjit`.
|
||||
|
||||
### test/ruby/test\_zjit.rb
|
||||
|
||||
This command runs Ruby execution tests.
|
||||
|
@ -91,3 +101,33 @@ You can also run a single test case by matching the method name:
|
|||
```
|
||||
make test-all TESTS="test/ruby/test_zjit.rb -n TestZJIT#test_putobject"
|
||||
```
|
||||
|
||||
## ZJIT Glossary
|
||||
|
||||
This glossary contains terms that are helpful for understanding ZJIT.
|
||||
|
||||
Please note that some terms may appear in CRuby internals too but with different meanings.
|
||||
|
||||
| Term | Definition |
|
||||
| --- | -----------|
|
||||
| HIR | High-level Intermediate Representation. High-level (Ruby semantics) graph representation in static single-assignment (SSA) form |
|
||||
| LIR | Low-level Intermediate Representation. Low-level IR used in the backend for assembly generation |
|
||||
| SSA | Static Single Assignment. A form where each variable is assigned exactly once |
|
||||
| `opnd` | Operand. An operand to an IR instruction (can be register, memory, immediate, etc.) |
|
||||
| `dst` | Destination. The output operand of an instruction where the result is stored |
|
||||
| VReg | Virtual Register. A virtual register that gets lowered to physical register or memory |
|
||||
| `insn_id` | Instruction ID. An index of an instruction in a function |
|
||||
| `block_id` | The index of a basic block, which effectively acts like a pointer |
|
||||
| `branch` | Control flow edge between basic blocks in the compiled code |
|
||||
| `cb` | Code Block. Memory region for generated machine code |
|
||||
| `entry` | The starting address of compiled code for an ISEQ |
|
||||
| Patch Point | Location in generated code that can be modified later in case assumptions get invalidated |
|
||||
| Frame State | Captured state of the Ruby stack frame at a specific point for deoptimization |
|
||||
| Guard | A run-time check that ensures assumptions are still valid |
|
||||
| `invariant` | An assumption that JIT code relies on, requiring invalidation if broken |
|
||||
| Deopt | Deoptimization. Process of falling back from JIT code to interpreter |
|
||||
| Side Exit | Exit from JIT code back to interpreter |
|
||||
| Type Lattice | Hierarchy of types used for type inference and optimization |
|
||||
| Constant Folding | Optimization that evaluates constant expressions at compile time |
|
||||
| RSP | x86-64 stack pointer register used for native stack operations |
|
||||
| Register Spilling | Process of moving register values to memory when running out of physical registers |
|
||||
|
|
66
enc/depend
66
enc/depend
|
@ -317,6 +317,7 @@ enc/ascii.$(OBJEXT): internal/intern/re.h
|
|||
enc/ascii.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/ascii.$(OBJEXT): internal/intern/select.h
|
||||
enc/ascii.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/ascii.$(OBJEXT): internal/intern/set.h
|
||||
enc/ascii.$(OBJEXT): internal/intern/signal.h
|
||||
enc/ascii.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/ascii.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -479,6 +480,7 @@ enc/big5.$(OBJEXT): internal/intern/re.h
|
|||
enc/big5.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/big5.$(OBJEXT): internal/intern/select.h
|
||||
enc/big5.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/big5.$(OBJEXT): internal/intern/set.h
|
||||
enc/big5.$(OBJEXT): internal/intern/signal.h
|
||||
enc/big5.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/big5.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -651,6 +653,7 @@ enc/cesu_8.$(OBJEXT): internal/intern/re.h
|
|||
enc/cesu_8.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/cesu_8.$(OBJEXT): internal/intern/select.h
|
||||
enc/cesu_8.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/cesu_8.$(OBJEXT): internal/intern/set.h
|
||||
enc/cesu_8.$(OBJEXT): internal/intern/signal.h
|
||||
enc/cesu_8.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/cesu_8.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -813,6 +816,7 @@ enc/cp949.$(OBJEXT): internal/intern/re.h
|
|||
enc/cp949.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/cp949.$(OBJEXT): internal/intern/select.h
|
||||
enc/cp949.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/cp949.$(OBJEXT): internal/intern/set.h
|
||||
enc/cp949.$(OBJEXT): internal/intern/signal.h
|
||||
enc/cp949.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/cp949.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -974,6 +978,7 @@ enc/emacs_mule.$(OBJEXT): internal/intern/re.h
|
|||
enc/emacs_mule.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/emacs_mule.$(OBJEXT): internal/intern/select.h
|
||||
enc/emacs_mule.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/emacs_mule.$(OBJEXT): internal/intern/set.h
|
||||
enc/emacs_mule.$(OBJEXT): internal/intern/signal.h
|
||||
enc/emacs_mule.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/emacs_mule.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -1145,6 +1150,7 @@ enc/encdb.$(OBJEXT): internal/intern/re.h
|
|||
enc/encdb.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/encdb.$(OBJEXT): internal/intern/select.h
|
||||
enc/encdb.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/encdb.$(OBJEXT): internal/intern/set.h
|
||||
enc/encdb.$(OBJEXT): internal/intern/signal.h
|
||||
enc/encdb.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/encdb.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -1309,6 +1315,7 @@ enc/euc_jp.$(OBJEXT): internal/intern/re.h
|
|||
enc/euc_jp.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/euc_jp.$(OBJEXT): internal/intern/select.h
|
||||
enc/euc_jp.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/euc_jp.$(OBJEXT): internal/intern/set.h
|
||||
enc/euc_jp.$(OBJEXT): internal/intern/signal.h
|
||||
enc/euc_jp.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/euc_jp.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -1470,6 +1477,7 @@ enc/euc_kr.$(OBJEXT): internal/intern/re.h
|
|||
enc/euc_kr.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/euc_kr.$(OBJEXT): internal/intern/select.h
|
||||
enc/euc_kr.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/euc_kr.$(OBJEXT): internal/intern/set.h
|
||||
enc/euc_kr.$(OBJEXT): internal/intern/signal.h
|
||||
enc/euc_kr.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/euc_kr.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -1631,6 +1639,7 @@ enc/euc_tw.$(OBJEXT): internal/intern/re.h
|
|||
enc/euc_tw.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/euc_tw.$(OBJEXT): internal/intern/select.h
|
||||
enc/euc_tw.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/euc_tw.$(OBJEXT): internal/intern/set.h
|
||||
enc/euc_tw.$(OBJEXT): internal/intern/signal.h
|
||||
enc/euc_tw.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/euc_tw.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -1792,6 +1801,7 @@ enc/gb18030.$(OBJEXT): internal/intern/re.h
|
|||
enc/gb18030.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/gb18030.$(OBJEXT): internal/intern/select.h
|
||||
enc/gb18030.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/gb18030.$(OBJEXT): internal/intern/set.h
|
||||
enc/gb18030.$(OBJEXT): internal/intern/signal.h
|
||||
enc/gb18030.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/gb18030.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -1953,6 +1963,7 @@ enc/gb2312.$(OBJEXT): internal/intern/re.h
|
|||
enc/gb2312.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/gb2312.$(OBJEXT): internal/intern/select.h
|
||||
enc/gb2312.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/gb2312.$(OBJEXT): internal/intern/set.h
|
||||
enc/gb2312.$(OBJEXT): internal/intern/signal.h
|
||||
enc/gb2312.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/gb2312.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -2114,6 +2125,7 @@ enc/gbk.$(OBJEXT): internal/intern/re.h
|
|||
enc/gbk.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/gbk.$(OBJEXT): internal/intern/select.h
|
||||
enc/gbk.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/gbk.$(OBJEXT): internal/intern/set.h
|
||||
enc/gbk.$(OBJEXT): internal/intern/signal.h
|
||||
enc/gbk.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/gbk.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -2276,6 +2288,7 @@ enc/iso_8859_1.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_1.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_1.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_1.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_1.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_1.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_1.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_1.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -2438,6 +2451,7 @@ enc/iso_8859_10.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_10.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_10.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_10.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_10.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_10.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_10.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_10.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -2599,6 +2613,7 @@ enc/iso_8859_11.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_11.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_11.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_11.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_11.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_11.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_11.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_11.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -2761,6 +2776,7 @@ enc/iso_8859_13.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_13.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_13.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_13.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_13.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_13.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_13.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_13.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -2923,6 +2939,7 @@ enc/iso_8859_14.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_14.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_14.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_14.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_14.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_14.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_14.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_14.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -3085,6 +3102,7 @@ enc/iso_8859_15.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_15.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_15.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_15.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_15.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_15.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_15.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_15.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -3247,6 +3265,7 @@ enc/iso_8859_16.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_16.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_16.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_16.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_16.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_16.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_16.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_16.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -3409,6 +3428,7 @@ enc/iso_8859_2.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_2.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_2.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_2.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_2.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_2.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_2.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_2.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -3571,6 +3591,7 @@ enc/iso_8859_3.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_3.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_3.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_3.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_3.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_3.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_3.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_3.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -3733,6 +3754,7 @@ enc/iso_8859_4.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_4.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_4.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_4.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_4.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_4.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_4.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_4.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -3894,6 +3916,7 @@ enc/iso_8859_5.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_5.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_5.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_5.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_5.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_5.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_5.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_5.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -4055,6 +4078,7 @@ enc/iso_8859_6.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_6.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_6.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_6.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_6.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_6.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_6.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_6.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -4216,6 +4240,7 @@ enc/iso_8859_7.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_7.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_7.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_7.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_7.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_7.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_7.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_7.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -4377,6 +4402,7 @@ enc/iso_8859_8.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_8.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_8.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_8.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_8.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_8.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_8.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_8.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -4539,6 +4565,7 @@ enc/iso_8859_9.$(OBJEXT): internal/intern/re.h
|
|||
enc/iso_8859_9.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/iso_8859_9.$(OBJEXT): internal/intern/select.h
|
||||
enc/iso_8859_9.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/iso_8859_9.$(OBJEXT): internal/intern/set.h
|
||||
enc/iso_8859_9.$(OBJEXT): internal/intern/signal.h
|
||||
enc/iso_8859_9.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/iso_8859_9.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -4700,6 +4727,7 @@ enc/koi8_r.$(OBJEXT): internal/intern/re.h
|
|||
enc/koi8_r.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/koi8_r.$(OBJEXT): internal/intern/select.h
|
||||
enc/koi8_r.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/koi8_r.$(OBJEXT): internal/intern/set.h
|
||||
enc/koi8_r.$(OBJEXT): internal/intern/signal.h
|
||||
enc/koi8_r.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/koi8_r.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -4861,6 +4889,7 @@ enc/koi8_u.$(OBJEXT): internal/intern/re.h
|
|||
enc/koi8_u.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/koi8_u.$(OBJEXT): internal/intern/select.h
|
||||
enc/koi8_u.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/koi8_u.$(OBJEXT): internal/intern/set.h
|
||||
enc/koi8_u.$(OBJEXT): internal/intern/signal.h
|
||||
enc/koi8_u.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/koi8_u.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -5025,6 +5054,7 @@ enc/shift_jis.$(OBJEXT): internal/intern/re.h
|
|||
enc/shift_jis.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/shift_jis.$(OBJEXT): internal/intern/select.h
|
||||
enc/shift_jis.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/shift_jis.$(OBJEXT): internal/intern/set.h
|
||||
enc/shift_jis.$(OBJEXT): internal/intern/signal.h
|
||||
enc/shift_jis.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/shift_jis.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -5185,6 +5215,7 @@ enc/trans/big5.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/big5.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/big5.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/big5.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/big5.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/big5.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/big5.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/big5.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -5344,6 +5375,7 @@ enc/trans/cesu_8.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/cesu_8.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/cesu_8.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/cesu_8.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/cesu_8.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/cesu_8.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/cesu_8.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/cesu_8.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -5503,6 +5535,7 @@ enc/trans/chinese.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/chinese.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/chinese.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/chinese.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/chinese.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/chinese.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/chinese.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/chinese.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -5662,6 +5695,7 @@ enc/trans/ebcdic.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/ebcdic.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/ebcdic.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/ebcdic.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/ebcdic.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/ebcdic.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/ebcdic.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/ebcdic.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -5821,6 +5855,7 @@ enc/trans/emoji.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/emoji.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/emoji.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/emoji.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/emoji.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/emoji.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/emoji.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/emoji.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -5980,6 +6015,7 @@ enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/emoji_iso2022_kddi.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -6139,6 +6175,7 @@ enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/emoji_sjis_docomo.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -6298,6 +6335,7 @@ enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/emoji_sjis_kddi.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -6457,6 +6495,7 @@ enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/emoji_sjis_softbank.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -6616,6 +6655,7 @@ enc/trans/escape.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/escape.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/escape.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/escape.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/escape.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/escape.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/escape.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/escape.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -6775,6 +6815,7 @@ enc/trans/gb18030.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/gb18030.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/gb18030.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/gb18030.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/gb18030.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/gb18030.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/gb18030.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/gb18030.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -6934,6 +6975,7 @@ enc/trans/gbk.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/gbk.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/gbk.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/gbk.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/gbk.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/gbk.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/gbk.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/gbk.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -7094,6 +7136,7 @@ enc/trans/iso2022.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/iso2022.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/iso2022.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/iso2022.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/iso2022.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/iso2022.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/iso2022.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/iso2022.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -7253,6 +7296,7 @@ enc/trans/japanese.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/japanese.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/japanese.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/japanese.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/japanese.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/japanese.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/japanese.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/japanese.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -7412,6 +7456,7 @@ enc/trans/japanese_euc.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/japanese_euc.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/japanese_euc.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/japanese_euc.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/japanese_euc.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/japanese_euc.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/japanese_euc.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/japanese_euc.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -7571,6 +7616,7 @@ enc/trans/japanese_sjis.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/japanese_sjis.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -7730,6 +7776,7 @@ enc/trans/korean.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/korean.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/korean.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/korean.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/korean.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/korean.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/korean.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/korean.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -7888,6 +7935,7 @@ enc/trans/newline.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/newline.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/newline.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/newline.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/newline.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/newline.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/newline.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/newline.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -8047,6 +8095,7 @@ enc/trans/single_byte.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/single_byte.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/single_byte.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/single_byte.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/single_byte.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/single_byte.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/single_byte.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/single_byte.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -8206,6 +8255,7 @@ enc/trans/transdb.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/transdb.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/transdb.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/transdb.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/transdb.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/transdb.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/transdb.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/transdb.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -8366,6 +8416,7 @@ enc/trans/utf8_mac.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/utf8_mac.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/utf8_mac.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/utf8_mac.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/utf8_mac.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/utf8_mac.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/utf8_mac.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/utf8_mac.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -8525,6 +8576,7 @@ enc/trans/utf_16_32.$(OBJEXT): internal/intern/re.h
|
|||
enc/trans/utf_16_32.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/trans/utf_16_32.$(OBJEXT): internal/intern/select.h
|
||||
enc/trans/utf_16_32.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/trans/utf_16_32.$(OBJEXT): internal/intern/set.h
|
||||
enc/trans/utf_16_32.$(OBJEXT): internal/intern/signal.h
|
||||
enc/trans/utf_16_32.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/trans/utf_16_32.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -8687,6 +8739,7 @@ enc/unicode.$(OBJEXT): internal/intern/re.h
|
|||
enc/unicode.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/unicode.$(OBJEXT): internal/intern/select.h
|
||||
enc/unicode.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/unicode.$(OBJEXT): internal/intern/set.h
|
||||
enc/unicode.$(OBJEXT): internal/intern/signal.h
|
||||
enc/unicode.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/unicode.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -8858,6 +8911,7 @@ enc/us_ascii.$(OBJEXT): internal/intern/re.h
|
|||
enc/us_ascii.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/us_ascii.$(OBJEXT): internal/intern/select.h
|
||||
enc/us_ascii.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/us_ascii.$(OBJEXT): internal/intern/set.h
|
||||
enc/us_ascii.$(OBJEXT): internal/intern/signal.h
|
||||
enc/us_ascii.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/us_ascii.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -9021,6 +9075,7 @@ enc/utf_16be.$(OBJEXT): internal/intern/re.h
|
|||
enc/utf_16be.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/utf_16be.$(OBJEXT): internal/intern/select.h
|
||||
enc/utf_16be.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/utf_16be.$(OBJEXT): internal/intern/set.h
|
||||
enc/utf_16be.$(OBJEXT): internal/intern/signal.h
|
||||
enc/utf_16be.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/utf_16be.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -9183,6 +9238,7 @@ enc/utf_16le.$(OBJEXT): internal/intern/re.h
|
|||
enc/utf_16le.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/utf_16le.$(OBJEXT): internal/intern/select.h
|
||||
enc/utf_16le.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/utf_16le.$(OBJEXT): internal/intern/set.h
|
||||
enc/utf_16le.$(OBJEXT): internal/intern/signal.h
|
||||
enc/utf_16le.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/utf_16le.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -9345,6 +9401,7 @@ enc/utf_32be.$(OBJEXT): internal/intern/re.h
|
|||
enc/utf_32be.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/utf_32be.$(OBJEXT): internal/intern/select.h
|
||||
enc/utf_32be.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/utf_32be.$(OBJEXT): internal/intern/set.h
|
||||
enc/utf_32be.$(OBJEXT): internal/intern/signal.h
|
||||
enc/utf_32be.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/utf_32be.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -9507,6 +9564,7 @@ enc/utf_32le.$(OBJEXT): internal/intern/re.h
|
|||
enc/utf_32le.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/utf_32le.$(OBJEXT): internal/intern/select.h
|
||||
enc/utf_32le.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/utf_32le.$(OBJEXT): internal/intern/set.h
|
||||
enc/utf_32le.$(OBJEXT): internal/intern/signal.h
|
||||
enc/utf_32le.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/utf_32le.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -9678,6 +9736,7 @@ enc/utf_8.$(OBJEXT): internal/intern/re.h
|
|||
enc/utf_8.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/utf_8.$(OBJEXT): internal/intern/select.h
|
||||
enc/utf_8.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/utf_8.$(OBJEXT): internal/intern/set.h
|
||||
enc/utf_8.$(OBJEXT): internal/intern/signal.h
|
||||
enc/utf_8.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/utf_8.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -9841,6 +9900,7 @@ enc/windows_1250.$(OBJEXT): internal/intern/re.h
|
|||
enc/windows_1250.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/windows_1250.$(OBJEXT): internal/intern/select.h
|
||||
enc/windows_1250.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/windows_1250.$(OBJEXT): internal/intern/set.h
|
||||
enc/windows_1250.$(OBJEXT): internal/intern/signal.h
|
||||
enc/windows_1250.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/windows_1250.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -10002,6 +10062,7 @@ enc/windows_1251.$(OBJEXT): internal/intern/re.h
|
|||
enc/windows_1251.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/windows_1251.$(OBJEXT): internal/intern/select.h
|
||||
enc/windows_1251.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/windows_1251.$(OBJEXT): internal/intern/set.h
|
||||
enc/windows_1251.$(OBJEXT): internal/intern/signal.h
|
||||
enc/windows_1251.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/windows_1251.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -10164,6 +10225,7 @@ enc/windows_1252.$(OBJEXT): internal/intern/re.h
|
|||
enc/windows_1252.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/windows_1252.$(OBJEXT): internal/intern/select.h
|
||||
enc/windows_1252.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/windows_1252.$(OBJEXT): internal/intern/set.h
|
||||
enc/windows_1252.$(OBJEXT): internal/intern/signal.h
|
||||
enc/windows_1252.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/windows_1252.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -10325,6 +10387,7 @@ enc/windows_1253.$(OBJEXT): internal/intern/re.h
|
|||
enc/windows_1253.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/windows_1253.$(OBJEXT): internal/intern/select.h
|
||||
enc/windows_1253.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/windows_1253.$(OBJEXT): internal/intern/set.h
|
||||
enc/windows_1253.$(OBJEXT): internal/intern/signal.h
|
||||
enc/windows_1253.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/windows_1253.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -10487,6 +10550,7 @@ enc/windows_1254.$(OBJEXT): internal/intern/re.h
|
|||
enc/windows_1254.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/windows_1254.$(OBJEXT): internal/intern/select.h
|
||||
enc/windows_1254.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/windows_1254.$(OBJEXT): internal/intern/set.h
|
||||
enc/windows_1254.$(OBJEXT): internal/intern/signal.h
|
||||
enc/windows_1254.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/windows_1254.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -10649,6 +10713,7 @@ enc/windows_1257.$(OBJEXT): internal/intern/re.h
|
|||
enc/windows_1257.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/windows_1257.$(OBJEXT): internal/intern/select.h
|
||||
enc/windows_1257.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/windows_1257.$(OBJEXT): internal/intern/set.h
|
||||
enc/windows_1257.$(OBJEXT): internal/intern/signal.h
|
||||
enc/windows_1257.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/windows_1257.$(OBJEXT): internal/intern/string.h
|
||||
|
@ -10813,6 +10878,7 @@ enc/windows_31j.$(OBJEXT): internal/intern/re.h
|
|||
enc/windows_31j.$(OBJEXT): internal/intern/ruby.h
|
||||
enc/windows_31j.$(OBJEXT): internal/intern/select.h
|
||||
enc/windows_31j.$(OBJEXT): internal/intern/select/largesize.h
|
||||
enc/windows_31j.$(OBJEXT): internal/intern/set.h
|
||||
enc/windows_31j.$(OBJEXT): internal/intern/signal.h
|
||||
enc/windows_31j.$(OBJEXT): internal/intern/sprintf.h
|
||||
enc/windows_31j.$(OBJEXT): internal/intern/string.h
|
||||
|
|
|
@ -3943,7 +3943,7 @@ static const OnigCodePoint CR_XDigit[] = {
|
|||
|
||||
/* 'Word': [[:Word:]] */
|
||||
static const OnigCodePoint CR_Word[] = {
|
||||
795,
|
||||
796,
|
||||
0x0030, 0x0039,
|
||||
0x0041, 0x005a,
|
||||
0x005f, 0x005f,
|
||||
|
@ -4241,6 +4241,7 @@ static const OnigCodePoint CR_Word[] = {
|
|||
0x1fe0, 0x1fec,
|
||||
0x1ff2, 0x1ff4,
|
||||
0x1ff6, 0x1ffc,
|
||||
0x200c, 0x200d,
|
||||
0x203f, 0x2040,
|
||||
0x2054, 0x2054,
|
||||
0x2071, 0x2071,
|
||||
|
|
127
encoding.c
127
encoding.c
|
@ -24,6 +24,7 @@
|
|||
#include "internal/string.h"
|
||||
#include "internal/vm.h"
|
||||
#include "regenc.h"
|
||||
#include "ruby/atomic.h"
|
||||
#include "ruby/encoding.h"
|
||||
#include "ruby/util.h"
|
||||
#include "ruby_assert.h"
|
||||
|
@ -60,6 +61,7 @@ VALUE rb_cEncoding;
|
|||
static VALUE rb_encoding_list;
|
||||
|
||||
struct rb_encoding_entry {
|
||||
rb_atomic_t loaded;
|
||||
const char *name;
|
||||
rb_encoding *enc;
|
||||
rb_encoding *base;
|
||||
|
@ -93,15 +95,11 @@ static rb_encoding *global_enc_ascii,
|
|||
*global_enc_utf_8,
|
||||
*global_enc_us_ascii;
|
||||
|
||||
#define GLOBAL_ENC_TABLE_ENTER(enc_table) struct enc_table *enc_table = &global_enc_table; RB_VM_LOCK_ENTER()
|
||||
#define GLOBAL_ENC_TABLE_LEAVE() RB_VM_LOCK_LEAVE()
|
||||
#define GLOBAL_ENC_TABLE_EVAL(enc_table, expr) do { \
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table); \
|
||||
{ \
|
||||
expr; \
|
||||
} \
|
||||
GLOBAL_ENC_TABLE_LEAVE(); \
|
||||
} while (0)
|
||||
#define GLOBAL_ENC_TABLE_LOCKING(tbl) \
|
||||
for (struct enc_table *tbl = &global_enc_table, **locking = &tbl; \
|
||||
locking; \
|
||||
locking = NULL) \
|
||||
RB_VM_LOCKING()
|
||||
|
||||
|
||||
#define ENC_DUMMY_FLAG (1<<24)
|
||||
|
@ -348,6 +346,8 @@ enc_table_expand(struct enc_table *enc_table, int newsize)
|
|||
static int
|
||||
enc_register_at(struct enc_table *enc_table, int index, const char *name, rb_encoding *base_encoding)
|
||||
{
|
||||
ASSERT_vm_locking();
|
||||
|
||||
struct rb_encoding_entry *ent = &enc_table->list[index];
|
||||
rb_raw_encoding *encoding;
|
||||
|
||||
|
@ -362,6 +362,7 @@ enc_register_at(struct enc_table *enc_table, int index, const char *name, rb_enc
|
|||
if (!encoding) {
|
||||
encoding = xmalloc(sizeof(rb_encoding));
|
||||
}
|
||||
|
||||
if (base_encoding) {
|
||||
*encoding = *base_encoding;
|
||||
}
|
||||
|
@ -374,12 +375,18 @@ enc_register_at(struct enc_table *enc_table, int index, const char *name, rb_enc
|
|||
st_insert(enc_table->names, (st_data_t)name, (st_data_t)index);
|
||||
|
||||
enc_list_update(index, encoding);
|
||||
|
||||
// max_enc_len is used to mark a fully loaded encoding.
|
||||
RUBY_ATOMIC_SET(ent->loaded, encoding->max_enc_len);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int
|
||||
enc_register(struct enc_table *enc_table, const char *name, rb_encoding *encoding)
|
||||
{
|
||||
ASSERT_vm_locking();
|
||||
|
||||
int index = enc_table->count;
|
||||
|
||||
enc_table->count = enc_table_expand(enc_table, index + 1);
|
||||
|
@ -409,8 +416,7 @@ rb_enc_register(const char *name, rb_encoding *encoding)
|
|||
{
|
||||
int index;
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
index = enc_registered(enc_table, name);
|
||||
|
||||
if (index >= 0) {
|
||||
|
@ -430,13 +436,13 @@ rb_enc_register(const char *name, rb_encoding *encoding)
|
|||
set_encoding_const(name, rb_enc_from_index(index));
|
||||
}
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
return index;
|
||||
}
|
||||
|
||||
int
|
||||
enc_registered(struct enc_table *enc_table, const char *name)
|
||||
{
|
||||
ASSERT_vm_locking();
|
||||
st_data_t idx = 0;
|
||||
|
||||
if (!name) return -1;
|
||||
|
@ -450,15 +456,13 @@ enc_registered(struct enc_table *enc_table, const char *name)
|
|||
void
|
||||
rb_encdb_declare(const char *name)
|
||||
{
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
int idx = enc_registered(enc_table, name);
|
||||
if (idx < 0) {
|
||||
idx = enc_register(enc_table, name, 0);
|
||||
}
|
||||
set_encoding_const(name, rb_enc_from_index(idx));
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -490,13 +494,11 @@ set_base_encoding(struct enc_table *enc_table, int index, rb_encoding *base)
|
|||
void
|
||||
rb_enc_set_base(const char *name, const char *orig)
|
||||
{
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
int idx = enc_registered(enc_table, name);
|
||||
int origidx = enc_registered(enc_table, orig);
|
||||
set_base_encoding(enc_table, idx, rb_enc_from_index(origidx));
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
}
|
||||
|
||||
/* for encdb.h
|
||||
|
@ -547,8 +549,7 @@ rb_encdb_replicate(const char *name, const char *orig)
|
|||
{
|
||||
int r;
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
int origidx = enc_registered(enc_table, orig);
|
||||
int idx = enc_registered(enc_table, name);
|
||||
|
||||
|
@ -557,7 +558,6 @@ rb_encdb_replicate(const char *name, const char *orig)
|
|||
}
|
||||
r = enc_replicate_with_index(enc_table, name, rb_enc_from_index(origidx), idx);
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -567,13 +567,11 @@ rb_define_dummy_encoding(const char *name)
|
|||
{
|
||||
int index;
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
index = enc_replicate(enc_table, name, rb_ascii8bit_encoding());
|
||||
rb_encoding *enc = enc_table->list[index].enc;
|
||||
ENC_SET_DUMMY((rb_raw_encoding *)enc);
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
@ -583,15 +581,13 @@ rb_encdb_dummy(const char *name)
|
|||
{
|
||||
int index;
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
index = enc_replicate_with_index(enc_table, name,
|
||||
rb_ascii8bit_encoding(),
|
||||
enc_registered(enc_table, name));
|
||||
rb_encoding *enc = enc_table->list[index].enc;
|
||||
ENC_SET_DUMMY((rb_raw_encoding *)enc);
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
|
||||
return index;
|
||||
}
|
||||
|
@ -653,6 +649,7 @@ enc_dup_name(st_data_t name)
|
|||
static int
|
||||
enc_alias_internal(struct enc_table *enc_table, const char *alias, int idx)
|
||||
{
|
||||
ASSERT_vm_locking();
|
||||
return st_insert2(enc_table->names, (st_data_t)alias, (st_data_t)idx,
|
||||
enc_dup_name);
|
||||
}
|
||||
|
@ -671,8 +668,7 @@ rb_enc_alias(const char *alias, const char *orig)
|
|||
{
|
||||
int idx, r;
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
enc_check_addable(enc_table, alias);
|
||||
if ((idx = rb_enc_find_index(orig)) < 0) {
|
||||
r = -1;
|
||||
|
@ -681,7 +677,6 @@ rb_enc_alias(const char *alias, const char *orig)
|
|||
r = enc_alias(enc_table, alias, idx);
|
||||
}
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -691,8 +686,7 @@ rb_encdb_alias(const char *alias, const char *orig)
|
|||
{
|
||||
int r;
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
int idx = enc_registered(enc_table, orig);
|
||||
|
||||
if (idx < 0) {
|
||||
|
@ -700,7 +694,6 @@ rb_encdb_alias(const char *alias, const char *orig)
|
|||
}
|
||||
r = enc_alias(enc_table, alias, idx);
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
@ -708,6 +701,7 @@ rb_encdb_alias(const char *alias, const char *orig)
|
|||
static void
|
||||
rb_enc_init(struct enc_table *enc_table)
|
||||
{
|
||||
ASSERT_vm_locking();
|
||||
enc_table_expand(enc_table, ENCODING_COUNT + 1);
|
||||
if (!enc_table->names) {
|
||||
enc_table->names = st_init_strcasetable_with_size(ENCODING_LIST_CAPA);
|
||||
|
@ -767,8 +761,7 @@ load_encoding(const char *name)
|
|||
ruby_debug = debug;
|
||||
rb_set_errinfo(errinfo);
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
if (loaded < 0 || 1 < loaded) {
|
||||
idx = -1;
|
||||
}
|
||||
|
@ -779,51 +772,74 @@ load_encoding(const char *name)
|
|||
idx = -1;
|
||||
}
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
||||
static int
|
||||
enc_autoload_body(struct enc_table *enc_table, rb_encoding *enc)
|
||||
enc_autoload_body(rb_encoding *enc)
|
||||
{
|
||||
rb_encoding *base = enc_table->list[ENC_TO_ENCINDEX(enc)].base;
|
||||
rb_encoding *base;
|
||||
int i = 0;
|
||||
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
base = enc_table->list[ENC_TO_ENCINDEX(enc)].base;
|
||||
if (base) {
|
||||
do {
|
||||
if (i >= enc_table->count) {
|
||||
i = -1;
|
||||
break;
|
||||
}
|
||||
} while (enc_table->list[i].enc != base && (++i, 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (i == -1) return -1;
|
||||
|
||||
if (base) {
|
||||
int i = 0;
|
||||
do {
|
||||
if (i >= enc_table->count) return -1;
|
||||
} while (enc_table->list[i].enc != base && (++i, 1));
|
||||
if (rb_enc_autoload_p(base)) {
|
||||
if (rb_enc_autoload(base) < 0) return -1;
|
||||
}
|
||||
i = enc->ruby_encoding_index;
|
||||
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
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;
|
||||
return i;
|
||||
}
|
||||
else {
|
||||
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
rb_enc_autoload(rb_encoding *enc)
|
||||
{
|
||||
int i;
|
||||
GLOBAL_ENC_TABLE_EVAL(enc_table, i = enc_autoload_body(enc_table, enc));
|
||||
int i = enc_autoload_body(enc);
|
||||
if (i == -2) {
|
||||
i = load_encoding(rb_enc_name(enc));
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
bool
|
||||
rb_enc_autoload_p(rb_encoding *enc)
|
||||
{
|
||||
int idx = ENC_TO_ENCINDEX(enc);
|
||||
RUBY_ASSERT(rb_enc_from_index(idx) == enc);
|
||||
return !RUBY_ATOMIC_LOAD(global_enc_table.list[idx].loaded);
|
||||
}
|
||||
|
||||
/* Return encoding index or UNSPECIFIED_ENCODING from encoding name */
|
||||
int
|
||||
rb_enc_find_index(const char *name)
|
||||
{
|
||||
int i = enc_registered(&global_enc_table, name);
|
||||
int i;
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
i = enc_registered(enc_table, name);
|
||||
}
|
||||
rb_encoding *enc;
|
||||
|
||||
if (i < 0) {
|
||||
|
@ -1504,16 +1520,16 @@ rb_locale_encindex(void)
|
|||
|
||||
if (idx < 0) idx = ENCINDEX_UTF_8;
|
||||
|
||||
if (enc_registered(&global_enc_table, "locale") < 0) {
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
if (enc_registered(enc_table, "locale") < 0) {
|
||||
# if defined _WIN32
|
||||
void Init_w32_codepage(void);
|
||||
Init_w32_codepage();
|
||||
# endif
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
enc_alias_internal(enc_table, "locale", idx);
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
|
@ -1528,7 +1544,10 @@ rb_locale_encoding(void)
|
|||
int
|
||||
rb_filesystem_encindex(void)
|
||||
{
|
||||
int idx = enc_registered(&global_enc_table, "filesystem");
|
||||
int idx;
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
idx = enc_registered(enc_table, "filesystem");
|
||||
}
|
||||
if (idx < 0) idx = ENCINDEX_ASCII_8BIT;
|
||||
return idx;
|
||||
}
|
||||
|
@ -1555,8 +1574,7 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
|
|||
/* Already set */
|
||||
overridden = TRUE;
|
||||
|
||||
GLOBAL_ENC_TABLE_ENTER(enc_table);
|
||||
{
|
||||
GLOBAL_ENC_TABLE_LOCKING(enc_table) {
|
||||
if (NIL_P(encoding)) {
|
||||
def->index = -1;
|
||||
def->enc = 0;
|
||||
|
@ -1580,7 +1598,6 @@ enc_set_default_encoding(struct default_encoding *def, VALUE encoding, const cha
|
|||
enc_alias_internal(enc_table, "filesystem", Init_enc_set_filesystem_encoding());
|
||||
}
|
||||
}
|
||||
GLOBAL_ENC_TABLE_LEAVE();
|
||||
|
||||
return overridden;
|
||||
}
|
||||
|
|
5
enum.c
5
enum.c
|
@ -1215,14 +1215,15 @@ tally_up(st_data_t *group, st_data_t *value, st_data_t arg, int existing)
|
|||
RB_OBJ_WRITTEN(hash, Qundef, tally);
|
||||
}
|
||||
*value = (st_data_t)tally;
|
||||
if (!SPECIAL_CONST_P(*group)) RB_OBJ_WRITTEN(hash, Qundef, *group);
|
||||
return ST_CONTINUE;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
rb_enum_tally_up(VALUE hash, VALUE group)
|
||||
{
|
||||
rb_hash_stlike_update(hash, group, tally_up, (st_data_t)hash);
|
||||
if (!rb_hash_stlike_update(hash, group, tally_up, (st_data_t)hash)) {
|
||||
RB_OBJ_WRITTEN(hash, Qundef, group);
|
||||
}
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
|
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