summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.document1
-rw-r--r--.github/codeql/codeql-config.yml3
-rw-r--r--.github/workflows/baseruby.yml3
-rw-r--r--.github/workflows/bundled_gems.yml66
-rw-r--r--.github/workflows/check_dependencies.yml10
-rw-r--r--.github/workflows/codeql-analysis.yml5
-rw-r--r--.github/workflows/compilers.yml57
-rw-r--r--.github/workflows/macos.yml8
-rw-r--r--.github/workflows/mingw.yml4
-rw-r--r--.github/workflows/mjit.yml4
-rw-r--r--.github/workflows/spec_guards.yml2
-rw-r--r--.github/workflows/ubuntu.yml23
-rw-r--r--.github/workflows/windows.yml62
-rw-r--r--.travis.yml10
-rw-r--r--CONTRIBUTING.md2
-rw-r--r--LEGAL34
-rw-r--r--NEWS.md146
-rw-r--r--README.ja.md7
-rw-r--r--README.md8
-rw-r--r--addr2line.c165
-rw-r--r--appveyor.yml2
-rw-r--r--array.c116
-rw-r--r--ast.c46
-rw-r--r--ast.rb23
-rw-r--r--benchmark/attr_accessor.yml29
-rw-r--r--benchmark/time_new.yml4
-rw-r--r--benchmark/time_parse.yml8
-rw-r--r--benchmark/vm_cvar.yml20
-rw-r--r--benchmark/vm_thread_condvar1.rb8
-rw-r--r--benchmark/vm_thread_condvar2.rb10
-rw-r--r--bignum.c37
-rw-r--r--bootstraptest/test_fiber.rb4
-rw-r--r--bootstraptest/test_insns.rb2
-rw-r--r--bootstraptest/test_ractor.rb30
-rw-r--r--class.c250
-rw-r--r--common.mk309
-rw-r--r--compar.c31
-rw-r--r--compile.c2380
-rw-r--r--complex.c66
-rw-r--r--configure.ac176
-rw-r--r--cont.c166
-rw-r--r--coroutine/Stack.h21
-rw-r--r--coroutine/amd64/Context.h1
-rw-r--r--coroutine/arm32/Context.h1
-rw-r--r--coroutine/arm64/Context.h1
-rw-r--r--coroutine/copy/Context.c162
-rw-r--r--coroutine/copy/Context.h98
-rw-r--r--coroutine/emscripten/Context.h1
-rw-r--r--coroutine/ppc64le/Context.h1
-rw-r--r--coroutine/pthread/Context.c272
-rw-r--r--coroutine/pthread/Context.h63
-rw-r--r--coroutine/riscv64/Context.h1
-rw-r--r--coroutine/ucontext/Context.c1
-rw-r--r--coroutine/ucontext/Context.h1
-rw-r--r--coroutine/win32/Context.h1
-rw-r--r--coroutine/win64/Context.h1
-rw-r--r--coroutine/x86/Context.h1
-rw-r--r--debug.c1
-rw-r--r--debug_counter.h6
-rw-r--r--defs/gmake.mk29
-rw-r--r--defs/id.def28
-rw-r--r--dir.c6
-rw-r--r--dir.rb36
-rw-r--r--dln.c1
-rw-r--r--doc/NEWS-3.0.0.md2
-rw-r--r--doc/bsearch.rdoc120
-rw-r--r--doc/contributing.rdoc2
-rw-r--r--doc/documentation_guide.rdoc281
-rw-r--r--doc/extension.ja.rdoc36
-rw-r--r--doc/extension.rdoc30
-rw-r--r--doc/irb/irb.rd.ja9
-rw-r--r--doc/make_cheatsheet.md6
-rw-r--r--doc/memory_view.md2
-rw-r--r--doc/method_documentation.rdoc211
-rw-r--r--doc/optparse/argument_converters.rdoc24
-rw-r--r--doc/optparse/creates_option.rdoc2
-rw-r--r--doc/optparse/option_params.rdoc34
-rw-r--r--doc/optparse/ruby/basic.rb17
-rw-r--r--doc/optparse/ruby/help.rb18
-rw-r--r--doc/optparse/ruby/help_banner.rb7
-rw-r--r--doc/optparse/ruby/help_format.rb25
-rw-r--r--doc/optparse/ruby/help_program_name.rb7
-rw-r--r--doc/optparse/ruby/match_converter.rb9
-rw-r--r--doc/optparse/ruby/name_abbrev.rb (renamed from doc/optparse/ruby/abbreviation.rb)0
-rw-r--r--doc/optparse/ruby/parse.rb13
-rw-r--r--doc/optparse/ruby/parse_bang.rb13
-rw-r--r--doc/optparse/tutorial.rdoc505
-rw-r--r--doc/ractor.md2
-rw-r--r--doc/regexp.rdoc40
-rw-r--r--doc/syntax/pattern_matching.rdoc42
-rw-r--r--enc/depend18
-rw-r--r--enc/unicode/13.0.0/casefold.h (renamed from enc/unicode/12.1.0/casefold.h)4402
-rw-r--r--enc/unicode/13.0.0/name2ctype.h (renamed from enc/unicode/12.1.0/name2ctype.h)5473
-rw-r--r--encoding.c26
-rw-r--r--enum.c133
-rw-r--r--enumerator.c4
-rw-r--r--error.c174
-rw-r--r--eval.c243
-rw-r--r--eval_error.c4
-rw-r--r--eval_intern.h34
-rw-r--r--ext/-test-/array/concat/depend321
-rw-r--r--ext/-test-/array/concat/extconf.rb2
-rw-r--r--ext/-test-/array/concat/to_ary_conact.c34
-rw-r--r--ext/-test-/auto_ext.rb1
-rw-r--r--ext/-test-/memory_status/memory_status.c19
-rw-r--r--ext/-test-/memory_view/extconf.rb2
-rw-r--r--ext/-test-/memory_view/memory_view.c7
-rw-r--r--ext/-test-/string/enc_str_buf_cat.c14
-rw-r--r--ext/-test-/thread_fd/depend161
-rw-r--r--ext/-test-/thread_fd/extconf.rb2
-rw-r--r--ext/-test-/thread_fd/thread_fd.c30
-rw-r--r--ext/-test-/thread_fd_close/depend161
-rw-r--r--ext/-test-/thread_fd_close/extconf.rb2
-rw-r--r--ext/-test-/thread_fd_close/thread_fd_close.c14
-rw-r--r--ext/-test-/time/leap_second.c1
-rw-r--r--ext/-test-/wait/depend (renamed from ext/-test-/wait_for_single_fd/depend)191
-rw-r--r--ext/-test-/wait/extconf.rb2
-rw-r--r--ext/-test-/wait/wait.c39
-rw-r--r--ext/-test-/wait_for_single_fd/extconf.rb8
-rw-r--r--ext/-test-/wait_for_single_fd/wait_for_single_fd.c94
-rw-r--r--ext/bigdecimal/bigdecimal.c4
-rw-r--r--ext/date/date_core.c6
-rw-r--r--ext/date/extconf.rb6
-rw-r--r--ext/date/lib/date.rb2
-rw-r--r--ext/date/prereq.mk7
-rw-r--r--ext/date/zonetab.h14
-rw-r--r--ext/digest/digest.gemspec12
-rw-r--r--ext/fiddle/depend3
-rw-r--r--ext/fiddle/extconf.rb9
-rw-r--r--ext/fiddle/fiddle.c4
-rw-r--r--ext/fiddle/fiddle.gemspec6
-rw-r--r--ext/fiddle/fiddle.h11
-rw-r--r--ext/fiddle/function.c3
-rw-r--r--ext/fiddle/handle.c60
-rw-r--r--ext/fiddle/lib/fiddle/struct.rb71
-rw-r--r--ext/fiddle/lib/fiddle/version.rb2
-rw-r--r--ext/fiddle/memory_view.c89
-rw-r--r--ext/fiddle/pointer.c27
-rw-r--r--ext/json/json.gemspec8
-rw-r--r--ext/monitor/monitor.c4
-rw-r--r--ext/objspace/objspace.c3
-rw-r--r--ext/openssl/extconf.rb64
-rw-r--r--ext/openssl/lib/openssl/buffering.rb19
-rw-r--r--ext/openssl/lib/openssl/pkey.rb354
-rw-r--r--ext/openssl/lib/openssl/x509.rb4
-rw-r--r--ext/openssl/openssl.gemspec5
-rw-r--r--ext/openssl/openssl_missing.c37
-rw-r--r--ext/openssl/openssl_missing.h36
-rw-r--r--ext/openssl/ossl.c37
-rw-r--r--ext/openssl/ossl.h4
-rw-r--r--ext/openssl/ossl_asn1.c18
-rw-r--r--ext/openssl/ossl_bn.c134
-rw-r--r--ext/openssl/ossl_cipher.c8
-rw-r--r--ext/openssl/ossl_config.c2
-rw-r--r--ext/openssl/ossl_kdf.c8
-rw-r--r--ext/openssl/ossl_ocsp.c50
-rw-r--r--ext/openssl/ossl_pkcs12.c24
-rw-r--r--ext/openssl/ossl_pkcs7.c20
-rw-r--r--ext/openssl/ossl_pkey.c650
-rw-r--r--ext/openssl/ossl_pkey.h63
-rw-r--r--ext/openssl/ossl_pkey_dh.c305
-rw-r--r--ext/openssl/ossl_pkey_dsa.c299
-rw-r--r--ext/openssl/ossl_pkey_ec.c113
-rw-r--r--ext/openssl/ossl_pkey_rsa.c362
-rw-r--r--ext/openssl/ossl_ssl.c227
-rw-r--r--ext/openssl/ossl_ssl_session.c53
-rw-r--r--ext/openssl/ossl_ts.c35
-rw-r--r--ext/openssl/ossl_x509.c6
-rw-r--r--ext/openssl/ossl_x509cert.c170
-rw-r--r--ext/openssl/ossl_x509crl.c17
-rw-r--r--ext/openssl/ossl_x509req.c17
-rw-r--r--ext/openssl/ossl_x509store.c13
-rw-r--r--ext/pathname/lib/pathname.rb8
-rw-r--r--ext/psych/lib/psych.rb2
-rw-r--r--ext/psych/lib/psych/scalar_scanner.rb17
-rw-r--r--ext/psych/lib/psych/visitors/yaml_tree.rb2
-rw-r--r--ext/racc/cparse/extconf.rb1
-rw-r--r--ext/readline/readline-ext.gemspec2
-rw-r--r--ext/readline/readline.c3
-rw-r--r--ext/socket/ancdata.c4
-rw-r--r--ext/socket/basicsocket.c75
-rw-r--r--ext/socket/ifaddr.c1
-rw-r--r--ext/socket/init.c120
-rw-r--r--ext/socket/rubysocket.h25
-rw-r--r--ext/socket/socket.c26
-rw-r--r--ext/socket/tcpserver.c22
-rw-r--r--ext/socket/udpsocket.c27
-rw-r--r--ext/socket/unixserver.c23
-rw-r--r--ext/stringio/stringio.c2
-rw-r--r--ext/zlib/extconf.rb7
-rw-r--r--ext/zlib/zlib.c35
-rw-r--r--file.c93
-rw-r--r--gc.c1827
-rw-r--r--gc.h6
-rw-r--r--gem_prelude.rb10
-rw-r--r--gems/bundled_gems16
-rw-r--r--goruby.c6
-rw-r--r--hash.c180
-rw-r--r--id_table.c6
-rw-r--r--include/ruby.h1
-rw-r--r--include/ruby/assert.h2
-rw-r--r--include/ruby/atomic.h258
-rw-r--r--include/ruby/backward.h1
-rw-r--r--include/ruby/backward/2/assume.h25
-rw-r--r--include/ruby/backward/2/attributes.h3
-rw-r--r--include/ruby/backward/2/bool.h5
-rw-r--r--include/ruby/backward/2/gcc_version_since.h5
-rw-r--r--include/ruby/backward/2/inttypes.h3
-rw-r--r--include/ruby/backward/2/limits.h5
-rw-r--r--include/ruby/backward/2/long_long.h12
-rw-r--r--include/ruby/backward/2/r_cast.h5
-rw-r--r--include/ruby/backward/2/rmodule.h3
-rw-r--r--include/ruby/backward/2/stdalign.h6
-rw-r--r--include/ruby/backward/2/stdarg.h24
-rw-r--r--include/ruby/backward/cxxanyargs.hpp69
-rw-r--r--include/ruby/debug.h555
-rw-r--r--include/ruby/defines.h11
-rw-r--r--include/ruby/encoding.h2124
-rw-r--r--include/ruby/fiber/scheduler.h185
-rw-r--r--include/ruby/internal/anyargs.h8
-rw-r--r--include/ruby/internal/arithmetic.h2
-rw-r--r--include/ruby/internal/arithmetic/char.h31
-rw-r--r--include/ruby/internal/arithmetic/double.h49
-rw-r--r--include/ruby/internal/arithmetic/fixnum.h32
-rw-r--r--include/ruby/internal/arithmetic/gid_t.h5
-rw-r--r--include/ruby/internal/arithmetic/int.h129
-rw-r--r--include/ruby/internal/arithmetic/intptr_t.h38
-rw-r--r--include/ruby/internal/arithmetic/long.h158
-rw-r--r--include/ruby/internal/arithmetic/long_long.h85
-rw-r--r--include/ruby/internal/arithmetic/mode_t.h5
-rw-r--r--include/ruby/internal/arithmetic/off_t.h5
-rw-r--r--include/ruby/internal/arithmetic/pid_t.h5
-rw-r--r--include/ruby/internal/arithmetic/short.h85
-rw-r--r--include/ruby/internal/arithmetic/size_t.h24
-rw-r--r--include/ruby/internal/arithmetic/st_data_t.h24
-rw-r--r--include/ruby/internal/arithmetic/uid_t.h5
-rw-r--r--include/ruby/internal/assume.h2
-rw-r--r--include/ruby/internal/attr/alloc_size.h2
-rw-r--r--include/ruby/internal/attr/artificial.h2
-rw-r--r--include/ruby/internal/attr/cold.h2
-rw-r--r--include/ruby/internal/attr/const.h2
-rw-r--r--include/ruby/internal/attr/constexpr.h2
-rw-r--r--include/ruby/internal/attr/deprecated.h18
-rw-r--r--include/ruby/internal/attr/diagnose_if.h2
-rw-r--r--include/ruby/internal/attr/enum_extensibility.h2
-rw-r--r--include/ruby/internal/attr/error.h2
-rw-r--r--include/ruby/internal/attr/flag_enum.h2
-rw-r--r--include/ruby/internal/attr/forceinline.h2
-rw-r--r--include/ruby/internal/attr/format.h2
-rw-r--r--include/ruby/internal/attr/maybe_unused.h2
-rw-r--r--include/ruby/internal/attr/noalias.h2
-rw-r--r--include/ruby/internal/attr/nodiscard.h2
-rw-r--r--include/ruby/internal/attr/noexcept.h2
-rw-r--r--include/ruby/internal/attr/noinline.h2
-rw-r--r--include/ruby/internal/attr/nonnull.h2
-rw-r--r--include/ruby/internal/attr/noreturn.h2
-rw-r--r--include/ruby/internal/attr/pure.h2
-rw-r--r--include/ruby/internal/attr/restrict.h2
-rw-r--r--include/ruby/internal/attr/returns_nonnull.h2
-rw-r--r--include/ruby/internal/attr/warning.h2
-rw-r--r--include/ruby/internal/attr/weakref.h2
-rw-r--r--include/ruby/internal/cast.h5
-rw-r--r--include/ruby/internal/compiler_is.h2
-rw-r--r--include/ruby/internal/compiler_is/apple.h5
-rw-r--r--include/ruby/internal/compiler_is/clang.h5
-rw-r--r--include/ruby/internal/compiler_is/gcc.h5
-rw-r--r--include/ruby/internal/compiler_is/intel.h5
-rw-r--r--include/ruby/internal/compiler_is/msvc.h5
-rw-r--r--include/ruby/internal/compiler_is/sunpro.h5
-rw-r--r--include/ruby/internal/compiler_since.h2
-rw-r--r--include/ruby/internal/config.h9
-rw-r--r--include/ruby/internal/constant_p.h3
-rw-r--r--include/ruby/internal/core.h2
-rw-r--r--include/ruby/internal/core/rarray.h342
-rw-r--r--include/ruby/internal/core/rbasic.h88
-rw-r--r--include/ruby/internal/core/rbignum.h33
-rw-r--r--include/ruby/internal/core/rclass.h99
-rw-r--r--include/ruby/internal/core/rdata.h231
-rw-r--r--include/ruby/internal/core/rfile.h17
-rw-r--r--include/ruby/internal/core/rhash.h112
-rw-r--r--include/ruby/internal/core/rmatch.h85
-rw-r--r--include/ruby/internal/core/robject.h99
-rw-r--r--include/ruby/internal/core/rregexp.h88
-rw-r--r--include/ruby/internal/core/rstring.h381
-rw-r--r--include/ruby/internal/core/rstruct.h58
-rw-r--r--include/ruby/internal/core/rtypeddata.h428
-rw-r--r--include/ruby/internal/ctype.h382
-rw-r--r--include/ruby/internal/dllexport.h28
-rw-r--r--include/ruby/internal/dosish.h28
-rw-r--r--include/ruby/internal/error.h568
-rw-r--r--include/ruby/internal/eval.h355
-rw-r--r--include/ruby/internal/event.h157
-rw-r--r--include/ruby/internal/fl_type.h659
-rw-r--r--include/ruby/internal/gc.h2
-rw-r--r--include/ruby/internal/glob.h88
-rw-r--r--include/ruby/internal/globals.h225
-rw-r--r--include/ruby/internal/has/attribute.h2
-rw-r--r--include/ruby/internal/has/builtin.h2
-rw-r--r--include/ruby/internal/has/c_attribute.h2
-rw-r--r--include/ruby/internal/has/cpp_attribute.h2
-rw-r--r--include/ruby/internal/has/declspec_attribute.h2
-rw-r--r--include/ruby/internal/has/extension.h2
-rw-r--r--include/ruby/internal/has/feature.h2
-rw-r--r--include/ruby/internal/has/warning.h2
-rw-r--r--include/ruby/internal/intern/array.h659
-rw-r--r--include/ruby/internal/intern/bignum.h815
-rw-r--r--include/ruby/internal/intern/class.h339
-rw-r--r--include/ruby/internal/intern/compar.h34
-rw-r--r--include/ruby/internal/intern/complex.h203
-rw-r--r--include/ruby/internal/intern/cont.h205
-rw-r--r--include/ruby/internal/intern/dir.h11
-rw-r--r--include/ruby/internal/intern/enum.h44
-rw-r--r--include/ruby/internal/intern/enumerator.h201
-rw-r--r--include/ruby/internal/intern/error.h255
-rw-r--r--include/ruby/internal/intern/eval.h183
-rw-r--r--include/ruby/internal/intern/file.h170
-rw-r--r--include/ruby/internal/intern/gc.h373
-rw-r--r--include/ruby/internal/intern/hash.h300
-rw-r--r--include/ruby/internal/intern/io.h635
-rw-r--r--include/ruby/internal/intern/load.h194
-rw-r--r--include/ruby/internal/intern/marshal.h83
-rw-r--r--include/ruby/internal/intern/numeric.h188
-rw-r--r--include/ruby/internal/intern/object.h565
-rw-r--r--include/ruby/internal/intern/parse.h155
-rw-r--r--include/ruby/internal/intern/proc.h336
-rw-r--r--include/ruby/internal/intern/process.h239
-rw-r--r--include/ruby/internal/intern/random.h74
-rw-r--r--include/ruby/internal/intern/range.h60
-rw-r--r--include/ruby/internal/intern/rational.h138
-rw-r--r--include/ruby/internal/intern/re.h227
-rw-r--r--include/ruby/internal/intern/ruby.h46
-rw-r--r--include/ruby/internal/intern/select.h38
-rw-r--r--include/ruby/internal/intern/select/largesize.h138
-rw-r--r--include/ruby/internal/intern/select/posix.h67
-rw-r--r--include/ruby/internal/intern/select/win32.h153
-rw-r--r--include/ruby/internal/intern/signal.h121
-rw-r--r--include/ruby/internal/intern/sprintf.h132
-rw-r--r--include/ruby/internal/intern/string.h1697
-rw-r--r--include/ruby/internal/intern/struct.h184
-rw-r--r--include/ruby/internal/intern/thread.h452
-rw-r--r--include/ruby/internal/intern/time.h122
-rw-r--r--include/ruby/internal/intern/variable.h629
-rw-r--r--include/ruby/internal/intern/vm.h403
-rw-r--r--include/ruby/internal/interpreter.h235
-rw-r--r--include/ruby/internal/iterator.h480
-rw-r--r--include/ruby/internal/memory.h431
-rw-r--r--include/ruby/internal/method.h180
-rw-r--r--include/ruby/internal/module.h154
-rw-r--r--include/ruby/internal/newobj.h152
-rw-r--r--include/ruby/internal/rgengc.h286
-rw-r--r--include/ruby/internal/scan_args.h157
-rw-r--r--include/ruby/internal/special_consts.h141
-rw-r--r--include/ruby/internal/static_assert.h2
-rw-r--r--include/ruby/internal/stdalign.h8
-rw-r--r--include/ruby/internal/stdbool.h2
-rw-r--r--include/ruby/internal/symbol.h256
-rw-r--r--include/ruby/internal/value.h71
-rw-r--r--include/ruby/internal/value_type.h199
-rw-r--r--include/ruby/internal/variable.h301
-rw-r--r--include/ruby/internal/warning_push.h41
-rw-r--r--include/ruby/internal/xmalloc.h110
-rw-r--r--include/ruby/io.h845
-rw-r--r--include/ruby/memory_view.h196
-rw-r--r--include/ruby/missing.h43
-rw-r--r--include/ruby/ractor.h209
-rw-r--r--include/ruby/random.h226
-rw-r--r--include/ruby/re.h129
-rw-r--r--include/ruby/regex.h1
-rw-r--r--include/ruby/ruby.h177
-rw-r--r--include/ruby/subst.h1
-rw-r--r--include/ruby/thread.h157
-rw-r--r--include/ruby/thread_native.h141
-rw-r--r--include/ruby/util.h193
-rw-r--r--include/ruby/version.h106
-rw-r--r--include/ruby/vm.h19
-rw-r--r--include/ruby/win32.h10
-rw-r--r--insns.def10
-rw-r--r--internal.h8
-rw-r--r--internal/array.h7
-rw-r--r--internal/bignum.h1
-rw-r--r--internal/bits.h1
-rw-r--r--internal/class.h10
-rw-r--r--internal/compar.h1
-rw-r--r--internal/compile.h1
-rw-r--r--internal/compilers.h1
-rw-r--r--internal/complex.h1
-rw-r--r--internal/cont.h2
-rw-r--r--internal/dir.h1
-rw-r--r--internal/enc.h1
-rw-r--r--internal/encoding.h1
-rw-r--r--internal/enum.h1
-rw-r--r--internal/enumerator.h1
-rw-r--r--internal/error.h71
-rw-r--r--internal/eval.h1
-rw-r--r--internal/file.h1
-rw-r--r--internal/fixnum.h1
-rw-r--r--internal/gc.h11
-rw-r--r--internal/hash.h1
-rw-r--r--internal/imemo.h1
-rw-r--r--internal/inits.h1
-rw-r--r--internal/io.h1
-rw-r--r--internal/load.h1
-rw-r--r--internal/loadpath.h1
-rw-r--r--internal/math.h1
-rw-r--r--internal/missing.h1
-rw-r--r--internal/numeric.h3
-rw-r--r--internal/object.h2
-rw-r--r--internal/parse.h3
-rw-r--r--internal/proc.h1
-rw-r--r--internal/process.h1
-rw-r--r--internal/random.h1
-rw-r--r--internal/range.h1
-rw-r--r--internal/rational.h2
-rw-r--r--internal/re.h1
-rw-r--r--internal/sanitizers.h1
-rw-r--r--internal/serial.h1
-rw-r--r--internal/signal.h1
-rw-r--r--internal/static_assert.h1
-rw-r--r--internal/string.h2
-rw-r--r--internal/struct.h1
-rw-r--r--internal/symbol.h1
-rw-r--r--internal/thread.h1
-rw-r--r--internal/time.h1
-rw-r--r--internal/transcode.h1
-rw-r--r--internal/util.h4
-rw-r--r--internal/variable.h2
-rw-r--r--internal/vm.h1
-rw-r--r--internal/warnings.h1
-rw-r--r--io.c352
-rw-r--r--iseq.c54
-rw-r--r--iseq.h3
-rw-r--r--lib/bundler.rb48
-rw-r--r--lib/bundler/cli.rb61
-rw-r--r--lib/bundler/cli/cache.rb2
-rw-r--r--lib/bundler/cli/check.rb6
-rw-r--r--lib/bundler/cli/doctor.rb14
-rw-r--r--lib/bundler/cli/exec.rb7
-rw-r--r--lib/bundler/cli/gem.rb5
-rw-r--r--lib/bundler/cli/install.rb26
-rw-r--r--lib/bundler/cli/list.rb8
-rw-r--r--lib/bundler/cli/lock.rb6
-rw-r--r--lib/bundler/cli/open.rb3
-rw-r--r--lib/bundler/cli/outdated.rb19
-rw-r--r--lib/bundler/cli/update.rb13
-rw-r--r--lib/bundler/compact_index_client.rb4
-rw-r--r--lib/bundler/current_ruby.rb8
-rw-r--r--lib/bundler/definition.rb244
-rw-r--r--lib/bundler/dsl.rb44
-rw-r--r--lib/bundler/endpoint_specification.rb8
-rw-r--r--lib/bundler/errors.rb2
-rw-r--r--lib/bundler/feature_flag.rb2
-rw-r--r--lib/bundler/fetcher/compact_index.rb2
-rw-r--r--lib/bundler/fetcher/downloader.rb3
-rw-r--r--lib/bundler/fetcher/index.rb1
-rw-r--r--lib/bundler/friendly_errors.rb6
-rw-r--r--lib/bundler/gemdeps.rb29
-rw-r--r--lib/bundler/index.rb9
-rw-r--r--lib/bundler/installer.rb21
-rw-r--r--lib/bundler/installer/gem_installer.rb19
-rw-r--r--lib/bundler/installer/standalone.rb23
-rw-r--r--lib/bundler/lockfile_parser.rb23
-rw-r--r--lib/bundler/man/bundle-add.12
-rw-r--r--lib/bundler/man/bundle-binstubs.12
-rw-r--r--lib/bundler/man/bundle-cache.12
-rw-r--r--lib/bundler/man/bundle-check.12
-rw-r--r--lib/bundler/man/bundle-clean.12
-rw-r--r--lib/bundler/man/bundle-config.113
-rw-r--r--lib/bundler/man/bundle-config.1.ronn15
-rw-r--r--lib/bundler/man/bundle-doctor.12
-rw-r--r--lib/bundler/man/bundle-exec.12
-rw-r--r--lib/bundler/man/bundle-gem.12
-rw-r--r--lib/bundler/man/bundle-info.12
-rw-r--r--lib/bundler/man/bundle-init.12
-rw-r--r--lib/bundler/man/bundle-inject.12
-rw-r--r--lib/bundler/man/bundle-install.14
-rw-r--r--lib/bundler/man/bundle-install.1.ronn4
-rw-r--r--lib/bundler/man/bundle-list.12
-rw-r--r--lib/bundler/man/bundle-lock.12
-rw-r--r--lib/bundler/man/bundle-open.12
-rw-r--r--lib/bundler/man/bundle-outdated.12
-rw-r--r--lib/bundler/man/bundle-platform.12
-rw-r--r--lib/bundler/man/bundle-pristine.12
-rw-r--r--lib/bundler/man/bundle-remove.12
-rw-r--r--lib/bundler/man/bundle-show.12
-rw-r--r--lib/bundler/man/bundle-update.110
-rw-r--r--lib/bundler/man/bundle-update.1.ronn9
-rw-r--r--lib/bundler/man/bundle-viz.12
-rw-r--r--lib/bundler/man/bundle.12
-rw-r--r--lib/bundler/man/gemfile.52
-rw-r--r--lib/bundler/plugin.rb31
-rw-r--r--lib/bundler/plugin/api/source.rb14
-rw-r--r--lib/bundler/plugin/index.rb5
-rw-r--r--lib/bundler/plugin/installer.rb4
-rw-r--r--lib/bundler/psyched_yaml.rb14
-rw-r--r--lib/bundler/resolver.rb103
-rw-r--r--lib/bundler/rubygems_ext.rb34
-rw-r--r--lib/bundler/rubygems_gem_installer.rb6
-rw-r--r--lib/bundler/rubygems_integration.rb19
-rw-r--r--lib/bundler/runtime.rb25
-rw-r--r--lib/bundler/settings.rb46
-rw-r--r--lib/bundler/setup.rb4
-rw-r--r--lib/bundler/shared_helpers.rb7
-rw-r--r--lib/bundler/source.rb15
-rw-r--r--lib/bundler/source/git/git_proxy.rb3
-rw-r--r--lib/bundler/source/rubygems.rb69
-rw-r--r--lib/bundler/source/rubygems_aggregate.rb68
-rw-r--r--lib/bundler/source_list.rb109
-rw-r--r--lib/bundler/source_map.rb58
-rw-r--r--lib/bundler/spec_set.rb59
-rw-r--r--lib/bundler/templates/Executable.bundler12
-rw-r--r--lib/bundler/templates/newgem/github/workflows/main.yml.tt15
-rw-r--r--lib/bundler/templates/newgem/newgem.gemspec.tt6
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool.rb113
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/monotonic_time.rb66
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/timed_stack.rb40
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/version.rb2
-rw-r--r--lib/bundler/vendor/connection_pool/lib/connection_pool/wrapper.rb57
-rw-r--r--lib/bundler/vendor/uri/lib/uri.rb1
-rw-r--r--lib/bundler/vendor/uri/lib/uri/common.rb97
-rw-r--r--lib/bundler/vendor/uri/lib/uri/ftp.rb1
-rw-r--r--lib/bundler/vendor/uri/lib/uri/generic.rb11
-rw-r--r--lib/bundler/vendor/uri/lib/uri/http.rb1
-rw-r--r--lib/bundler/vendor/uri/lib/uri/https.rb1
-rw-r--r--lib/bundler/vendor/uri/lib/uri/ldap.rb2
-rw-r--r--lib/bundler/vendor/uri/lib/uri/mailto.rb1
-rw-r--r--lib/bundler/vendor/uri/lib/uri/rfc2396_parser.rb15
-rw-r--r--lib/bundler/vendor/uri/lib/uri/rfc3986_parser.rb13
-rw-r--r--lib/bundler/vendor/uri/lib/uri/version.rb2
-rw-r--r--lib/bundler/vendor/uri/lib/uri/ws.rb84
-rw-r--r--lib/bundler/vendor/uri/lib/uri/wss.rb22
-rw-r--r--lib/bundler/worker.rb23
-rw-r--r--lib/cgi/util.rb11
-rw-r--r--lib/did_you_mean/core_ext/name_error.rb11
-rw-r--r--lib/did_you_mean/spell_checkers/require_path_checker.rb1
-rw-r--r--lib/did_you_mean/version.rb2
-rw-r--r--lib/error_highlight.rb2
-rw-r--r--lib/error_highlight/base.rb461
-rw-r--r--lib/error_highlight/core_ext.rb50
-rw-r--r--lib/error_highlight/error_highlight.gemspec27
-rw-r--r--lib/error_highlight/formatter.rb25
-rw-r--r--lib/error_highlight/version.rb3
-rw-r--r--lib/find.rb4
-rw-r--r--lib/forwardable.rb2
-rw-r--r--lib/getoptlong.rb10
-rw-r--r--lib/getoptlong/getoptlong.gemspec2
-rw-r--r--lib/irb.rb7
-rw-r--r--lib/irb/cmd/help.rb3
-rw-r--r--lib/irb/cmd/info.rb6
-rw-r--r--lib/irb/cmd/ls.rb24
-rw-r--r--lib/irb/cmd/measure.rb3
-rw-r--r--lib/irb/cmd/show_source.rb16
-rw-r--r--lib/irb/completion.rb56
-rw-r--r--lib/irb/context.rb5
-rw-r--r--lib/irb/init.rb21
-rw-r--r--lib/irb/input-method.rb74
-rw-r--r--lib/irb/irb.gemspec2
-rw-r--r--lib/irb/lc/help-message2
-rw-r--r--lib/irb/lc/ja/help-message2
-rw-r--r--lib/irb/ruby-lex.rb67
-rw-r--r--lib/irb/version.rb4
-rw-r--r--lib/irb/workspace.rb3
-rw-r--r--lib/logger/logger.gemspec2
-rw-r--r--lib/mkmf.rb32
-rw-r--r--lib/mutex_m.rb12
-rw-r--r--lib/net/http/generic_request.rb4
-rw-r--r--lib/optparse.rb24
-rw-r--r--lib/ostruct.rb2
-rw-r--r--lib/racc/parser-text.rb2
-rw-r--r--lib/racc/parserfilegenerator.rb44
-rw-r--r--lib/racc/pre-setup13
-rw-r--r--lib/racc/racc.gemspec75
-rw-r--r--lib/racc/rdoc/grammar.en.rdoc219
-rw-r--r--lib/racc/statetransitiontable.rb10
-rw-r--r--lib/rdoc/Rakefile107
-rw-r--r--lib/rdoc/generator/darkfish.rb4
-rw-r--r--lib/rdoc/generator/template/darkfish/_head.rhtml4
-rw-r--r--lib/rdoc/markdown.rb79
-rw-r--r--lib/rdoc/markdown/literals.rb15
-rw-r--r--lib/rdoc/markup/to_html.rb4
-rw-r--r--lib/rdoc/options.rb31
-rw-r--r--lib/rdoc/parser/ruby.rb18
-rw-r--r--lib/rdoc/rd/block_parser.rb2
-rw-r--r--lib/rdoc/rd/inline_parser.rb2
-rw-r--r--lib/rdoc/rdoc.gemspec1
-rw-r--r--lib/rdoc/rdoc.rb33
-rw-r--r--lib/rdoc/ri/driver.rb15
-rw-r--r--lib/rdoc/rubygems_hook.rb4
-rw-r--r--lib/rdoc/text.rb16
-rw-r--r--lib/rdoc/version.rb2
-rw-r--r--lib/readline.gemspec24
-rw-r--r--lib/reline.rb172
-rw-r--r--lib/reline/ansi.rb100
-rw-r--r--lib/reline/config.rb49
-rw-r--r--lib/reline/general_io.rb12
-rw-r--r--lib/reline/key_stroke.rb77
-rw-r--r--lib/reline/line_editor.rb490
-rw-r--r--lib/reline/terminfo.rb126
-rw-r--r--lib/reline/unicode.rb35
-rw-r--r--lib/reline/version.rb2
-rw-r--r--lib/reline/windows.rb212
-rw-r--r--lib/resolv-replace.gemspec2
-rw-r--r--lib/resolv.gemspec2
-rw-r--r--lib/ruby2_keywords.gemspec19
-rw-r--r--lib/rubygems.rb84
-rw-r--r--lib/rubygems/command.rb2
-rw-r--r--lib/rubygems/command_manager.rb6
-rw-r--r--lib/rubygems/commands/build_command.rb8
-rw-r--r--lib/rubygems/commands/cert_command.rb84
-rw-r--r--lib/rubygems/commands/check_command.rb8
-rw-r--r--lib/rubygems/commands/cleanup_command.rb6
-rw-r--r--lib/rubygems/commands/contents_command.rb4
-rw-r--r--lib/rubygems/commands/dependency_command.rb6
-rw-r--r--lib/rubygems/commands/environment_command.rb2
-rw-r--r--lib/rubygems/commands/fetch_command.rb6
-rw-r--r--lib/rubygems/commands/generate_index_command.rb4
-rw-r--r--lib/rubygems/commands/help_command.rb2
-rw-r--r--lib/rubygems/commands/info_command.rb4
-rw-r--r--lib/rubygems/commands/install_command.rb23
-rw-r--r--lib/rubygems/commands/list_command.rb4
-rw-r--r--lib/rubygems/commands/lock_command.rb2
-rw-r--r--lib/rubygems/commands/mirror_command.rb2
-rw-r--r--lib/rubygems/commands/open_command.rb4
-rw-r--r--lib/rubygems/commands/outdated_command.rb8
-rw-r--r--lib/rubygems/commands/owner_command.rb8
-rw-r--r--lib/rubygems/commands/pristine_command.rb10
-rw-r--r--lib/rubygems/commands/push_command.rb8
-rw-r--r--lib/rubygems/commands/query_command.rb6
-rw-r--r--lib/rubygems/commands/rdoc_command.rb6
-rw-r--r--lib/rubygems/commands/search_command.rb4
-rw-r--r--lib/rubygems/commands/server_command.rb6
-rw-r--r--lib/rubygems/commands/setup_command.rb26
-rw-r--r--lib/rubygems/commands/signin_command.rb4
-rw-r--r--lib/rubygems/commands/signout_command.rb2
-rw-r--r--lib/rubygems/commands/sources_command.rb8
-rw-r--r--lib/rubygems/commands/specification_command.rb8
-rw-r--r--lib/rubygems/commands/stale_command.rb2
-rw-r--r--lib/rubygems/commands/uninstall_command.rb6
-rw-r--r--lib/rubygems/commands/unpack_command.rb10
-rw-r--r--lib/rubygems/commands/update_command.rb18
-rw-r--r--lib/rubygems/commands/which_command.rb2
-rw-r--r--lib/rubygems/commands/yank_command.rb8
-rw-r--r--lib/rubygems/config_file.rb10
-rw-r--r--lib/rubygems/core_ext/tcpsocket_init.rb4
-rw-r--r--lib/rubygems/defaults.rb22
-rw-r--r--lib/rubygems/dependency_installer.rb16
-rw-r--r--lib/rubygems/dependency_list.rb2
-rw-r--r--lib/rubygems/deprecate.rb59
-rw-r--r--lib/rubygems/doctor.rb4
-rw-r--r--lib/rubygems/exceptions.rb6
-rw-r--r--lib/rubygems/ext/builder.rb1
-rw-r--r--lib/rubygems/ext/ext_conf_builder.rb11
-rw-r--r--lib/rubygems/ext/rake_builder.rb3
-rw-r--r--lib/rubygems/gem_runner.rb6
-rw-r--r--lib/rubygems/gemcutter_utilities.rb20
-rw-r--r--lib/rubygems/indexer.rb4
-rw-r--r--lib/rubygems/install_default_message.rb4
-rw-r--r--lib/rubygems/install_message.rb4
-rw-r--r--lib/rubygems/install_update_options.rb4
-rw-r--r--lib/rubygems/installer.rb31
-rw-r--r--lib/rubygems/local_remote_options.rb2
-rw-r--r--lib/rubygems/mock_gem_ui.rb2
-rw-r--r--lib/rubygems/name_tuple.rb5
-rw-r--r--lib/rubygems/package.rb24
-rw-r--r--lib/rubygems/package/io_source.rb4
-rw-r--r--lib/rubygems/package/tar_reader.rb2
-rw-r--r--lib/rubygems/package_task.rb4
-rw-r--r--lib/rubygems/path_support.rb7
-rw-r--r--lib/rubygems/platform.rb6
-rw-r--r--lib/rubygems/rdoc.rb2
-rw-r--r--lib/rubygems/remote_fetcher.rb37
-rw-r--r--lib/rubygems/request.rb12
-rw-r--r--lib/rubygems/request/connection_pools.rb2
-rw-r--r--lib/rubygems/request/http_pool.rb2
-rw-r--r--lib/rubygems/request_set.rb10
-rw-r--r--lib/rubygems/request_set/lockfile.rb2
-rw-r--r--lib/rubygems/request_set/lockfile/tokenizer.rb2
-rw-r--r--lib/rubygems/requirement.rb25
-rw-r--r--lib/rubygems/resolver.rb62
-rw-r--r--lib/rubygems/resolver/git_specification.rb2
-rw-r--r--lib/rubygems/resolver/installer_set.rb8
-rw-r--r--lib/rubygems/resolver/molinillo.rb2
-rw-r--r--lib/rubygems/resolver/specification.rb2
-rw-r--r--lib/rubygems/s3_uri_signer.rb1
-rw-r--r--lib/rubygems/safe_yaml.rb2
-rw-r--r--lib/rubygems/security.rb10
-rw-r--r--lib/rubygems/security/policy.rb2
-rw-r--r--lib/rubygems/security/signer.rb2
-rw-r--r--lib/rubygems/security_option.rb4
-rw-r--r--lib/rubygems/server.rb4
-rw-r--r--lib/rubygems/source.rb12
-rw-r--r--lib/rubygems/spec_fetcher.rb10
-rw-r--r--lib/rubygems/specification.rb38
-rw-r--r--lib/rubygems/specification_policy.rb11
-rw-r--r--lib/rubygems/syck_hack.rb77
-rw-r--r--lib/rubygems/uninstaller.rb58
-rw-r--r--lib/rubygems/uri.rb102
-rw-r--r--lib/rubygems/uri_parser.rb34
-rw-r--r--lib/rubygems/uri_parsing.rb23
-rw-r--r--lib/rubygems/user_interaction.rb6
-rw-r--r--lib/rubygems/util/licenses.rb111
-rw-r--r--lib/rubygems/validator.rb4
-rw-r--r--lib/rubygems/version_option.rb2
-rw-r--r--lib/securerandom.rb2
-rw-r--r--lib/set.rb32
-rw-r--r--lib/set/set.gemspec2
-rw-r--r--lib/tempfile.rb6
-rw-r--r--lib/un.gemspec3
-rw-r--r--lib/un.rb39
-rw-r--r--lib/unicode_normalize/tables.rb36
-rw-r--r--lib/uri.rb3
-rw-r--r--lib/uri/common.rb30
-rw-r--r--lib/uri/file.rb2
-rw-r--r--lib/uri/ftp.rb3
-rw-r--r--lib/uri/http.rb3
-rw-r--r--lib/uri/https.rb3
-rw-r--r--lib/uri/ldap.rb2
-rw-r--r--lib/uri/ldaps.rb3
-rw-r--r--lib/uri/mailto.rb2
-rw-r--r--lib/uri/ws.rb3
-rw-r--r--lib/uri/wss.rb3
-rw-r--r--load.c90
-rw-r--r--man/irb.18
-rw-r--r--marshal.c7
-rw-r--r--math.c46
-rw-r--r--memory_view.c4
-rwxr-xr-xmisc/lldb_cruby.py10
-rw-r--r--missing/erf.c15
-rw-r--r--missing/finite.c9
-rw-r--r--missing/isinf.c69
-rw-r--r--missing/isnan.c32
-rw-r--r--missing/signbit.c19
-rw-r--r--missing/tgamma.c15
-rw-r--r--mjit.c15
-rw-r--r--mjit.h2
-rw-r--r--mjit_compile.c1
-rw-r--r--node.c4
-rw-r--r--numeric.c502
-rw-r--r--numeric.rb20
-rw-r--r--object.c388
-rw-r--r--pack.c8
-rw-r--r--parse.y137
-rw-r--r--proc.c52
-rw-r--r--process.c65
-rw-r--r--ractor.c21
-rw-r--r--ractor.rb6
-rw-r--r--ractor_core.h19
-rw-r--r--random.c10
-rw-r--r--range.c591
-rw-r--r--rational.c37
-rw-r--r--re.c129
-rw-r--r--ruby.c25
-rw-r--r--ruby_assert.h1
-rw-r--r--sample/drb/dchats.rb2
-rw-r--r--sample/exyacc.rb2
-rw-r--r--signal.c12
-rw-r--r--spec/bundler/bundler/bundler_spec.rb51
-rw-r--r--spec/bundler/bundler/cli_spec.rb56
-rw-r--r--spec/bundler/bundler/definition_spec.rb31
-rw-r--r--spec/bundler/bundler/dsl_spec.rb17
-rw-r--r--spec/bundler/bundler/endpoint_specification_spec.rb16
-rw-r--r--spec/bundler/bundler/env_spec.rb18
-rw-r--r--spec/bundler/bundler/fetcher/downloader_spec.rb11
-rw-r--r--spec/bundler/bundler/fetcher/index_spec.rb2
-rw-r--r--spec/bundler/bundler/plugin/index_spec.rb10
-rw-r--r--spec/bundler/bundler/plugin_spec.rb9
-rw-r--r--spec/bundler/bundler/psyched_yaml_spec.rb9
-rw-r--r--spec/bundler/bundler/settings_spec.rb23
-rw-r--r--spec/bundler/bundler/source/rubygems_spec.rb14
-rw-r--r--spec/bundler/bundler/source_list_spec.rb57
-rw-r--r--spec/bundler/bundler/worker_spec.rb47
-rw-r--r--spec/bundler/cache/gems_spec.rb8
-rw-r--r--spec/bundler/cache/git_spec.rb9
-rw-r--r--spec/bundler/cache/path_spec.rb12
-rw-r--r--spec/bundler/commands/binstubs_spec.rb21
-rw-r--r--spec/bundler/commands/cache_spec.rb44
-rw-r--r--spec/bundler/commands/check_spec.rb143
-rw-r--r--spec/bundler/commands/clean_spec.rb15
-rw-r--r--spec/bundler/commands/config_spec.rb34
-rw-r--r--spec/bundler/commands/doctor_spec.rb24
-rw-r--r--spec/bundler/commands/exec_spec.rb74
-rw-r--r--spec/bundler/commands/info_spec.rb4
-rw-r--r--spec/bundler/commands/install_spec.rb171
-rw-r--r--spec/bundler/commands/lock_spec.rb4
-rw-r--r--spec/bundler/commands/newgem_spec.rb60
-rw-r--r--spec/bundler/commands/open_spec.rb1
-rw-r--r--spec/bundler/commands/outdated_spec.rb53
-rw-r--r--spec/bundler/commands/post_bundle_message_spec.rb1
-rw-r--r--spec/bundler/commands/update_spec.rb211
-rw-r--r--spec/bundler/install/allow_offline_install_spec.rb2
-rw-r--r--spec/bundler/install/deploy_spec.rb5
-rw-r--r--spec/bundler/install/failure_spec.rb97
-rw-r--r--spec/bundler/install/gemfile/eval_gemfile_spec.rb39
-rw-r--r--spec/bundler/install/gemfile/gemspec_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/git_spec.rb42
-rw-r--r--spec/bundler/install/gemfile/groups_spec.rb2
-rw-r--r--spec/bundler/install/gemfile/path_spec.rb30
-rw-r--r--spec/bundler/install/gemfile/platform_spec.rb1
-rw-r--r--spec/bundler/install/gemfile/sources_spec.rb1040
-rw-r--r--spec/bundler/install/gemfile/specific_platform_spec.rb37
-rw-r--r--spec/bundler/install/gemfile_spec.rb8
-rw-r--r--spec/bundler/install/gems/compact_index_spec.rb36
-rw-r--r--spec/bundler/install/gems/dependency_api_spec.rb36
-rw-r--r--spec/bundler/install/gems/native_extensions_spec.rb4
-rw-r--r--spec/bundler/install/gems/standalone_spec.rb72
-rw-r--r--spec/bundler/install/gemspecs_spec.rb7
-rw-r--r--spec/bundler/install/git_spec.rb4
-rw-r--r--spec/bundler/install/global_cache_spec.rb11
-rw-r--r--spec/bundler/install/redownload_spec.rb1
-rw-r--r--spec/bundler/install/yanked_spec.rb31
-rw-r--r--spec/bundler/lock/git_spec.rb1
-rw-r--r--spec/bundler/lock/lockfile_spec.rb107
-rw-r--r--spec/bundler/other/major_deprecation_spec.rb114
-rw-r--r--spec/bundler/other/platform_spec.rb16
-rw-r--r--spec/bundler/plugins/command_spec.rb6
-rw-r--r--spec/bundler/plugins/install_spec.rb36
-rw-r--r--spec/bundler/realworld/double_check_spec.rb4
-rw-r--r--spec/bundler/realworld/edgecases_spec.rb154
-rw-r--r--spec/bundler/realworld/slow_perf_spec.rb10
-rw-r--r--spec/bundler/runtime/executable_spec.rb1
-rw-r--r--spec/bundler/runtime/inline_spec.rb17
-rw-r--r--spec/bundler/runtime/load_spec.rb2
-rw-r--r--spec/bundler/runtime/platform_spec.rb2
-rw-r--r--spec/bundler/runtime/require_spec.rb17
-rw-r--r--spec/bundler/runtime/setup_spec.rb75
-rw-r--r--spec/bundler/runtime/with_unbundled_env_spec.rb2
-rw-r--r--spec/bundler/spec_helper.rb3
-rw-r--r--spec/bundler/support/api_request_limit_hax.rb16
-rw-r--r--spec/bundler/support/artifice/compact_index_rate_limited.rb2
-rw-r--r--spec/bundler/support/artifice/endpoint.rb6
-rw-r--r--spec/bundler/support/artifice/vcr.rb13
-rw-r--r--spec/bundler/support/builders.rb2
-rw-r--r--spec/bundler/support/hax.rb29
-rw-r--r--spec/bundler/support/helpers.rb18
-rw-r--r--spec/bundler/support/indexes.rb5
-rw-r--r--spec/bundler/support/matchers.rb10
-rw-r--r--spec/bundler/support/path.rb11
-rw-r--r--spec/bundler/update/git_spec.rb10
-rw-r--r--spec/bundler/update/path_spec.rb1
-rw-r--r--spec/mspec/README.md2
-rw-r--r--spec/mspec/lib/mspec/helpers/ruby_exe.rb10
-rw-r--r--spec/mspec/lib/mspec/utils/script.rb4
-rw-r--r--spec/mspec/spec/helpers/ruby_exe_spec.rb2
-rw-r--r--spec/ruby/.rubocop.yml2
-rw-r--r--spec/ruby/CONTRIBUTING.md2
-rw-r--r--spec/ruby/README.md6
-rw-r--r--spec/ruby/command_line/dash_upper_w_spec.rb2
-rw-r--r--spec/ruby/command_line/feature_spec.rb14
-rw-r--r--spec/ruby/core/array/difference_spec.rb28
-rw-r--r--spec/ruby/core/array/element_set_spec.rb60
-rw-r--r--spec/ruby/core/array/fill_spec.rb12
-rw-r--r--spec/ruby/core/array/filter_spec.rb18
-rw-r--r--spec/ruby/core/array/intersect_spec.rb17
-rw-r--r--spec/ruby/core/array/shared/slice.rb22
-rw-r--r--spec/ruby/core/array/slice_spec.rb34
-rw-r--r--spec/ruby/core/array/to_h_spec.rb72
-rw-r--r--spec/ruby/core/array/union_spec.rb26
-rw-r--r--spec/ruby/core/array/values_at_spec.rb8
-rw-r--r--spec/ruby/core/binding/source_location_spec.rb10
-rw-r--r--spec/ruby/core/dir/children_spec.rb114
-rw-r--r--spec/ruby/core/dir/each_child_spec.rb72
-rw-r--r--spec/ruby/core/dir/fixtures/common.rb1
-rw-r--r--spec/ruby/core/dir/glob_spec.rb27
-rw-r--r--spec/ruby/core/dir/shared/glob.rb22
-rw-r--r--spec/ruby/core/enumerable/all_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/any_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/chain_spec.rb30
-rw-r--r--spec/ruby/core/enumerable/filter_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/none_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/one_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/tally_spec.rb2
-rw-r--r--spec/ruby/core/enumerable/to_h_spec.rb80
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb12
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/each_spec.rb24
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/end_spec.rb12
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/eq_spec.rb24
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/exclude_end_spec.rb22
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/first_spec.rb12
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/hash_spec.rb26
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/inspect_spec.rb26
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/last_spec.rb12
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/new_spec.rb24
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/size_spec.rb22
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/step_spec.rb14
-rw-r--r--spec/ruby/core/enumerator/chain/each_spec.rb18
-rw-r--r--spec/ruby/core/enumerator/chain/initialize_spec.rb44
-rw-r--r--spec/ruby/core/enumerator/chain/inspect_spec.rb20
-rw-r--r--spec/ruby/core/enumerator/chain/rewind_spec.rb96
-rw-r--r--spec/ruby/core/enumerator/chain/size_spec.rb30
-rw-r--r--spec/ruby/core/enumerator/lazy/filter_spec.rb6
-rw-r--r--spec/ruby/core/enumerator/lazy/with_index_spec.rb30
-rw-r--r--spec/ruby/core/enumerator/plus_spec.rb46
-rw-r--r--spec/ruby/core/enumerator/yielder/append_spec.rb24
-rw-r--r--spec/ruby/core/env/filter_spec.rb16
-rw-r--r--spec/ruby/core/env/slice_spec.rb40
-rw-r--r--spec/ruby/core/env/to_h_spec.rb100
-rw-r--r--spec/ruby/core/exception/full_message_spec.rb110
-rw-r--r--spec/ruby/core/exception/key_error_spec.rb22
-rw-r--r--spec/ruby/core/exception/name_error_spec.rb12
-rw-r--r--spec/ruby/core/exception/no_method_error_spec.rb16
-rw-r--r--spec/ruby/core/exception/signal_exception_spec.rb6
-rw-r--r--spec/ruby/core/exception/top_level_spec.rb42
-rw-r--r--spec/ruby/core/file/open_spec.rb40
-rw-r--r--spec/ruby/core/float/comparison_spec.rb27
-rw-r--r--spec/ruby/core/gc/stat_spec.rb6
-rw-r--r--spec/ruby/core/hash/filter_spec.rb12
-rw-r--r--spec/ruby/core/hash/merge_spec.rb24
-rw-r--r--spec/ruby/core/hash/shared/update.rb16
-rw-r--r--spec/ruby/core/hash/to_h_spec.rb58
-rw-r--r--spec/ruby/core/hash/transform_keys_spec.rb27
-rw-r--r--spec/ruby/core/integer/try_convert_spec.rb40
-rw-r--r--spec/ruby/core/io/close_on_exec_spec.rb4
-rw-r--r--spec/ruby/core/io/external_encoding_spec.rb8
-rw-r--r--spec/ruby/core/io/internal_encoding_spec.rb8
-rw-r--r--spec/ruby/core/io/set_encoding_by_bom_spec.rb6
-rw-r--r--spec/ruby/core/io/ungetbyte_spec.rb15
-rw-r--r--spec/ruby/core/kernel/Complex_spec.rb62
-rw-r--r--spec/ruby/core/kernel/Float_spec.rb32
-rw-r--r--spec/ruby/core/kernel/Integer_spec.rb163
-rw-r--r--spec/ruby/core/kernel/autoload_spec.rb15
-rw-r--r--spec/ruby/core/kernel/caller_locations_spec.rb10
-rw-r--r--spec/ruby/core/kernel/caller_spec.rb10
-rw-r--r--spec/ruby/core/kernel/match_spec.rb10
-rw-r--r--spec/ruby/core/kernel/nil_spec.rb10
-rw-r--r--spec/ruby/core/kernel/open_spec.rb13
-rw-r--r--spec/ruby/core/kernel/raise_spec.rb28
-rw-r--r--spec/ruby/core/kernel/system_spec.rb12
-rw-r--r--spec/ruby/core/kernel/then_spec.rb6
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb8
-rw-r--r--spec/ruby/core/marshal/dump_spec.rb23
-rw-r--r--spec/ruby/core/marshal/fixtures/marshal_data.rb2
-rw-r--r--spec/ruby/core/marshal/shared/load.rb112
-rw-r--r--spec/ruby/core/method/compose_spec.rb134
-rw-r--r--spec/ruby/core/module/define_method_spec.rb51
-rw-r--r--spec/ruby/core/module/include_spec.rb156
-rw-r--r--spec/ruby/core/module/method_defined_spec.rb90
-rw-r--r--spec/ruby/core/module/prepend_spec.rb185
-rw-r--r--spec/ruby/core/module/private_method_defined_spec.rb88
-rw-r--r--spec/ruby/core/module/protected_method_defined_spec.rb88
-rw-r--r--spec/ruby/core/module/refine_spec.rb130
-rw-r--r--spec/ruby/core/module/remove_const_spec.rb21
-rw-r--r--spec/ruby/core/nil/match_spec.rb30
-rw-r--r--spec/ruby/core/numeric/shared/step.rb4
-rw-r--r--spec/ruby/core/numeric/step_spec.rb30
-rw-r--r--spec/ruby/core/proc/compose_spec.rb216
-rw-r--r--spec/ruby/core/proc/shared/compose.rb2
-rw-r--r--spec/ruby/core/process/spawn_spec.rb49
-rw-r--r--spec/ruby/core/process/status/wait_spec.rb102
-rw-r--r--spec/ruby/core/random/bytes_spec.rb6
-rw-r--r--spec/ruby/core/random/random_number_spec.rb4
-rw-r--r--spec/ruby/core/range/bsearch_spec.rb178
-rw-r--r--spec/ruby/core/range/case_compare_spec.rb24
-rw-r--r--spec/ruby/core/range/each_spec.rb34
-rw-r--r--spec/ruby/core/range/equal_value_spec.rb6
-rw-r--r--spec/ruby/core/range/inspect_spec.rb8
-rw-r--r--spec/ruby/core/range/last_spec.rb6
-rw-r--r--spec/ruby/core/range/max_spec.rb6
-rw-r--r--spec/ruby/core/range/min_spec.rb14
-rw-r--r--spec/ruby/core/range/minmax_spec.rb14
-rw-r--r--spec/ruby/core/range/new_spec.rb22
-rw-r--r--spec/ruby/core/range/percent_spec.rb24
-rw-r--r--spec/ruby/core/range/shared/cover.rb96
-rw-r--r--spec/ruby/core/range/shared/cover_and_include.rb8
-rw-r--r--spec/ruby/core/range/shared/equal_value.rb10
-rw-r--r--spec/ruby/core/range/size_spec.rb16
-rw-r--r--spec/ruby/core/range/step_spec.rb191
-rw-r--r--spec/ruby/core/range/to_a_spec.rb6
-rw-r--r--spec/ruby/core/range/to_s_spec.rb8
-rw-r--r--spec/ruby/core/rational/rational_spec.rb4
-rw-r--r--spec/ruby/core/string/gsub_spec.rb8
-rw-r--r--spec/ruby/core/string/index_spec.rb1
-rw-r--r--spec/ruby/core/string/scrub_spec.rb6
-rw-r--r--spec/ruby/core/string/shared/slice.rb12
-rw-r--r--spec/ruby/core/string/split_spec.rb152
-rw-r--r--spec/ruby/core/string/uminus_spec.rb40
-rw-r--r--spec/ruby/core/struct/filter_spec.rb10
-rw-r--r--spec/ruby/core/struct/to_h_spec.rb78
-rw-r--r--spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb18
-rw-r--r--spec/ruby/core/thread/backtrace_locations_spec.rb10
-rw-r--r--spec/ruby/core/thread/shared/wakeup.rb3
-rw-r--r--spec/ruby/core/time/at_spec.rb72
-rw-r--r--spec/ruby/core/time/getlocal_spec.rb102
-rw-r--r--spec/ruby/core/time/minus_spec.rb14
-rw-r--r--spec/ruby/core/time/new_spec.rb318
-rw-r--r--spec/ruby/core/time/plus_spec.rb14
-rw-r--r--spec/ruby/core/time/succ_spec.rb14
-rw-r--r--spec/ruby/core/tracepoint/enable_spec.rb544
-rw-r--r--spec/ruby/core/tracepoint/eval_script_spec.rb30
-rw-r--r--spec/ruby/core/tracepoint/inspect_spec.rb8
-rw-r--r--spec/ruby/core/tracepoint/parameters_spec.rb42
-rw-r--r--spec/ruby/core/warning/element_set_spec.rb2
-rw-r--r--spec/ruby/language/constants_spec.rb36
-rw-r--r--spec/ruby/language/delegation_spec.rb27
-rw-r--r--spec/ruby/language/hash_spec.rb15
-rw-r--r--spec/ruby/language/lambda_spec.rb12
-rw-r--r--spec/ruby/language/numbers_spec.rb4
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb44
-rw-r--r--spec/ruby/language/range_spec.rb8
-rw-r--r--spec/ruby/language/regexp/grouping_spec.rb28
-rw-r--r--spec/ruby/language/regexp_spec.rb9
-rw-r--r--spec/ruby/language/rescue_spec.rb38
-rw-r--r--spec/ruby/language/safe_spec.rb101
-rw-r--r--spec/ruby/language/variables_spec.rb63
-rw-r--r--spec/ruby/library/base64/decode64_spec.rb4
-rw-r--r--spec/ruby/library/bigdecimal/BigDecimal_spec.rb57
-rw-r--r--spec/ruby/library/bigdecimal/util_spec.rb6
-rw-r--r--spec/ruby/library/erb/fixtures/classes.rb6
-rw-r--r--spec/ruby/library/erb/new_spec.rb19
-rw-r--r--spec/ruby/library/matrix/antisymmetric_spec.rb52
-rw-r--r--spec/ruby/library/monitor/enter_spec.rb28
-rw-r--r--spec/ruby/library/monitor/new_cond_spec.rb88
-rw-r--r--spec/ruby/library/monitor/synchronize_spec.rb19
-rw-r--r--spec/ruby/library/monitor/try_enter_spec.rb39
-rw-r--r--spec/ruby/library/net/http/HTTPClientExcepton_spec.rb14
-rw-r--r--spec/ruby/library/net/http/HTTPServerException_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/fixtures/http_server.rb151
-rw-r--r--spec/ruby/library/net/http/http/post_spec.rb2
-rw-r--r--spec/ruby/library/net/http/http/send_request_spec.rb2
-rw-r--r--spec/ruby/library/net/http/httpresponse/error_spec.rb7
-rw-r--r--spec/ruby/library/net/http/httpresponse/error_type_spec.rb7
-rw-r--r--spec/ruby/library/net/http/httpresponse/exception_type_spec.rb7
-rw-r--r--spec/ruby/library/net/http/httpresponse/value_spec.rb7
-rw-r--r--spec/ruby/library/objectspace/memsize_of_all_spec.rb21
-rw-r--r--spec/ruby/library/objectspace/memsize_of_spec.rb2
-rw-r--r--spec/ruby/library/objectspace/trace_object_allocations_spec.rb131
-rw-r--r--spec/ruby/library/openstruct/to_h_spec.rb60
-rw-r--r--spec/ruby/library/rbconfig/rbconfig_spec.rb2
-rw-r--r--spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb10
-rw-r--r--spec/ruby/library/rbconfig/unicode_version_spec.rb16
-rw-r--r--spec/ruby/library/set/filter_spec.rb6
-rw-r--r--spec/ruby/library/set/sortedset/filter_spec.rb6
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb21
-rw-r--r--spec/ruby/library/socket/basicsocket/recvmsg_nonblock_spec.rb15
-rw-r--r--spec/ruby/library/socket/basicsocket/sendmsg_nonblock_spec.rb7
-rw-r--r--spec/ruby/library/socket/socket/accept_nonblock_spec.rb3
-rw-r--r--spec/ruby/optional/capi/array_spec.rb8
-rw-r--r--spec/ruby/optional/capi/debug_spec.rb12
-rw-r--r--spec/ruby/optional/capi/encoding_spec.rb32
-rw-r--r--spec/ruby/optional/capi/ext/array_spec.c22
-rw-r--r--spec/ruby/optional/capi/ext/fiber_spec.c58
-rw-r--r--spec/ruby/optional/capi/ext/integer_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c18
-rw-r--r--spec/ruby/optional/capi/ext/regexp_spec.c6
-rw-r--r--spec/ruby/optional/capi/ext/rubyspec.h2
-rw-r--r--spec/ruby/optional/capi/ext/string_spec.c79
-rw-r--r--spec/ruby/optional/capi/fiber_spec.rb51
-rw-r--r--spec/ruby/optional/capi/fixtures/read.txt1
-rw-r--r--spec/ruby/optional/capi/proc_spec.rb5
-rw-r--r--spec/ruby/optional/capi/regexp_spec.rb29
-rw-r--r--spec/ruby/optional/capi/spec_helper.rb7
-rw-r--r--spec/ruby/optional/capi/string_spec.rb48
-rw-r--r--spec/ruby/security/cve_2017_17742_spec.rb57
-rw-r--r--spec/ruby/security/cve_2019_8321_spec.rb26
-rw-r--r--spec/ruby/security/cve_2019_8322_spec.rb24
-rw-r--r--spec/ruby/security/cve_2019_8323_spec.rb48
-rw-r--r--spec/ruby/security/cve_2019_8325_spec.rb2
-rw-r--r--spec/ruby/security/cve_2020_10663_spec.rb3
-rw-r--r--spec/ruby/shared/rational/Rational.rb54
-rw-r--r--sprintf.c18
-rw-r--r--strftime.c4
-rw-r--r--string.c142
-rw-r--r--struct.c27
-rw-r--r--symbol.c23
-rw-r--r--template/Doxyfile.tmpl2541
-rw-r--r--template/Makefile.in26
-rw-r--r--template/encdb.h.tmpl17
-rw-r--r--template/ruby.pc.in16
-rw-r--r--test/-ext-/array/test_to_ary_concat.rb20
-rw-r--r--test/-ext-/float/test_nextafter.rb2
-rw-r--r--test/-ext-/string/test_enc_str_buf_cat.rb9
-rw-r--r--test/-ext-/test_printf.rb4
-rw-r--r--test/-ext-/thread_fd/test_thread_fd_close.rb (renamed from test/-ext-/thread_fd_close/test_thread_fd_close.rb)2
-rw-r--r--test/-ext-/wait/test_wait.rb32
-rw-r--r--test/-ext-/wait_for_single_fd/test_wait_for_single_fd.rb49
-rw-r--r--test/coverage/test_coverage.rb14
-rw-r--r--test/date/test_date.rb12
-rw-r--r--test/did_you_mean/spell_checking/test_uncorrectable_name_check.rb2
-rw-r--r--test/did_you_mean/tree_spell/test_change_word.rb2
-rw-r--r--test/digest/test_ractor.rb2
-rw-r--r--test/error_highlight/test_error_highlight.rb1197
-rw-r--r--test/excludes/TestArray.rb1
-rw-r--r--test/fiber/scheduler.rb30
-rw-r--r--test/fiber/test_io.rb43
-rw-r--r--test/fiber/test_mutex.rb18
-rw-r--r--test/fiber/test_thread.rb39
-rw-r--r--test/fiddle/helper.rb20
-rw-r--r--test/fiddle/test_c_struct_builder.rb69
-rw-r--r--test/fiddle/test_cparser.rb2
-rw-r--r--test/fiddle/test_func.rb25
-rw-r--r--test/fiddle/test_function.rb64
-rw-r--r--test/fiddle/test_handle.rb35
-rw-r--r--test/fiddle/test_memory_view.rb36
-rw-r--r--test/fiddle/test_pinned.rb1
-rw-r--r--test/fiddle/test_pointer.rb21
-rw-r--r--test/fileutils/test_fileutils.rb2
-rw-r--r--test/irb/test_cmd.rb123
-rw-r--r--test/irb/test_color.rb2
-rw-r--r--test/irb/test_color_printer.rb2
-rw-r--r--test/irb/test_completion.rb25
-rw-r--r--test/irb/test_context.rb57
-rw-r--r--test/irb/test_raise_no_backtrace_exception.rb6
-rw-r--r--test/irb/test_ruby_lex.rb30
-rw-r--r--test/irb/test_workspace.rb21
-rw-r--r--test/irb/yamatanooroti/test_rendering.rb23
-rw-r--r--test/logger/helper.rb13
-rw-r--r--test/logger/test_logdevice.rb2
-rw-r--r--test/logger/test_logger.rb2
-rw-r--r--test/logger/test_logperiod.rb2
-rw-r--r--test/logger/test_severity.rb2
-rw-r--r--test/mkmf/test_have_var.rb17
-rw-r--r--test/mkmf/test_libs.rb9
-rw-r--r--test/monitor/test_monitor.rb24
-rw-r--r--test/net/http/test_http.rb27
-rw-r--r--test/net/http/test_httpresponse.rb2
-rw-r--r--test/openssl/fixtures/pkey/certificate.derbin0 -> 1325 bytes
-rw-r--r--test/openssl/fixtures/pkey/empty.der0
-rw-r--r--test/openssl/fixtures/pkey/empty.pem0
-rw-r--r--test/openssl/fixtures/pkey/fullchain.pem56
-rw-r--r--test/openssl/fixtures/pkey/garbage.txt1
-rw-r--r--test/openssl/test_asn1.rb7
-rw-r--r--test/openssl/test_bn.rb44
-rw-r--r--test/openssl/test_ocsp.rb9
-rw-r--r--test/openssl/test_pkey.rb5
-rw-r--r--test/openssl/test_pkey_dh.rb31
-rw-r--r--test/openssl/test_pkey_dsa.rb48
-rw-r--r--test/openssl/test_pkey_ec.rb21
-rw-r--r--test/openssl/test_pkey_rsa.rb179
-rw-r--r--test/openssl/test_ssl.rb128
-rw-r--r--test/openssl/test_x509cert.rb44
-rw-r--r--test/openssl/ut_eof.rb4
-rw-r--r--test/openssl/utils.rb3
-rw-r--r--test/ostruct/test_ostruct.rb4
-rw-r--r--test/pathname/test_pathname.rb30
-rw-r--r--test/pathname/test_ractor.rb2
-rw-r--r--test/psych/test_scalar_scanner.rb49
-rw-r--r--test/psych/test_string.rb13
-rw-r--r--test/psych/visitors/test_yaml_tree.rb1
-rw-r--r--test/racc/assets/mof.y6
-rw-r--r--test/racc/case.rb (renamed from test/racc/helper.rb)7
-rw-r--r--test/racc/regress/cast1223
-rw-r--r--test/racc/regress/huia619
-rw-r--r--test/racc/regress/mof6
-rw-r--r--test/racc/regress/nasl1122
-rw-r--r--test/racc/regress/opal7426
-rw-r--r--test/racc/regress/riml1922
-rw-r--r--test/racc/regress/ruby187193
-rw-r--r--test/racc/regress/ruby227654
-rw-r--r--test/racc/test_chk_y.rb2
-rw-r--r--test/racc/test_grammar_file_parser.rb2
-rw-r--r--test/racc/test_racc_command.rb2
-rw-r--r--test/racc/test_scan_y.rb2
-rw-r--r--test/rdoc/support/test_case.rb17
-rw-r--r--test/rdoc/test_rdoc_generator_darkfish.rb24
-rw-r--r--test/rdoc/test_rdoc_generator_json_index.rb2
-rw-r--r--test/rdoc/test_rdoc_markup_to_html.rb26
-rw-r--r--test/rdoc/test_rdoc_options.rb73
-rw-r--r--test/rdoc/test_rdoc_parser_ruby.rb48
-rw-r--r--test/rdoc/test_rdoc_rdoc.rb58
-rw-r--r--test/rdoc/test_rdoc_ri_driver.rb24
-rw-r--r--test/rdoc/test_rdoc_rubygems_hook.rb74
-rw-r--r--test/rdoc/test_rdoc_servlet.rb4
-rw-r--r--test/rdoc/test_rdoc_task.rb4
-rw-r--r--test/rdoc/test_rdoc_text.rb10
-rw-r--r--test/readline/helper.rb5
-rw-r--r--test/readline/test_readline.rb118
-rw-r--r--test/readline/test_readline_history.rb7
-rw-r--r--test/reline/helper.rb17
-rw-r--r--test/reline/test_config.rb31
-rw-r--r--test/reline/test_history.rb11
-rw-r--r--test/reline/test_key_actor_emacs.rb150
-rw-r--r--test/reline/test_key_actor_vi.rb36
-rw-r--r--test/reline/test_key_stroke.rb32
-rw-r--r--test/reline/test_macro.rb4
-rw-r--r--test/reline/test_reline.rb8
-rw-r--r--test/reline/test_string_processing.rb6
-rw-r--r--test/reline/test_terminfo.rb32
-rw-r--r--test/reline/test_unicode.rb9
-rw-r--r--test/reline/test_within_pipe.rb7
-rw-r--r--test/reline/windows/test_key_event_record.rb41
-rwxr-xr-xtest/reline/yamatanooroti/multiline_repl64
-rw-r--r--test/reline/yamatanooroti/termination_checker.rb2
-rw-r--r--test/reline/yamatanooroti/test_rendering.rb341
-rw-r--r--test/ripper/test_ripper.rb9
-rw-r--r--test/ripper/test_sexp.rb14
-rw-r--r--test/ruby/enc/test_emoji_breaks.rb57
-rw-r--r--test/ruby/marshaltestlib.rb2
-rw-r--r--test/ruby/test_argf.rb19
-rw-r--r--test/ruby/test_array.rb30
-rw-r--r--test/ruby/test_ast.rb32
-rw-r--r--test/ruby/test_backtrace.rb28
-rw-r--r--test/ruby/test_bignum.rb2
-rw-r--r--test/ruby/test_dir.rb13
-rw-r--r--test/ruby/test_enumerator.rb2
-rw-r--r--test/ruby/test_exception.rb31
-rw-r--r--test/ruby/test_fiber.rb5
-rw-r--r--test/ruby/test_gc.rb34
-rw-r--r--test/ruby/test_gc_compact.rb5
-rw-r--r--test/ruby/test_hash.rb199
-rw-r--r--test/ruby/test_integer.rb19
-rw-r--r--test/ruby/test_io.rb62
-rw-r--r--test/ruby/test_jit.rb17
-rw-r--r--test/ruby/test_keyword.rb17
-rw-r--r--test/ruby/test_literal.rb24
-rw-r--r--test/ruby/test_marshal.rb19
-rw-r--r--test/ruby/test_math.rb53
-rw-r--r--test/ruby/test_method.rb19
-rw-r--r--test/ruby/test_module.rb58
-rw-r--r--test/ruby/test_name_error.rb2
-rw-r--r--test/ruby/test_nomethod_error.rb2
-rw-r--r--test/ruby/test_numeric.rb17
-rw-r--r--test/ruby/test_object.rb2
-rw-r--r--test/ruby/test_objectspace.rb34
-rw-r--r--test/ruby/test_optimization.rb46
-rw-r--r--test/ruby/test_pack.rb4
-rw-r--r--test/ruby/test_parse.rb26
-rw-r--r--test/ruby/test_pattern_matching.rb167
-rw-r--r--test/ruby/test_proc.rb9
-rw-r--r--test/ruby/test_process.rb14
-rw-r--r--test/ruby/test_refinement.rb16
-rw-r--r--test/ruby/test_regexp.rb41
-rw-r--r--test/ruby/test_require.rb17
-rw-r--r--test/ruby/test_settracefunc.rb66
-rw-r--r--test/ruby/test_string.rb10
-rw-r--r--test/ruby/test_struct.rb11
-rw-r--r--test/ruby/test_syntax.rb3
-rw-r--r--test/ruby/test_thread.rb18
-rw-r--r--test/ruby/test_thread_cv.rb60
-rw-r--r--test/ruby/test_thread_queue.rb80
-rw-r--r--test/ruby/test_time.rb4
-rw-r--r--test/ruby/test_transcode.rb22
-rw-r--r--test/rubygems/bogussources.rb9
-rw-r--r--test/rubygems/data/null-type.gemspec.rzbin554 -> 504 bytes
-rw-r--r--test/rubygems/helper.rb12
-rw-r--r--test/rubygems/packages/ill-formatted-platform-1.0.0.10.gembin0 -> 10240 bytes
-rw-r--r--test/rubygems/test_exit.rb11
-rw-r--r--test/rubygems/test_gem.rb367
-rw-r--r--test/rubygems/test_gem_bundler_version_finder.rb4
-rw-r--r--test/rubygems/test_gem_command.rb12
-rw-r--r--test/rubygems/test_gem_commands_help_command.rb7
-rw-r--r--test/rubygems/test_gem_commands_install_command.rb25
-rw-r--r--test/rubygems/test_gem_commands_push_command.rb5
-rw-r--r--test/rubygems/test_gem_commands_setup_command.rb4
-rw-r--r--test/rubygems/test_gem_commands_signin_command.rb7
-rw-r--r--test/rubygems/test_gem_dependency.rb6
-rw-r--r--test/rubygems/test_gem_ext_builder.rb6
-rw-r--r--test/rubygems/test_gem_ext_ext_conf_builder.rb1
-rw-r--r--test/rubygems/test_gem_ext_rake_builder.rb2
-rw-r--r--test/rubygems/test_gem_gemcutter_utilities.rb18
-rw-r--r--test/rubygems/test_gem_installer.rb22
-rw-r--r--test/rubygems/test_gem_package.rb7
-rw-r--r--test/rubygems/test_gem_path_support.rb8
-rw-r--r--test/rubygems/test_gem_remote_fetcher.rb30
-rw-r--r--test/rubygems/test_gem_request.rb34
-rw-r--r--test/rubygems/test_gem_requirement.rb34
-rw-r--r--test/rubygems/test_gem_resolver_installer_set.rb18
-rw-r--r--test/rubygems/test_gem_specification.rb170
-rw-r--r--test/rubygems/test_gem_uninstaller.rb11
-rw-r--r--test/rubygems/test_gem_uri.rb32
-rw-r--r--test/rubygems/test_kernel.rb2
-rw-r--r--test/rubygems/test_require.rb2
-rw-r--r--test/rubygems/test_rubygems.rb44
-rw-r--r--test/runner.rb2
-rw-r--r--test/socket/test_addrinfo.rb2
-rw-r--r--test/socket/test_basicsocket.rb2
-rw-r--r--test/socket/test_socket.rb4
-rw-r--r--test/test_pstore.rb4
-rw-r--r--test/test_set.rb6
-rw-r--r--test/uri/test_common.rb22
-rw-r--r--test/uri/test_generic.rb7
-rw-r--r--test/yaml/test_store.rb4
-rw-r--r--test/zlib/test_zlib.rb65
-rw-r--r--thread.c214
-rw-r--r--thread_pthread.c12
-rw-r--r--thread_sync.c228
-rw-r--r--thread_win32.c4
-rw-r--r--thread_win32.h4
-rw-r--r--time.c67
-rw-r--r--timev.rb11
-rw-r--r--tool/bundler/rubocop_gems.rb.lock1
-rw-r--r--tool/bundler/standard_gems.rb.lock1
-rw-r--r--tool/downloader.rb17
-rwxr-xr-xtool/enc-unicode.rb6
-rwxr-xr-xtool/intern_ids.rb35
-rw-r--r--tool/lib/colorize.rb2
-rw-r--r--tool/lib/core_assertions.rb (renamed from tool/lib/test/unit/core_assertions.rb)78
-rw-r--r--tool/lib/gc_checker.rb36
-rw-r--r--tool/lib/gc_compact_checker.rb10
-rw-r--r--tool/lib/leakchecker.rb4
-rw-r--r--tool/lib/memory_status.rb6
-rw-r--r--tool/lib/minitest/README.txt457
-rw-r--r--tool/lib/minitest/unit.rb1479
-rw-r--r--tool/lib/profile_test_all.rb2
-rw-r--r--tool/lib/test/unit.rb468
-rw-r--r--tool/lib/test/unit/assertions.rb560
-rw-r--r--tool/lib/test/unit/parallel.rb27
-rw-r--r--tool/lib/test/unit/testcase.rb328
-rw-r--r--tool/lib/vcs.rb28
-rw-r--r--tool/m4/_colorize_result_prepare.m41
-rwxr-xr-xtool/make-snapshot6
-rw-r--r--tool/mk_builtin_loader.rb2
-rwxr-xr-xtool/mkrunnable.rb18
-rwxr-xr-xtool/rbinstall.rb72
-rw-r--r--tool/ruby_vm/views/_trace_instruction.erb7
-rwxr-xr-xtool/strip-rdoc.rb30
-rw-r--r--tool/sync_default_gems.rb40
-rw-r--r--tool/test-bundled-gems.rb17
-rw-r--r--tool/test/runner.rb2
-rw-r--r--tool/test/testunit/metametameta.rb (renamed from tool/test/minitest/metametameta.rb)16
-rw-r--r--tool/test/testunit/test_assertion.rb2
-rw-r--r--tool/test/testunit/test_minitest_unit.rb (renamed from tool/test/minitest/test_minitest_unit.rb)526
-rw-r--r--tool/test/testunit/test_parallel.rb10
-rw-r--r--tool/test/webrick/utils.rb2
-rwxr-xr-x[-rw-r--r--]tool/update-bundled_gems.rb8
-rw-r--r--trace_point.rb2
-rw-r--r--transcode.c107
-rw-r--r--util.c22
-rw-r--r--variable.c190
-rw-r--r--variable.h1
-rw-r--r--version.c2
-rw-r--r--version.h5
-rw-r--r--vm.c91
-rw-r--r--vm_args.c2
-rw-r--r--vm_backtrace.c483
-rw-r--r--vm_callinfo.h7
-rw-r--r--vm_core.h16
-rw-r--r--vm_debug.h1
-rw-r--r--vm_eval.c147
-rw-r--r--vm_exec.c1
-rw-r--r--vm_exec.h25
-rw-r--r--vm_insnhelper.c208
-rw-r--r--vm_insnhelper.h3
-rw-r--r--vm_method.c63
-rw-r--r--vm_trace.c51
-rw-r--r--win32/Makefile.sub13
-rwxr-xr-xwin32/configure.bat22
-rw-r--r--win32/setup.mak10
-rw-r--r--win32/win32.c2
1336 files changed, 80232 insertions, 32891 deletions
diff --git a/.document b/.document
index 8b4938f..2c68af2 100644
--- a/.document
+++ b/.document
@@ -18,6 +18,7 @@ gc.rb
io.rb
kernel.rb
numeric.rb
+nilclass.rb
pack.rb
ractor.rb
timev.rb
diff --git a/.github/codeql/codeql-config.yml b/.github/codeql/codeql-config.yml
index 7196708..91f82b8 100644
--- a/.github/codeql/codeql-config.yml
+++ b/.github/codeql/codeql-config.yml
@@ -1,4 +1,3 @@
name: "CodeQL config for the Ruby language"
-paths-ignore:
- - '/ext/**/*/conftest.c'
+languages: cpp
diff --git a/.github/workflows/baseruby.yml b/.github/workflows/baseruby.yml
index 11f71e0..788ca8f 100644
--- a/.github/workflows/baseruby.yml
+++ b/.github/workflows/baseruby.yml
@@ -15,6 +15,7 @@ jobs:
# - ruby-2.5
# - ruby-2.6
- ruby-2.7
+ - ruby-3.0
steps:
- uses: actions/checkout@v2
@@ -42,4 +43,4 @@ jobs:
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: failure() && github.event_name == 'push'
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/bundled_gems.yml b/.github/workflows/bundled_gems.yml
new file mode 100644
index 0000000..d46c070
--- /dev/null
+++ b/.github/workflows/bundled_gems.yml
@@ -0,0 +1,66 @@
+name: bundled_gems
+
+on:
+ schedule:
+ - cron: '45 6 * * *'
+
+jobs:
+ update:
+ if: ${{ github.repository == 'ruby/ruby' }}
+ name: update ${{ github.workflow }}
+ runs-on: ubuntu-latest
+ steps:
+ - name: git config
+ run: |
+ git config --global advice.detachedHead 0
+ git config --global init.defaultBranch garbage
+
+ - name: Set ENV
+ run: |
+ echo "JOBS=-j$((1 + $(nproc --all)))" >> $GITHUB_ENV
+
+ - uses: actions/checkout@v2
+
+ - name: Update ${{ github.workflow }}
+ run: |
+ ruby -i~ tool/update-bundled_gems.rb gems/${{ github.workflow }}
+
+ - name: Check diffs
+ id: diff
+ run: |
+ git diff --no-ext-diff --ignore-submodules --exit-code
+ continue-on-error: true
+
+ - name: Install libraries
+ run: |
+ set -x
+ sudo apt-get update -q || :
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
+ if: ${{ steps.diff.outcome == 'failure' }}
+
+ - name: Build
+ run: |
+ ./autogen.sh
+ ./configure -C --disable-install-doc
+ make $JOBS
+ if: ${{ steps.diff.outcome == 'failure' }}
+
+ - name: Test bundled gems
+ run: |
+ make $JOBS -s test-bundled-gems
+ timeout-minutes: 30
+ env:
+ RUBY_TESTOPTS: "-q --tty=no"
+ TEST_BUNDLED_GEMS_ALLOW_FAILURES: ""
+ if: ${{ steps.diff.outcome == 'failure' }}
+
+ - name: Commit
+ run: |
+ git commit --message="Update ${{ github.workflow }} at $(date +%F)" gems/${{ github.workflow }}
+ git pull --ff-only origin ${GITHUB_REF#refs/heads/}
+ git push origin ${GITHUB_REF#refs/heads/}
+ env:
+ EMAIL: svn-admin@ruby-lang.org
+ GIT_AUTHOR_NAME: git
+ GIT_COMMITTER_NAME: git
+ if: ${{ steps.diff.outcome == 'failure' }}
diff --git a/.github/workflows/check_dependencies.yml b/.github/workflows/check_dependencies.yml
index d207378..645da40 100644
--- a/.github/workflows/check_dependencies.yml
+++ b/.github/workflows/check_dependencies.yml
@@ -12,13 +12,13 @@ jobs:
run: |
set -x
sudo apt-get update -q || :
- sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev bison autoconf ruby
- if: "contains(matrix.os, 'ubuntu')"
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
+ if: ${{ contains(matrix.os, 'ubuntu') }}
- name: Install libraries
run: |
brew upgrade
- brew install gdbm gmp libffi openssl@1.1 zlib autoconf automake libtool readline
- if: "contains(matrix.os, 'macos')"
+ brew install gmp libffi openssl@1.1 zlib autoconf automake libtool readline
+ if: ${{ contains(matrix.os, 'macos') }}
- name: git config
run: |
git config --global advice.detachedHead 0
@@ -42,4 +42,4 @@ jobs:
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: failure() && github.event_name == 'push'
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 22c5cc0..19ad77d 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -17,12 +17,10 @@ jobs:
run: |
set -x
sudo apt-get update -q || :
- sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev bison autoconf ruby
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
- name: Checkout repository
uses: actions/checkout@v2
- with:
- fetch-depth: 2
- name: Remove an obsolete rubygems vendored file
run: sudo rm /usr/lib/ruby/vendor_ruby/rubygems/defaults/operating_system.rb
@@ -30,7 +28,6 @@ jobs:
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
with:
- languages: cpp
config-file: ./.github/codeql/codeql-config.yml
- name: Autobuild
diff --git a/.github/workflows/compilers.yml b/.github/workflows/compilers.yml
index 3bd7bab..2fc387a 100644
--- a/.github/workflows/compilers.yml
+++ b/.github/workflows/compilers.yml
@@ -3,15 +3,15 @@ name: Compilations
on: [push, pull_request]
# Github actions does not support YAML anchors. This creative use of
-# environment variables (plus the "echo ::set-env" hack) is to reroute that
+# environment variables (plus the "echo $GITHUB_ENV" hack) is to reroute that
# restriction.
env:
- default_cc: clang-13
+ default_cc: clang-14
append_cc: ''
crosshost: ''
# -O1 is faster than -O3 in our tests... Majority of time are consumed trying
- # to optimize binaries. Also Github Actions runs on a relatively modern CPU
+ # to optimize binaries. Also Github Actions run on relatively modern CPUs
# compared to, say, GCC 4 or Clang 3. We don't specify `-march=native`
# because compilers tend not understand what the CPU is.
optflags: '-O1'
@@ -55,6 +55,13 @@ jobs:
- { key: default_cc, name: gcc-6, value: gcc-6, container: gcc-6 }
- { key: default_cc, name: gcc-5, value: gcc-5, container: gcc-5 }
- { key: default_cc, name: gcc-4.8, value: gcc-4.8, container: gcc-4.8 }
+ - key: default_cc
+ name: 'gcc-11 LTO'
+ value: 'gcc-11 -O2 -flto=auto -ffat-lto-objects'
+ container: gcc-11
+ shared: '--disable-shared'
+ # check: true
+ - { key: default_cc, name: clang-14, value: clang-14, container: clang-14 }
- { key: default_cc, name: clang-13, value: clang-13, container: clang-13 }
- { key: default_cc, name: clang-12, value: clang-12, container: clang-12 }
- { key: default_cc, name: clang-11, value: clang-11, container: clang-11 }
@@ -66,6 +73,12 @@ jobs:
- { key: default_cc, name: clang-5.0, value: clang-5.0, container: clang-5.0 }
- { key: default_cc, name: clang-4.0, value: clang-4.0, container: clang-4.0 }
- { key: default_cc, name: clang-3.9, value: clang-3.9, container: clang-3.9 }
+ - key: default_cc
+ name: 'clang-14 LTO'
+ value: 'clang-14 -O2 -flto=auto'
+ container: clang-14
+ shared: '--disable-shared'
+ # check: true
- { key: crosshost, name: aarch64-linux-gnu, value: aarch64-linux-gnu, container: crossbuild-essential-arm64 }
# - { key: crosshost, name: arm-linux-gnueabi, value: arm-linux-gnueabi }
@@ -87,13 +100,13 @@ jobs:
- { key: CXXFLAGS, name: c++2a, value: '-std=c++2a -Werror=pedantic -pedantic-errors -Wno-c++11-long-long' }
- { key: optflags, name: '-O0', value: '-O0 -march=x86-64 -mtune=generic' }
-# - { key: optflags, name: '-O3', value: '-O3 -march=x86-64 -mtune=generic' }
+# - { key: optflags, name: '-O3', value: '-O3 -march=x86-64 -mtune=generic', check: true }
- { key: append_configure, name: gmp, value: '--with-gmp' }
- { key: append_configure, name: jemalloc, value: '--with-jemalloc' }
- { key: append_configure, name: valgrind, value: '--with-valgrind' }
- { key: append_configure, name: 'coroutine=ucontext', value: '--with-coroutine=ucontext' }
- - { key: append_configure, name: 'coroutine=copy', value: '--with-coroutine=copy' }
+ - { key: append_configure, name: 'coroutine=pthread', value: '--with-coroutine=pthread' }
- { key: append_configure, name: disable-jit-support, value: '--disable-jit-support' }
- { key: append_configure, name: disable-dln, value: '--disable-dln' }
- { key: append_configure, name: disable-rubygems, value: '--disable-rubygems' }
@@ -157,8 +170,12 @@ jobs:
name: ${{ matrix.entry.name }}
runs-on: ubuntu-latest
- container: ghcr.io/ruby/ruby-ci-image:${{ matrix.entry.container || 'clang-13' }}
+ container:
+ image: ghcr.io/ruby/ruby-ci-image:${{ matrix.entry.container || 'clang-14' }}
+ options: --user root
steps:
+ - run: id
+ working-directory:
- run: mkdir build
working-directory:
- name: setenv
@@ -171,33 +188,25 @@ jobs:
- run: ./autogen.sh
working-directory: src
- name: Run configure
- run: |
- if [ -n "${crosshost}" ]; then
- ../src/configure -C \
- ${default_configure} \
- ${append_configure} \
- --host="${crosshost}"
- else
- ../src/configure -C \
- ${default_configure} \
- ${append_configure} \
- --with-gcc="${default_cc} ${append_cc}"
- fi
+ run: >
+ ../src/configure -C ${default_configure} ${append_configure}
+ ${{ matrix.entry.key == 'crosshost' && '--host="${crosshost}"' || '--with-gcc="${default_cc} ${append_cc}"' }}
+ ${{ matrix.entry.shared || '--enable-shared' }}
- run: $make extract-extlibs
- run: $make incs
- run: $make
- run: $make leaked-globals
- run: $make test
- run: $make install
- if: "matrix.entry.name == '-O3'"
+ if: ${{ matrix.entry.check }}
- run: /usr/local/bin/gem install --no-doc timezone tzinfo
- if: "matrix.entry.name == '-O3'"
+ if: ${{ matrix.entry.check }}
- run: $make test-tool
- if: "matrix.entry.name == '-O3'"
+ if: ${{ matrix.entry.check }}
- run: $make test-all TESTS='-- ruby -ext-'
- if: "matrix.entry.name == '-O3'"
+ if: ${{ matrix.entry.check }}
- run: $make test-spec
- if: "matrix.entry.name == '-O3'"
+ if: ${{ matrix.entry.check }}
- uses: k0kubun/action-slack@v2.0.0
with:
@@ -211,7 +220,7 @@ jobs:
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: failure() && github.event_name == 'push'
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 9e02185..0a2d7ea 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -22,7 +22,7 @@ jobs:
- name: Install libraries
run: |
brew upgrade
- brew install gdbm gmp libffi openssl@1.1 zlib autoconf automake libtool readline
+ brew install gmp libffi openssl@1.1 zlib autoconf automake libtool readline
working-directory: src
- name: Set ENV
run: |
@@ -34,9 +34,9 @@ jobs:
- run: make $JOBS incs
- run: make $JOBS
- run: make leaked-globals
- if: matrix.test_task == 'check'
+ if: ${{ matrix.test_task == 'check' }}
- run: make prepare-gems
- if: matrix.test_task == 'check'
+ if: ${{ matrix.test_task == 'check' }}
- run: make $JOBS -s ${{ matrix.test_task }}
timeout-minutes: 60
env:
@@ -54,7 +54,7 @@ jobs:
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: failure() && github.event_name == 'push'
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/mingw.yml b/.github/workflows/mingw.yml
index f807a2e..8f5a8e6 100644
--- a/.github/workflows/mingw.yml
+++ b/.github/workflows/mingw.yml
@@ -38,7 +38,7 @@ jobs:
uses: MSP-Greg/setup-ruby-pkgs@v1
with:
ruby-version: 2.6
- mingw: _upgrade_ gdbm gmp libffi libyaml openssl ragel readline
+ mingw: _upgrade_ gmp libffi libyaml openssl ragel readline
msys2: automake1.16 bison
- name: where check
run: |
@@ -136,7 +136,7 @@ jobs:
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: failure() && github.event_name == 'push'
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/mjit.yml b/.github/workflows/mjit.yml
index d5cc9e9..63011e7 100644
--- a/.github/workflows/mjit.yml
+++ b/.github/workflows/mjit.yml
@@ -19,7 +19,7 @@ jobs:
run: |
set -x
sudo apt-get update -q || :
- sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev bison autoconf ruby
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
- name: git config
run: |
git config --global advice.detachedHead 0
@@ -70,7 +70,7 @@ jobs:
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: failure() && github.event_name == 'push'
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/spec_guards.yml b/.github/workflows/spec_guards.yml
index f921d66..61ebeb3 100644
--- a/.github/workflows/spec_guards.yml
+++ b/.github/workflows/spec_guards.yml
@@ -35,4 +35,4 @@ jobs:
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: failure() && github.event_name == 'push'
+ if: ${{ failure() && github.event_name == 'push' }}
diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml
index 34dffa2..e148b76 100644
--- a/.github/workflows/ubuntu.yml
+++ b/.github/workflows/ubuntu.yml
@@ -4,14 +4,15 @@ jobs:
make:
strategy:
matrix:
- test_task: [ "check", "test-bundler-parallel", "test-bundled-gems", "test-all TESTS=--repeat-count=2" ]
+ test_task: ["check", "test-bundler-parallel", "test-bundled-gems"]
os:
- ubuntu-20.04
# - ubuntu-18.04
- debug: ["", "-DRUBY_DEBUG"]
- exclude:
+ configure: ["", "cppflags=-DRUBY_DEBUG"]
+ include:
- test_task: "test-all TESTS=--repeat-count=2"
- debug: -DRUBY_DEBUG
+ os: ubuntu-20.04
+ configure: ""
fail-fast: false
env:
GITPULLOPTIONS: --no-tags origin ${{github.ref}}
@@ -24,7 +25,7 @@ jobs:
run: |
set -x
sudo apt-get update -q || :
- sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm-dev bison autoconf ruby
+ sudo apt-get install --no-install-recommends -q -y build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev bison autoconf ruby
- name: git config
run: |
git config --global advice.detachedHead 0
@@ -43,17 +44,17 @@ jobs:
- run: ./autogen.sh
working-directory: src
- name: Run configure
- run: ../src/configure -C --disable-install-doc cppflags=${{ matrix.debug }}
+ run: ../src/configure -C --disable-install-doc ${{ matrix.configure }}
- run: make $JOBS incs
- run: make $JOBS
- run: make leaked-globals
- if: matrix.test_task == 'check'
+ if: ${{ matrix.test_task == 'check' }}
- run: make prepare-gems
- if: matrix.test_task == 'check'
+ if: ${{ matrix.test_task == 'check' }}
- name: Create dummy files in build dir
run: |
./miniruby -e '(("a".."z").to_a+("A".."Z").to_a+("0".."9").to_a+%w[foo bar test zzz]).each{|basename|File.write("#{basename}.rb", "raise %(do not load #{basename}.rb)")}'
- if: matrix.test_task == 'check'
+ if: ${{ matrix.test_task == 'check' }}
- run: make $JOBS -s ${{ matrix.test_task }}
timeout-minutes: 30
env:
@@ -64,14 +65,14 @@ jobs:
payload: |
{
"ci": "GitHub Actions",
- "env": "${{ matrix.os }} / ${{ matrix.test_task }}${{ matrix.debug }}",
+ "env": "${{ matrix.os }} / ${{ matrix.test_task }}${{ matrix.configure }}",
"url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"commit": "${{ github.sha }}",
"branch": "${{ github.ref }}".split('/').reverse()[0]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: failure() && github.event_name == 'push'
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml
index ef2c003..66b2992 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -4,18 +4,34 @@ jobs:
make:
strategy:
matrix:
- test_task: [check] # to make job names consistent
- os: [windows-2019]
- vs: [2019]
+ include:
+ - vs: 2019
+ os: windows-2019
+ vcvars: '"C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat"'
+ # - vs: 2022
+ # os: windows-2022
+ # vcvars: '"C:\Program Files\Microsoft Visual Studio\2022\Preview\VC\Auxiliary\Build\vcvars64.bat"'
fail-fast: false
runs-on: ${{ matrix.os }}
+ name: VisualStudio ${{ matrix.vs }}
env:
GITPULLOPTIONS: --no-tags origin ${{github.ref}}
- VCVARS: C:\Program Files (x86)\Microsoft Visual Studio\${{ matrix.vs }}\Enterprise\VC\Auxiliary\Build\vcvars64.bat
+ VCVARS: ${{ matrix.vcvars }}
PATCH: C:\msys64\usr\bin\patch.exe
steps:
- run: md build
working-directory:
+ - uses: msys2/setup-msys2@v2
+ id: setup-msys2
+ with:
+ update: true
+ install: >-
+ patch
+ if: ${{ matrix.os != 'windows-2019' }}
+ - name: patch path
+ shell: msys2 {0}
+ run: echo PATCH=$(cygpath -wa $(command -v patch)) >> $GITHUB_ENV
+ if: ${{ steps.setup-msys2.outcome == 'success' }}
- uses: actions/cache@v2
with:
path: C:\vcpkg\downloads
@@ -49,50 +65,58 @@ jobs:
- uses: actions/checkout@v2
with:
path: src
+ - name: setup env
+ # %TEMP% is inconsistent with %TMP% and test-all expects they are consistent.
+ # https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302
+ run: |
+ set | C:\msys64\usr\bin\sort > old.env
+ call %VCVARS%
+ set TMP=%USERPROFILE%\AppData\Local\Temp
+ set TEMP=%USERPROFILE%\AppData\Local\Temp
+ set | C:\msys64\usr\bin\sort > new.env
+ C:\msys64\usr\bin\comm -13 old.env new.env >> %GITHUB_ENV%
+ del *.env
- name: Configure
run: |
- call "%VCVARS%"
- ../src/win32/configure.bat --disable-install-doc --without-ext=+,dbm,gdbm --enable-bundled-libffi --with-opt-dir=C:/vcpkg/installed/x64-windows --with-openssl-dir="C:/Program Files/OpenSSL-Win64"
+ ../src/win32/configure.bat --disable-install-doc --enable-bundled-libffi --with-opt-dir=C:/vcpkg/installed/x64-windows --with-openssl-dir="C:/Program Files/OpenSSL-Win64"
- name: nmake
run: |
- call "%VCVARS%"
- set YACC=win_bison
- echo on
+ echo ^#^#[group]incs
nmake incs
+ echo ^#^#[endgroup]
+ echo ^#^#[group]extract-extlibs
nmake extract-extlibs
+ echo ^#^#[endgroup]
nmake
+ env:
+ YACC: win_bison
- name: nmake test
timeout-minutes: 5
run: |
- call "%VCVARS%"
nmake test
- name: nmake test-all
timeout-minutes: 60
run: |
- call "%VCVARS%"
- ::- %TEMP% is inconsistent with %TMP% and test-all expects they are consistent.
- ::- https://github.com/actions/virtual-environments/issues/712#issuecomment-613004302
- set TMP=%USERPROFILE%\AppData\Local\Temp
- set TEMP=%USERPROFILE%\AppData\Local\Temp
- nmake test-all
+ nmake test-all TESTOPTS="-j%NUMBER_OF_PROCESSORS% --job-status=normal"
+ continue-on-error: ${{ matrix.continue-on-error || false }}
- name: nmake test-spec
timeout-minutes: 10
run: |
- call "%VCVARS%"
nmake test-spec
+ continue-on-error: ${{ matrix.continue-on-error || false }}
- uses: k0kubun/action-slack@v2.0.0
with:
payload: |
{
"ci": "GitHub Actions",
- "env": "${{ matrix.os }} / ${{ matrix.test_task }}",
+ "env": "VS${{ matrix.vs }} / ${{ matrix.test_task || 'check' }}",
"url": "https://github.com/${{ github.repository }}/actions/runs/${{ github.run_id }}",
"commit": "${{ github.sha }}",
"branch": "${{ github.ref }}".split('/').reverse()[0]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SIMPLER_ALERTS_URL }} # ruby-lang slack: ruby/simpler-alerts-bot
- if: failure() && github.event_name == 'push'
+ if: ${{ failure() && github.event_name == 'push' }}
defaults:
run:
diff --git a/.travis.yml b/.travis.yml
index ff0ce69..c84cb1a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -123,11 +123,13 @@ matrix:
- <<: *ppc64le-linux
- <<: *s390x-linux
allow_failures:
- # An arm64 job sometimes does not start right now.
- # https://travis-ci.community/t/11629
+ # The "TestReadline#test_interrupt_in_other_thread" started failing on arm32
+ # from https://www.travis-ci.com/github/ruby/ruby/jobs/529005145
- name: arm32-linux
- - name: arm64-linux
- # - name: ppc64le-linux
+ # - name: arm64-linux
+ # We see "Some worker was crashed." in about 40% of recent ppc64le-linux jobs
+ # e.g. https://app.travis-ci.com/github/ruby/ruby/jobs/530959548
+ - name: ppc64le-linux
# - name: s390x-linux
fast_finish: true
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index c112806..7363c10 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,5 +1,5 @@
Please see the [official issue tracker], [doc/contributing.rdoc] and wiki [HowToContribute].
[official issue tracker]: https://bugs.ruby-lang.org
-[doc/contributing.rdoc]: doc/contributing.rdoc
+[doc/contributing.rdoc]: contributing.rdoc
[HowToContribute]: https://bugs.ruby-lang.org/projects/ruby/wiki/HowToContribute
diff --git a/LEGAL b/LEGAL
index ecd1e16..5780450 100644
--- a/LEGAL
+++ b/LEGAL
@@ -343,6 +343,34 @@ mentioned below.
program. This Exception is an additional permission under section 7
of the GNU General Public License, version 3 ("GPLv3").
+[tool/lib/test/*]
+[tool/lib/core_assertions.rb]
+
+ Some of methods on these files are based on MiniTest 4. MiniTest 4 is
+ distributed under the MIT License.
+
+ >>>
+ Copyright (c) Ryan Davis, seattle.rb
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ 'Software'), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be
+ included in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+
[parse.c]
[parse.h]
@@ -440,7 +468,8 @@ mentioned below.
>>>
A C-program for MT19937, with initialization improved 2002/2/10.::
- Coded by Takuji Nishimura and Makoto Matsumoto.
+ Coded by Takuji Nishimura and Makoto Matsumoto.
+
This is a faster version by taking Shawn Cokus's optimization,
Matthe Bellew's simplification, Isaku Wada's real version.
@@ -532,10 +561,7 @@ mentioned below.
[missing/acosh.c]
[missing/alloca.c]
[missing/erf.c]
-[missing/finite.c]
[missing/hypot.c]
-[missing/isinf.c]
-[missing/isnan.c]
[missing/lgamma_r.c]
[missing/memcmp.c]
[missing/memmove.c]
diff --git a/NEWS.md b/NEWS.md
index d351a3d..4b77d66 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -14,6 +14,17 @@ Note that each entry is kept to a minimum, see links for details.
#=> [[3, 5], [5, 7], [11, 13]]
```
+* Pin operator now supports instance, class, and global variables.
+ [[Feature #17724]]
+
+ ```ruby
+ @n = 5
+ Prime.each_cons(2).lazy.find{_1 in [n, ^@n]}
+ #=> [3, 5]
+ ```
+
+* One-line pattern matching is no longer experimental.
+
* Multiple assignment evaluation order has been made consistent with
single assignment evaluation order. With single assignment, Ruby
uses a left-to-right evaluation order. With this code:
@@ -22,41 +33,54 @@ Note that each entry is kept to a minimum, see links for details.
foo[0] = bar
```
- The following evaluation order is used:
+ The following evaluation order is used:
- 1. `foo`
- 2. `bar`
- 3. `[]=` called on the result of `foo`
+ 1. `foo`
+ 2. `bar`
+ 3. `[]=` called on the result of `foo`
- In Ruby before 3.1.0, multiple assignment did not follow this
- evaluation order. With this code:
+ In Ruby before 3.1.0, multiple assignment did not follow this
+ evaluation order. With this code:
- ```ruby
- foo[0], bar.baz = a, b
- ```
+ ```ruby
+ foo[0], bar.baz = a, b
+ ```
+
+ Versions of Ruby before 3.1.0 would evaluate in the following
+ order
- Versions of Ruby before 3.1.0 would evaluate in the following
- order
+ 1. `a`
+ 2. `b`
+ 3. `foo`
+ 4. `[]=` called on the result of `foo`
+ 5. `bar`
+ 6. `baz=` called on the result of `bar`
- 1. `a`
- 2. `b`
- 3. `foo`
- 4. `[]=` called on the result of `foo`
- 5. `bar`
- 6. `baz=` called on the result of `bar`
+ Starting in Ruby 3.1.0, evaluation order is now consistent with
+ single assignment, with the left hand side being evaluated before
+ the right hand side:
- Starting in Ruby 3.1.0, evaluation order is now consistent with
- single assignment, with the left hand side being evaluated before
- the right hand side:
+ 1. `foo`
+ 2. `bar`
+ 3. `a`
+ 4. `b`
+ 5. `[]=` called on the result of `foo`
+ 6. `baz=` called on the result of `bar`
- 1. `foo`
- 2. `bar`
- 3. `a`
- 4. `b`
- 5. `[]=` called on the result of `foo`
- 6. `baz=` called on the result of `bar`
+ [[Bug #4443]]
- [[Bug #4443]]
+* Values in Hash literals and keyword arguments can be omitted.
+ [[Feature #14579]]
+
+ For example,
+
+ * `{x:, y:}` is a syntax sugar of `{x: x, y: y}`.
+ * `foo(x:, y:)` is a syntax sugar of `foo(x: x, y: y)`.
+
+ Constant names, local variable names, and method names are allowed as
+ key names. Note that a reserved word is considered as a local
+ variable or method name even if it's a pseudo variable name such as
+ `self`.
## Command line options
@@ -83,6 +107,16 @@ Outstanding ones only.
* File.dirname now accepts an optional argument for the level to
strip path components. [[Feature #12194]]
+* Integer
+
+ * Integer.try_convert is added. [[Feature #15211]]
+
+* MatchData
+
+ * MatchData#match is added [[Feature #18172]]
+
+ * MatchData#match_length is added [[Feature #18172]]
+
* Module
* Module#prepend now modifies the ancestor chain if the receiver
@@ -96,6 +130,13 @@ Outstanding ones only.
You need to use a Hash literal to set a Hash to a first member.
[[Feature #16806]]
+ * StructClass#keyword_init? is added [[Feature #18008]]
+
+* String
+
+ * Update Unicode version to 13.0.0 [[Feature #17750]]
+ and Emoji version to 13.0 [[Feature #18029]]
+
* Queue
* Queue#initialize now accepts an Enumerable of initial values.
@@ -108,13 +149,28 @@ Outstanding ones only.
* Thread::Backtrace
* Thread::Backtrace.limit, which returns the value to limit backtrace
- length set by `--backtracse-limit` command line option, is added.
+ length set by `--backtrace-limit` command line option, is added.
[[Feature #17479]]
* $LOAD_PATH
* $LOAD_PATH.resolve_feature_path does not raise. [[Feature #16043]]
+* Fiber Scheduler
+
+ * Add support for `Addrinfo.getaddrinfo` using `address_resolve` hook.
+ [[Feature #17370]]
+
+ * Introduce non-blocking `Timeout.timeout` using `timeout_after` hook.
+ [[Feature #17470]]
+
+ * IO hooks `io_wait`, `io_read`, `io_write`, receive the original IO object
+ where possible. [[Bug #18003]]
+
+ * Make `Monitor` fiber-safe. [[Bug #17827]]
+
+ * Replace copy coroutine with pthread implementation. [[Feature #18015]]
+
## Stdlib updates
Outstanding ones only.
@@ -123,6 +179,11 @@ Outstanding ones only.
Excluding feature bug fixes.
+* `rb_io_wait_readable`, `rb_io_wait_writable` and `rb_wait_for_single_fd` are
+ deprecated in favour of `rb_io_maybe_wait_readable`,
+ `rb_io_maybe_wait_writable` and `rb_io_maybe_wait` respectively.
+ `rb_thread_wait_fd` and `rb_thread_fd_writable` are deprecated. [[Bug #18003]]
+
## Stdlib compatibility issues
* `ERB#initialize` warns `safe_level` and later arguments even without -w.
@@ -136,9 +197,15 @@ Excluding feature bug fixes.
* The default `--jit-max-cache` is changed from 100 to 10000.
+* JIT-ed code is no longer cancelled when a TracePoint for class events
+ is enabled.
+
* The JIT compiler no longer skips compilation of methods longer than
1000 instructions.
+* `--jit-verbose` and `--jit-warning` output "JIT cancel" when JIT-ed
+ code is disabled because TracePoint or GC.compact is used.
+
* `RubyVM::MJIT` is renamed to `RubyVM::JIT`. [[Feature #17490]]
## Static analysis
@@ -154,19 +221,36 @@ Excluding feature bug fixes.
Just by `Kernel#p`, you can investigate where an object was created.
Note that just requiring this file brings a large performance overhead.
This is only for debugging purpose. Do not use this in production.
- [Feature #17762]
+ [[Feature #17762]]
+
+* Now exceptions raised in finalizers will be printed to `STDERR`, unless
+ `$VERBOSE` is `nil`. [[Feature #17798]]
-[Bug #4443]: https://bugs.ruby-lang.org/issues/4443
+[Bug #4443]: https://bugs.ruby-lang.org/issues/4443
[Feature #12194]: https://bugs.ruby-lang.org/issues/12194
[Feature #14256]: https://bugs.ruby-lang.org/issues/14256
+[Feature #14579]: https://bugs.ruby-lang.org/issues/14579
[Feature #15198]: https://bugs.ruby-lang.org/issues/15198
+[Feature #15211]: https://bugs.ruby-lang.org/issues/15211
[Feature #16043]: https://bugs.ruby-lang.org/issues/16043
[Feature #16806]: https://bugs.ruby-lang.org/issues/16806
[Feature #17312]: https://bugs.ruby-lang.org/issues/17312
[Feature #17327]: https://bugs.ruby-lang.org/issues/17327
[Feature #17411]: https://bugs.ruby-lang.org/issues/17411
-[Bug #17423]: https://bugs.ruby-lang.org/issues/17423
+[Bug #17423]: https://bugs.ruby-lang.org/issues/17423
[Feature #17479]: https://bugs.ruby-lang.org/issues/17479
[Feature #17490]: https://bugs.ruby-lang.org/issues/17490
+[Feature #17724]: https://bugs.ruby-lang.org/issues/17724
[Feature #17744]: https://bugs.ruby-lang.org/issues/17744
[Feature #17762]: https://bugs.ruby-lang.org/issues/17762
+[Feature #17798]: https://bugs.ruby-lang.org/issues/17798
+[Bug #18003]: https://bugs.ruby-lang.org/issues/18003
+[Feature #17370]: https://bugs.ruby-lang.org/issues/17370
+[Feature #17470]: https://bugs.ruby-lang.org/issues/17470
+[Feature #17750]: https://bugs.ruby-lang.org/issues/17750
+[Feature #17853]: https://bugs.ruby-lang.org/issues/17853
+[Bug #17827]: https://bugs.ruby-lang.org/issues/17827
+[Feature #18008]: https://bugs.ruby-lang.org/issues/18008
+[Feature #18015]: https://bugs.ruby-lang.org/issues/18015
+[Feature #18029]: https://bugs.ruby-lang.org/issues/18029
+[Feature #18172]: https://bugs.ruby-lang.org/issues/18172
diff --git a/README.ja.md b/README.ja.md
index 095c8fd..4516c71 100644
--- a/README.ja.md
+++ b/README.ja.md
@@ -167,11 +167,14 @@ UNIXであれば `configure` がほとんどの差異を吸収してくれるは
## フィードバック
-Rubyに関する質問は Ruby-Talk(英語)や Ruby-List(日本語) (https://www.ruby-lang.org/ja/community/mailing-lists) や,
-stackoverflow (https://ja.stackoverflow.com/) などのWebサイトに投稿してください.
+Rubyに関する質問は [Ruby-Talk](英語)や [Ruby-List](日本語)や,
+[stackoverflow] などのWebサイトに投稿してください.
バグ報告は https://bugs.ruby-lang.org で受け付けています.
+[Ruby-Talk]: https://www.ruby-lang.org/en/community/mailing-lists
+[Ruby-List]: https://www.ruby-lang.org/ja/community/mailing-lists
+[stackoverflow]: https://ja.stackoverflow.com/
## 著者
diff --git a/README.md b/README.md
index 4fe3b65..77a94c1 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
[![Actions Status: Ubuntu](https://github.com/ruby/ruby/workflows/Ubuntu/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Ubuntu")
[![Actions Status: Windows](https://github.com/ruby/ruby/workflows/Windows/badge.svg)](https://github.com/ruby/ruby/actions?query=workflow%3A"Windows")
[![AppVeyor status](https://ci.appveyor.com/api/projects/status/0sy8rrxut4o0k960/branch/master?svg=true)](https://ci.appveyor.com/project/ruby/ruby/branch/master)
-[![Travis Status](https://www.travis-ci.com/ruby/ruby.svg?branch=master)](https://www.travis-ci.com/ruby/ruby)
+[![Travis Status](https://app.travis-ci.com/ruby/ruby.svg?branch=master)](https://app.travis-ci.com/ruby/ruby)
# What's Ruby
@@ -167,12 +167,12 @@ See the file [COPYING](COPYING).
## Feedback
-Questions about the Ruby language can be asked on the Ruby-Talk mailing list
-(https://www.ruby-lang.org/en/community/mailing-lists) or on websites like
-(https://stackoverflow.com).
+Questions about the Ruby language can be asked on the [Ruby-Talk] mailing list
+or on websites like https://stackoverflow.com.
Bugs should be reported at https://bugs.ruby-lang.org. Read [HowToReport] for more information.
+[Ruby-Talk]: https://www.ruby-lang.org/en/community/mailing-lists
[HowToReport]: https://bugs.ruby-lang.org/projects/ruby/wiki/HowToReport
## Contributing
diff --git a/addr2line.c b/addr2line.c
index cf0a379..4d7b579 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -192,12 +192,12 @@ struct debug_section_definition {
static char binary_filename[PATH_MAX + 1];
static unsigned long
-uleb128(char **p)
+uleb128(const char **p)
{
unsigned long r = 0;
int s = 0;
for (;;) {
- unsigned char b = *(unsigned char *)(*p)++;
+ unsigned char b = (unsigned char)*(*p)++;
if (b < 0x80) {
r += (unsigned long)b << s;
break;
@@ -209,12 +209,12 @@ uleb128(char **p)
}
static long
-sleb128(char **p)
+sleb128(const char **p)
{
long r = 0;
int s = 0;
for (;;) {
- unsigned char b = *(unsigned char *)(*p)++;
+ unsigned char b = (unsigned char)*(*p)++;
if (b < 0x80) {
if (b & 0x40) {
r -= (0x80 - b) << s;
@@ -231,7 +231,7 @@ sleb128(char **p)
}
static const char *
-get_nth_dirname(unsigned long dir, char *p)
+get_nth_dirname(unsigned long dir, const char *p)
{
if (!dir--) {
return "";
@@ -249,11 +249,11 @@ get_nth_dirname(unsigned long dir, char *p)
}
static void
-fill_filename(int file, char *include_directories, char *filenames, line_info_t *line, obj_info_t *obj)
+fill_filename(int file, const char *include_directories, const char *filenames, line_info_t *line, obj_info_t *obj)
{
int i;
- char *p = filenames;
- char *filename;
+ const char *p = filenames;
+ const char *filename;
unsigned long dir;
for (i = 1; i <= file; i++) {
filename = p;
@@ -280,7 +280,7 @@ fill_filename(int file, char *include_directories, char *filenames, line_info_t
static void
fill_line(int num_traces, void **traces, uintptr_t addr, int file, int line,
- char *include_directories, char *filenames,
+ const char *include_directories, const char *filenames,
obj_info_t *obj, line_info_t *lines, int offset)
{
int i;
@@ -374,7 +374,7 @@ parse_debug_line_header(const char **pp, struct LineNumberProgramHeader *header)
}
static int
-parse_debug_line_cu(int num_traces, void **traces, char **debug_line,
+parse_debug_line_cu(int num_traces, void **traces, const char **debug_line,
obj_info_t *obj, line_info_t *lines, int offset)
{
const char *p = (const char *)*debug_line;
@@ -399,8 +399,8 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line,
#define FILL_LINE() \
do { \
fill_line(num_traces, traces, addr, file, line, \
- (char *)header.include_directories, \
- (char *)header.filenames, \
+ header.include_directories, \
+ header.filenames, \
obj, lines, offset); \
/*basic_block = prologue_end = epilogue_begin = 0;*/ \
} while (0)
@@ -413,19 +413,19 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line,
FILL_LINE();
break;
case DW_LNS_advance_pc:
- a = uleb128((char **)&p) * header.minimum_instruction_length;
+ a = uleb128(&p) * header.minimum_instruction_length;
addr += a;
break;
case DW_LNS_advance_line: {
- long a = sleb128((char **)&p);
+ long a = sleb128(&p);
line += a;
break;
}
case DW_LNS_set_file:
- file = (unsigned int)uleb128((char **)&p);
+ file = (unsigned int)uleb128(&p);
break;
case DW_LNS_set_column:
- /*column = (unsigned int)*/(void)uleb128((char **)&p);
+ /*column = (unsigned int)*/(void)uleb128(&p);
break;
case DW_LNS_negate_stmt:
is_stmt = !is_stmt;
@@ -450,10 +450,10 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line,
/* epilogue_begin = 1; */
break;
case DW_LNS_set_isa:
- /* isa = (unsigned int)*/(void)uleb128((char **)&p);
+ /* isa = (unsigned int)*/(void)uleb128(&p);
break;
case 0:
- a = uleb128((char **)&p);
+ a = uleb128(&p);
op = *p++;
switch (op) {
case DW_LNE_end_sequence:
@@ -477,7 +477,7 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line,
break;
case DW_LNE_set_discriminator:
/* TODO:currently ignore */
- uleb128((char **)&p);
+ uleb128(&p);
break;
default:
kprintf("Unknown extended opcode: %d in %s\n",
@@ -500,10 +500,10 @@ parse_debug_line_cu(int num_traces, void **traces, char **debug_line,
static int
parse_debug_line(int num_traces, void **traces,
- char *debug_line, unsigned long size,
+ const char *debug_line, unsigned long size,
obj_info_t *obj, line_info_t *lines, int offset)
{
- char *debug_line_end = debug_line + size;
+ const char *debug_line_end = debug_line + size;
while (debug_line < debug_line_end) {
if (parse_debug_line_cu(num_traces, traces, &debug_line, obj, lines, offset))
return -1;
@@ -833,21 +833,21 @@ enum {
# define ABBREV_TABLE_SIZE 256
typedef struct {
obj_info_t *obj;
- char *file;
- char *current_cu;
+ const char *file;
+ const char *current_cu;
uint64_t current_low_pc;
- char *debug_line_cu_end;
- char *debug_line_files;
- char *debug_line_directories;
- char *p;
- char *cu_end;
- char *pend;
- char *q0;
- char *q;
+ const char *debug_line_cu_end;
+ const char *debug_line_files;
+ const char *debug_line_directories;
+ const char *p;
+ const char *cu_end;
+ const char *pend;
+ const char *q0;
+ const char *q;
int format; // 4 or 8
uint8_t address_size;
int level;
- char *abbrev_table[ABBREV_TABLE_SIZE];
+ const char *abbrev_table[ABBREV_TABLE_SIZE];
} DebugInfoReader;
typedef struct {
@@ -858,7 +858,7 @@ typedef struct {
typedef struct {
union {
- char *ptr;
+ const char *ptr;
uint64_t uint64;
int64_t int64;
} as;
@@ -891,39 +891,39 @@ get_uint64(const uint8_t *p)
}
static uint8_t
-read_uint8(char **ptr)
+read_uint8(const char **ptr)
{
- const unsigned char *p = (const unsigned char *)*ptr;
- *ptr = (char *)(p + 1);
- return *p;
+ const char *p = *ptr;
+ *ptr = (p + 1);
+ return (uint8_t)*p;
}
static uint16_t
-read_uint16(char **ptr)
+read_uint16(const char **ptr)
{
- const unsigned char *p = (const unsigned char *)*ptr;
- *ptr = (char *)(p + 2);
- return get_uint16(p);
+ const char *p = *ptr;
+ *ptr = (p + 2);
+ return get_uint16((const uint8_t *)p);
}
static uint32_t
-read_uint24(char **ptr)
+read_uint24(const char **ptr)
{
- const unsigned char *p = (const unsigned char *)*ptr;
- *ptr = (char *)(p + 3);
- return (*p << 16) | get_uint16(p+1);
+ const char *p = *ptr;
+ *ptr = (p + 3);
+ return ((uint8_t)*p << 16) | get_uint16((const uint8_t *)p+1);
}
static uint32_t
-read_uint32(char **ptr)
+read_uint32(const char **ptr)
{
- const unsigned char *p = (const unsigned char *)*ptr;
- *ptr = (char *)(p + 4);
- return get_uint32(p);
+ const char *p = *ptr;
+ *ptr = (p + 4);
+ return get_uint32((const uint8_t *)p);
}
static uint64_t
-read_uint64(char **ptr)
+read_uint64(const char **ptr)
{
const unsigned char *p = (const unsigned char *)*ptr;
*ptr = (char *)(p + 8);
@@ -931,7 +931,7 @@ read_uint64(char **ptr)
}
static uintptr_t
-read_uintptr(char **ptr)
+read_uintptr(const char **ptr)
{
const unsigned char *p = (const unsigned char *)*ptr;
*ptr = (char *)(p + SIZEOF_VOIDP);
@@ -976,7 +976,7 @@ debug_info_reader_init(DebugInfoReader *reader, obj_info_t *obj)
}
static void
-di_skip_die_attributes(char **p)
+di_skip_die_attributes(const char **p)
{
for (;;) {
uint64_t at = uleb128(p);
@@ -996,7 +996,7 @@ static void
di_read_debug_abbrev_cu(DebugInfoReader *reader)
{
uint64_t prev = 0;
- char *p = reader->q0;
+ const char *p = reader->q0;
for (;;) {
uint64_t abbrev_number = uleb128(&p);
if (abbrev_number <= prev) break;
@@ -1042,7 +1042,7 @@ set_int_value(DebugInfoValue *v, int64_t n)
}
static void
-set_cstr_value(DebugInfoValue *v, char *s)
+set_cstr_value(DebugInfoValue *v, const char *s)
{
v->as.ptr = s;
v->off = 0;
@@ -1050,7 +1050,7 @@ set_cstr_value(DebugInfoValue *v, char *s)
}
static void
-set_cstrp_value(DebugInfoValue *v, char *s, uint64_t off)
+set_cstrp_value(DebugInfoValue *v, const char *s, uint64_t off)
{
v->as.ptr = s;
v->off = off;
@@ -1058,7 +1058,7 @@ set_cstrp_value(DebugInfoValue *v, char *s, uint64_t off)
}
static void
-set_data_value(DebugInfoValue *v, char *s)
+set_data_value(DebugInfoValue *v, const char *s)
{
v->as.ptr = s;
v->type = VAL_data;
@@ -1138,12 +1138,12 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
set_uint_value(v, read_uleb128(reader));
break;
case DW_FORM_ref_addr:
- if (reader->address_size == 4) {
+ if (reader->format == 4) {
set_uint_value(v, read_uint32(&reader->p));
- } else if (reader->address_size == 8) {
+ } else if (reader->format == 8) {
set_uint_value(v, read_uint64(&reader->p));
} else {
- fprintf(stderr,"unknown address_size:%d", reader->address_size);
+ fprintf(stderr,"unknown format:%d", reader->format);
abort();
}
break;
@@ -1259,10 +1259,10 @@ debug_info_reader_read_value(DebugInfoReader *reader, uint64_t form, DebugInfoVa
}
/* find abbrev in current compilation unit */
-static char *
+static const char *
di_find_abbrev(DebugInfoReader *reader, uint64_t abbrev_number)
{
- char *p;
+ const char *p;
if (abbrev_number < ABBREV_TABLE_SIZE) {
return reader->abbrev_table[abbrev_number];
}
@@ -1313,10 +1313,10 @@ div_inspect(DebugInfoValue *v)
{
switch (v->type) {
case VAL_uint:
- fprintf(stderr,"%d: type:%d size:%zx v:%lx\n",__LINE__,v->type,v->size,v->as.uint64);
+ fprintf(stderr,"%d: type:%d size:%zx v:%"PRIx64"\n",__LINE__,v->type,v->size,v->as.uint64);
break;
case VAL_int:
- fprintf(stderr,"%d: type:%d size:%zx v:%ld\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
+ fprintf(stderr,"%d: type:%d size:%zx v:%"PRId64"\n",__LINE__,v->type,v->size,(int64_t)v->as.uint64);
break;
case VAL_cstr:
fprintf(stderr,"%d: type:%d size:%zx v:'%s'\n",__LINE__,v->type,v->size,v->as.ptr);
@@ -1407,9 +1407,9 @@ ranges_set(ranges_t *ptr, DebugInfoValue *v)
}
static uint64_t
-read_dw_form_addr(DebugInfoReader *reader, char **ptr)
+read_dw_form_addr(DebugInfoReader *reader, const char **ptr)
{
- char *p = *ptr;
+ const char *p = *ptr;
*ptr = p + reader->format;
if (reader->format == 4) {
return read_uint32(&p);
@@ -1434,7 +1434,7 @@ ranges_include(DebugInfoReader *reader, ranges_t *ptr, uint64_t addr)
}
else if (ptr->ranges_set) {
/* TODO: support base address selection entry */
- char *p;
+ const char *p;
uint64_t base = ptr->low_pc_set ? ptr->low_pc : reader->current_low_pc;
if (reader->obj->debug_rnglists.ptr) {
p = reader->obj->debug_rnglists.ptr + ptr->ranges;
@@ -1593,14 +1593,31 @@ di_read_cu(DebugInfoReader *reader)
}
static void
-read_abstract_origin(DebugInfoReader *reader, uint64_t abstract_origin, line_info_t *line)
+read_abstract_origin(DebugInfoReader *reader, uint64_t form, uint64_t abstract_origin, line_info_t *line)
{
- char *p = reader->p;
- char *q = reader->q;
+ const char *p = reader->p;
+ const char *q = reader->q;
int level = reader->level;
DIE die;
- reader->p = reader->current_cu + abstract_origin;
+ switch (form) {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ reader->p = reader->current_cu + abstract_origin;
+ break;
+ case DW_FORM_ref_addr:
+ goto finish; /* not supported yet */
+ case DW_FORM_ref_sig8:
+ goto finish; /* not supported yet */
+ case DW_FORM_ref_sup4:
+ case DW_FORM_ref_sup8:
+ goto finish; /* not supported yet */
+ default:
+ goto finish;
+ }
if (!di_read_die(reader, &die)) goto finish;
/* enumerate abbrev */
@@ -1665,7 +1682,7 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
/* 1 or 3 */
break; /* goto skip_die; */
case DW_AT_abstract_origin:
- read_abstract_origin(reader, v.as.uint64, &line);
+ read_abstract_origin(reader, v.form, v.as.uint64, &line);
break; /* goto skip_die; */
}
}
@@ -1699,6 +1716,7 @@ debug_info_read(DebugInfoReader *reader, int num_traces, void **traces,
static unsigned long
uncompress_debug_section(ElfW(Shdr) *shdr, char *file, char **ptr)
{
+ *ptr = NULL;
#ifdef SUPPORT_COMPRESSED_DEBUG_LINE
ElfW(Chdr) *chdr = (ElfW(Chdr) *)(file + shdr->sh_offset);
unsigned long destsize = chdr->ch_size;
@@ -1719,6 +1737,7 @@ uncompress_debug_section(ElfW(Shdr) *shdr, char *file, char **ptr)
fail:
free(*ptr);
+ *ptr = NULL;
#endif
return 0;
}
@@ -2168,7 +2187,7 @@ fail:
#endif
#define HAVE_MAIN_EXE_PATH
-#if defined(__FreeBSD__)
+#if defined(__FreeBSD__) || defined(__DragonFly__)
# include <sys/sysctl.h>
#endif
/* ssize_t main_exe_path(void)
@@ -2191,7 +2210,7 @@ main_exe_path(void)
binary_filename[len] = 0;
return len;
}
-#elif defined(__FreeBSD__)
+#elif defined(__FreeBSD__) || defined(__DragonFly__)
static ssize_t
main_exe_path(void)
{
diff --git a/appveyor.yml b/appveyor.yml
index 351b7c7..0c984b9 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -48,7 +48,7 @@ for:
- echo>> Makefile RT_VER=0
- echo>> Makefile BUILTIN_ENCOBJS=nul
- type win32\Makefile.sub >> Makefile
- - nmake %mflags% up
+ - nmake %mflags% up VCSUP="echo Update OK"
- nmake %mflags% extract-extlibs
- del Makefile
- mkdir \usr\local\bin
diff --git a/array.c b/array.c
index a1e0c13..63d63aa 100644
--- a/array.c
+++ b/array.c
@@ -2234,14 +2234,6 @@ rb_ary_set_len(VALUE ary, long len)
ARY_SET_LEN(ary, len);
}
-/*!
- * expands or shrinks \a ary to \a len elements.
- * expanded region will be filled with Qnil.
- * \param ary an array
- * \param len new size
- * \return \a ary
- * \post the size of \a ary is \a len.
- */
VALUE
rb_ary_resize(VALUE ary, long len)
{
@@ -2668,9 +2660,7 @@ rb_ary_length(VALUE ary)
static VALUE
rb_ary_empty_p(VALUE ary)
{
- if (RARRAY_LEN(ary) == 0)
- return Qtrue;
- return Qfalse;
+ return RBOOL(RARRAY_LEN(ary) == 0);
}
VALUE
@@ -3432,89 +3422,8 @@ static VALUE rb_ary_bsearch_index(VALUE ary);
* array.bsearch -> new_enumerator
*
* Returns an element from +self+ selected by a binary search.
- * +self+ should be sorted, but this is not checked.
- *
- * By using binary search, finds a value from this array which meets
- * the given condition in <tt>O(log n)</tt> where +n+ is the size of the array.
- *
- * There are two search modes:
- * - <b>Find-minimum mode</b>: the block should return +true+ or +false+.
- * - <b>Find-any mode</b>: the block should return a numeric value.
- *
- * The block should not mix the modes by and sometimes returning +true+ or +false+
- * and sometimes returning a numeric value, but this is not checked.
- *
- * <b>Find-Minimum Mode</b>
*
- * In find-minimum mode, the block always returns +true+ or +false+.
- * The further requirement (though not checked) is that
- * there are no indexes +i+ and +j+ such that:
- * - <tt>0 <= i < j <= self.size</tt>.
- * - The block returns +true+ for <tt>self[i]</tt> and +false+ for <tt>self[j]</tt>.
- *
- * In find-minimum mode, method bsearch returns the first element for which the block returns true.
- *
- * Examples:
- * a = [0, 4, 7, 10, 12]
- * a.bsearch {|x| x >= 4 } # => 4
- * a.bsearch {|x| x >= 6 } # => 7
- * a.bsearch {|x| x >= -1 } # => 0
- * a.bsearch {|x| x >= 100 } # => nil
- *
- * Less formally: the block is such that all +false+-evaluating elements
- * precede all +true+-evaluating elements.
- *
- * These make sense as blocks in find-minimum mode:
- * a = [0, 4, 7, 10, 12]
- * a.map {|x| x >= 4 } # => [false, true, true, true, true]
- * a.map {|x| x >= 6 } # => [false, false, true, true, true]
- * a.map {|x| x >= -1 } # => [true, true, true, true, true]
- * a.map {|x| x >= 100 } # => [false, false, false, false, false]
- *
- * This would not make sense:
- * a = [0, 4, 7, 10, 12]
- * a.map {|x| x == 7 } # => [false, false, true, false, false]
- *
- * <b>Find-Any Mode</b>
- *
- * In find-any mode, the block always returns a numeric value.
- * The further requirement (though not checked) is that
- * there are no indexes +i+ and +j+ such that:
- * - <tt>0 <= i < j <= self.size</tt>.
- * - The block returns a negative value for <tt>self[i]</tt>
- * and a positive value for <tt>self[j]</tt>.
- * - The block returns a negative value for <tt>self[i]</tt> and zero <tt>self[j]</tt>.
- * - The block returns zero for <tt>self[i]</tt> and a positive value for <tt>self[j]</tt>.
- *
- * In find-any mode, method bsearch returns some element
- * for which the block returns zero, or +nil+ if no such element is found.
- *
- * Examples:
- * a = [0, 4, 7, 10, 12]
- * a.bsearch {|element| 7 <=> element } # => 7
- * a.bsearch {|element| -1 <=> element } # => nil
- * a.bsearch {|element| 5 <=> element } # => nil
- * a.bsearch {|element| 15 <=> element } # => nil
- *
- * Less formally: the block is such that:
- * - All positive-evaluating elements precede all zero-evaluating elements.
- * - All positive-evaluating elements precede all negative-evaluating elements.
- * - All zero-evaluating elements precede all negative-evaluating elements.
- *
- * These make sense as blocks in find-any mode:
- * a = [0, 4, 7, 10, 12]
- * a.map {|element| 7 <=> element } # => [1, 1, 0, -1, -1]
- * a.map {|element| -1 <=> element } # => [-1, -1, -1, -1, -1]
- * a.map {|element| 5 <=> element } # => [1, 1, -1, -1, -1]
- * a.map {|element| 15 <=> element } # => [1, 1, 1, 1, 1]
- *
- * This would not make sense:
- * a = [0, 4, 7, 10, 12]
- * a.map {|element| element <=> 7 } # => [-1, -1, 0, 1, 1]
- *
- * Returns an enumerator if no block given:
- * a = [0, 4, 7, 10, 12]
- * a.bsearch # => #<Enumerator: [0, 4, 7, 10, 12]:bsearch>
+ * See {Binary Searching}[rdoc-ref:bsearch.rdoc].
*/
static VALUE
@@ -4098,7 +4007,7 @@ ary_slice_bang_by_rb_ary_splice(VALUE ary, long pos, long len)
else if (orig_len < pos) {
return Qnil;
}
- else if (orig_len < pos + len) {
+ if (orig_len < pos + len) {
len = orig_len - pos;
}
if (len == 0) {
@@ -4847,6 +4756,7 @@ ary_append(VALUE x, VALUE y)
if (n > 0) {
rb_ary_splice(x, RARRAY_LEN(x), 0, RARRAY_CONST_PTR_TRANSIENT(y), n);
}
+ RB_GC_GUARD(y);
return x;
}
@@ -5923,8 +5833,7 @@ ary_min_opt_string(VALUE ary, long i, VALUE vmin)
*
* With an argument +n+ and a block, returns a new \Array with at most +n+ elements,
* in ascending order per the block:
- * [0, 1, 2, 3].min(3) # => [0, 1, 2]
- * [0, 1, 2, 3].min(6) # => [0, 1, 2, 3]
+ * ['0', '00', '000'].min(2) {|a, b| a.size <=> b.size } # => ["0", "00"]
*/
static VALUE
rb_ary_min(int argc, VALUE *argv, VALUE ary)
@@ -7719,7 +7628,7 @@ rb_ary_one_p(int argc, VALUE *argv, VALUE ary)
* Finds and returns the object in nested objects
* that is specified by +index+ and +identifiers+.
* The nested objects may be instances of various classes.
- * See {Dig Methods}[rdoc-ref:doc/dig_methods.rdoc].
+ * See {Dig Methods}[rdoc-ref:dig_methods.rdoc].
*
* Examples:
* a = [:foo, [:bar, :baz, [:bat, :bam]]]
@@ -7813,7 +7722,7 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
n = 0;
}
}
- else if (RB_TYPE_P(e, T_BIGNUM))
+ else if (RB_BIGNUM_TYPE_P(e))
v = rb_big_plus(e, v);
else if (RB_TYPE_P(e, T_RATIONAL)) {
if (r == Qundef)
@@ -7850,7 +7759,7 @@ rb_ary_sum(int argc, VALUE *argv, VALUE ary)
x = RFLOAT_VALUE(e);
else if (FIXNUM_P(e))
x = FIX2LONG(e);
- else if (RB_TYPE_P(e, T_BIGNUM))
+ else if (RB_BIGNUM_TYPE_P(e))
x = rb_big2dbl(e);
else if (RB_TYPE_P(e, T_RATIONAL))
x = rb_num2dbl(e);
@@ -8160,8 +8069,11 @@ rb_ary_deconstruct(VALUE ary)
*
* == What's Here
*
- * First, what's elsewhere. \Array includes the module Enumerable,
- * which provides dozens of additional methods.
+ * First, what's elsewhere. \Class \Array:
+ *
+ * - Inherits from {class Object}[Object.html#class-Object-label-What-27s+Here].
+ * - Includes {module Enumerable}[Enumerable.html#module-Enumerable-label-What-27s+Here],
+ * which provides dozens of additional methods.
*
* Here, class \Array provides methods that are useful for:
*
@@ -8381,7 +8293,7 @@ Init_Array(void)
rb_define_method(rb_cArray, "each_index", rb_ary_each_index, 0);
rb_define_method(rb_cArray, "reverse_each", rb_ary_reverse_each, 0);
rb_define_method(rb_cArray, "length", rb_ary_length, 0);
- rb_define_alias(rb_cArray, "size", "length");
+ rb_define_method(rb_cArray, "size", rb_ary_length, 0);
rb_define_method(rb_cArray, "empty?", rb_ary_empty_p, 0);
rb_define_method(rb_cArray, "find_index", rb_ary_index, -1);
rb_define_method(rb_cArray, "index", rb_ary_index, -1);
diff --git a/ast.c b/ast.c
index 3945a32..202527f 100644
--- a/ast.c
+++ b/ast.c
@@ -64,8 +64,8 @@ ast_new_internal(rb_ast_t *ast, const NODE *node)
return obj;
}
-static VALUE rb_ast_parse_str(VALUE str, VALUE save_script_lines);
-static VALUE rb_ast_parse_file(VALUE path, VALUE save_script_lines);
+static VALUE rb_ast_parse_str(VALUE str, VALUE keep_script_lines);
+static VALUE rb_ast_parse_file(VALUE path, VALUE keep_script_lines);
static VALUE
ast_parse_new(void)
@@ -85,31 +85,31 @@ ast_parse_done(rb_ast_t *ast)
}
static VALUE
-ast_s_parse(rb_execution_context_t *ec, VALUE module, VALUE str, VALUE save_script_lines)
+ast_s_parse(rb_execution_context_t *ec, VALUE module, VALUE str, VALUE keep_script_lines)
{
- return rb_ast_parse_str(str, save_script_lines);
+ return rb_ast_parse_str(str, keep_script_lines);
}
static VALUE
-rb_ast_parse_str(VALUE str, VALUE save_script_lines)
+rb_ast_parse_str(VALUE str, VALUE keep_script_lines)
{
rb_ast_t *ast = 0;
StringValue(str);
VALUE vparser = ast_parse_new();
- if (RTEST(save_script_lines)) rb_parser_save_script_lines(vparser);
+ if (RTEST(keep_script_lines)) rb_parser_keep_script_lines(vparser);
ast = rb_parser_compile_string_path(vparser, Qnil, str, 1);
return ast_parse_done(ast);
}
static VALUE
-ast_s_parse_file(rb_execution_context_t *ec, VALUE module, VALUE path, VALUE save_script_lines)
+ast_s_parse_file(rb_execution_context_t *ec, VALUE module, VALUE path, VALUE keep_script_lines)
{
- return rb_ast_parse_file(path, save_script_lines);
+ return rb_ast_parse_file(path, keep_script_lines);
}
static VALUE
-rb_ast_parse_file(VALUE path, VALUE save_script_lines)
+rb_ast_parse_file(VALUE path, VALUE keep_script_lines)
{
VALUE f;
rb_ast_t *ast = 0;
@@ -119,7 +119,7 @@ rb_ast_parse_file(VALUE path, VALUE save_script_lines)
f = rb_file_open_str(path, "r");
rb_funcall(f, rb_intern("set_encoding"), 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
VALUE vparser = ast_parse_new();
- if (RTEST(save_script_lines)) rb_parser_save_script_lines(vparser);
+ if (RTEST(keep_script_lines)) rb_parser_keep_script_lines(vparser);
ast = rb_parser_compile_file_path(vparser, Qnil, f, 1);
rb_io_close(f);
return ast_parse_done(ast);
@@ -139,13 +139,13 @@ lex_array(VALUE array, int index)
}
static VALUE
-rb_ast_parse_array(VALUE array, VALUE save_script_lines)
+rb_ast_parse_array(VALUE array, VALUE keep_script_lines)
{
rb_ast_t *ast = 0;
array = rb_check_array_type(array);
VALUE vparser = ast_parse_new();
- if (RTEST(save_script_lines)) rb_parser_save_script_lines(vparser);
+ if (RTEST(keep_script_lines)) rb_parser_keep_script_lines(vparser);
ast = rb_parser_compile_generic(vparser, lex_array, Qnil, array, 1);
return ast_parse_done(ast);
}
@@ -193,7 +193,7 @@ script_lines(VALUE path)
}
static VALUE
-ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE save_script_lines)
+ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE keep_script_lines)
{
VALUE path, node, lines;
int node_id;
@@ -213,18 +213,21 @@ ast_s_of(rb_execution_context_t *ec, VALUE module, VALUE body, VALUE save_script
else {
iseq = rb_method_iseq(body);
}
+ if (rb_iseq_from_eval_p(iseq)) {
+ rb_raise(rb_eArgError, "cannot get AST for method defined in eval");
+ }
path = rb_iseq_path(iseq);
node_id = iseq->body->location.node_id;
}
if (!NIL_P(lines = script_lines(path))) {
- node = rb_ast_parse_array(lines, save_script_lines);
+ node = rb_ast_parse_array(lines, keep_script_lines);
}
else if (RSTRING_LEN(path) == 2 && memcmp(RSTRING_PTR(path), "-e", 2) == 0) {
- node = rb_ast_parse_str(rb_e_script, save_script_lines);
+ node = rb_ast_parse_str(rb_e_script, keep_script_lines);
}
else {
- node = rb_ast_parse_file(path, save_script_lines);
+ node = rb_ast_parse_file(path, keep_script_lines);
}
return node_find(node, node_id);
@@ -254,16 +257,14 @@ ast_node_type(rb_execution_context_t *ec, VALUE self)
return rb_sym_intern_ascii_cstr(node_type_to_str(data->node));
}
-#ifdef DEBUG_ISEQ_NODE_ID
static VALUE
-ast_node_node_id(VALUE self)
+ast_node_node_id(rb_execution_context_t *ec, VALUE self)
{
struct ASTNodeData *data;
TypedData_Get_Struct(self, struct ASTNodeData, &rb_node_type, data);
return INT2FIX(nd_node_id(data->node));
}
-#endif
#define NEW_CHILD(ast, node) node ? ast_new_internal(ast, node) : Qnil
@@ -365,7 +366,7 @@ node_children(rb_ast_t *ast, const NODE *node)
case NODE_WHILE:
case NODE_UNTIL:
return rb_ary_push(rb_ary_new_from_node_args(ast, 2, node->nd_cond, node->nd_body),
- (node->nd_state ? Qtrue : Qfalse));
+ RBOOL(node->nd_state));
case NODE_ITER:
case NODE_FOR:
return rb_ary_new_from_node_args(ast, 2, node->nd_iter, node->nd_body);
@@ -432,7 +433,7 @@ node_children(rb_ast_t *ast, const NODE *node)
NEW_CHILD(ast, node->nd_args->nd_body));
case NODE_OP_ASGN2:
return rb_ary_new_from_args(5, NEW_CHILD(ast, node->nd_recv),
- node->nd_next->nd_aid ? Qtrue : Qfalse,
+ RBOOL(node->nd_next->nd_aid),
ID2SYM(node->nd_next->nd_vid),
ID2SYM(node->nd_next->nd_mid),
NEW_CHILD(ast, node->nd_value));
@@ -725,7 +726,4 @@ Init_ast(void)
rb_mAST = rb_define_module_under(rb_cRubyVM, "AbstractSyntaxTree");
rb_cNode = rb_define_class_under(rb_mAST, "Node", rb_cObject);
rb_undef_alloc_func(rb_cNode);
-#ifdef DEBUG_ISEQ_NODE_ID
- rb_define_method(rb_cNode, "node_id", ast_node_node_id, 0);
-#endif
}
diff --git a/ast.rb b/ast.rb
index ce99f53..f866bd2 100644
--- a/ast.rb
+++ b/ast.rb
@@ -29,8 +29,8 @@ module RubyVM::AbstractSyntaxTree
#
# RubyVM::AbstractSyntaxTree.parse("x = 1 + 2")
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-1:9>
- def self.parse string, save_script_lines: false
- Primitive.ast_s_parse string, save_script_lines
+ def self.parse string, keep_script_lines: false
+ Primitive.ast_s_parse string, keep_script_lines
end
# call-seq:
@@ -44,8 +44,8 @@ module RubyVM::AbstractSyntaxTree
#
# RubyVM::AbstractSyntaxTree.parse_file("my-app/app.rb")
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-31:3>
- def self.parse_file pathname, save_script_lines: false
- Primitive.ast_s_parse_file pathname, save_script_lines
+ def self.parse_file pathname, keep_script_lines: false
+ Primitive.ast_s_parse_file pathname, keep_script_lines
end
# call-seq:
@@ -63,8 +63,8 @@ module RubyVM::AbstractSyntaxTree
#
# RubyVM::AbstractSyntaxTree.of(method(:hello))
# # => #<RubyVM::AbstractSyntaxTree::Node:SCOPE@1:0-3:3>
- def self.of body, save_script_lines: false
- Primitive.ast_s_of body, save_script_lines
+ def self.of body, keep_script_lines: false
+ Primitive.ast_s_of body, keep_script_lines
end
# RubyVM::AbstractSyntaxTree::Node instances are created by parse methods in
@@ -141,6 +141,17 @@ module RubyVM::AbstractSyntaxTree
end
# call-seq:
+ # node.node_id -> integer
+ #
+ # Returns an internal node_id number.
+ # Note that this is an API for ruby internal use, debugging,
+ # and research. Do not use this for any other purpose.
+ # The compatibility is not guaranteed.
+ def node_id
+ Primitive.ast_node_node_id
+ end
+
+ # call-seq:
# node.script_lines -> array
#
# Returns the original source code as an array of lines.
diff --git a/benchmark/attr_accessor.yml b/benchmark/attr_accessor.yml
new file mode 100644
index 0000000..82134cd
--- /dev/null
+++ b/benchmark/attr_accessor.yml
@@ -0,0 +1,29 @@
+prelude: |
+ class C
+ attr_accessor :x
+ def initialize
+ @x = nil
+ end
+ class_eval <<-END
+ def ar
+ #{'x;'*256}
+ end
+ def aw
+ #{'self.x = nil;'*256}
+ end
+ def arm
+ m = method(:x)
+ #{'m.call;'*256}
+ end
+ def awm
+ m = method(:x=)
+ #{'m.call(nil);'*256}
+ end
+ END
+ end
+ obj = C.new
+benchmark:
+ attr_reader: "obj.ar"
+ attr_writer: "obj.aw"
+ attr_reader_method: "obj.arm"
+ attr_writer_method: "obj.awm"
diff --git a/benchmark/time_new.yml b/benchmark/time_new.yml
new file mode 100644
index 0000000..5947dd3
--- /dev/null
+++ b/benchmark/time_new.yml
@@ -0,0 +1,4 @@
+benchmark:
+ - 'Time.new(2021)'
+ - 'Time.new(2021, 8, 22)'
+ - 'Time.new(2021, 8, 22, in: "+09:00")'
diff --git a/benchmark/time_parse.yml b/benchmark/time_parse.yml
new file mode 100644
index 0000000..a6d6948
--- /dev/null
+++ b/benchmark/time_parse.yml
@@ -0,0 +1,8 @@
+prelude: |
+ require 'time'
+ inspect = "2021-08-23 09:57:02 +0900"
+ iso8601 = "2021-08-23T09:57:02+09:00"
+benchmark:
+ - Time.iso8601(iso8601)
+ - Time.parse(iso8601)
+ - Time.parse(inspect)
diff --git a/benchmark/vm_cvar.yml b/benchmark/vm_cvar.yml
new file mode 100644
index 0000000..1d0e161
--- /dev/null
+++ b/benchmark/vm_cvar.yml
@@ -0,0 +1,20 @@
+prelude: |
+ class A
+ @@foo = 1
+
+ def self.foo
+ @@foo
+ end
+
+ ("A".."Z").each do |module_name|
+ eval <<-EOM
+ module #{module_name}
+ end
+
+ include #{module_name}
+ EOM
+ end
+ end
+benchmark:
+ vm_cvar: A.foo
+loop_count: 600000
diff --git a/benchmark/vm_thread_condvar1.rb b/benchmark/vm_thread_condvar1.rb
index cf5706b..feed27c 100644
--- a/benchmark/vm_thread_condvar1.rb
+++ b/benchmark/vm_thread_condvar1.rb
@@ -1,9 +1,9 @@
# two threads, two mutex, two condvar ping-pong
require 'thread'
-m1 = Mutex.new
-m2 = Mutex.new
-cv1 = ConditionVariable.new
-cv2 = ConditionVariable.new
+m1 = Thread::Mutex.new
+m2 = Thread::Mutex.new
+cv1 = Thread::ConditionVariable.new
+cv2 = Thread::ConditionVariable.new
max = 100000
i = 0
wait = nil
diff --git a/benchmark/vm_thread_condvar2.rb b/benchmark/vm_thread_condvar2.rb
index 7c8dc19..6590c41 100644
--- a/benchmark/vm_thread_condvar2.rb
+++ b/benchmark/vm_thread_condvar2.rb
@@ -1,16 +1,16 @@
# many threads, one mutex, many condvars
require 'thread'
-m = Mutex.new
-cv1 = ConditionVariable.new
-cv2 = ConditionVariable.new
+m = Thread::Mutex.new
+cv1 = Thread::ConditionVariable.new
+cv2 = Thread::ConditionVariable.new
max = 1000
n = 100
waiting = 0
scvs = []
waiters = n.times.map do |i|
- start_cv = ConditionVariable.new
+ start_cv = Thread::ConditionVariable.new
scvs << start_cv
- start_mtx = Mutex.new
+ start_mtx = Thread::Mutex.new
start_mtx.synchronize do
th = Thread.new(start_mtx, start_cv) do |sm, scv|
m.synchronize do
diff --git a/bignum.c b/bignum.c
index d3e6cf2..7adf55d 100644
--- a/bignum.c
+++ b/bignum.c
@@ -36,15 +36,12 @@
#include "internal/numeric.h"
#include "internal/object.h"
#include "internal/sanitizers.h"
-#include "internal/util.h"
#include "internal/variable.h"
#include "internal/warnings.h"
#include "ruby/thread.h"
#include "ruby/util.h"
#include "ruby_assert.h"
-#define RB_BIGNUM_TYPE_P(x) RB_TYPE_P((x), T_BIGNUM)
-
const char ruby_digitmap[] = "0123456789abcdefghijklmnopqrstuvwxyz";
#ifndef SIZEOF_BDIGIT_DBL
@@ -463,7 +460,6 @@ static int
bary_2comp(BDIGIT *ds, size_t n)
{
size_t i;
- i = 0;
for (i = 0; i < n; i++) {
if (ds[i] != 0) {
goto non_zero;
@@ -1053,6 +1049,7 @@ integer_unpack_num_bdigits(size_t numwords, size_t wordsize, size_t nails, int *
size_t num_bdigits1 = integer_unpack_num_bdigits_generic(numwords, wordsize, nails, &nlp_bits1);
assert(num_bdigits == num_bdigits1);
assert(*nlp_bits_ret == nlp_bits1);
+ (void)num_bdigits1;
}
#endif
}
@@ -3401,6 +3398,7 @@ rb_absint_numwords(VALUE val, size_t word_numbits, size_t *nlz_bits_ret)
numwords0 = absint_numwords_generic(numbytes, nlz_bits_in_msbyte, word_numbits, &nlz_bits0);
assert(numwords0 == numwords);
assert(nlz_bits0 == nlz_bits);
+ (void)numwords0;
}
#endif
}
@@ -5381,7 +5379,7 @@ rb_integer_float_eq(VALUE x, VALUE y)
double yd = RFLOAT_VALUE(y);
double yi, yf;
- if (isnan(yd) || isinf(yd))
+ if (!isfinite(yd))
return Qfalse;
yf = modf(yd, &yi);
if (yf != 0)
@@ -5389,18 +5387,14 @@ rb_integer_float_eq(VALUE x, VALUE y)
if (FIXNUM_P(x)) {
#if SIZEOF_LONG * CHAR_BIT < DBL_MANT_DIG /* assume FLT_RADIX == 2 */
double xd = (double)FIX2LONG(x);
- if (xd != yd)
- return Qfalse;
- return Qtrue;
+ return RBOOL(xd == yd);
#else
long xn, yn;
if (yi < LONG_MIN || LONG_MAX_as_double <= yi)
return Qfalse;
xn = FIX2LONG(x);
yn = (long)yi;
- if (xn != yn)
- return Qfalse;
- return Qtrue;
+ return RBOOL(xn == yn);
#endif
}
y = rb_dbl2big(yi);
@@ -5470,10 +5464,10 @@ big_op(VALUE x, VALUE y, enum big_op_t op)
n = FIX2INT(rel);
switch (op) {
- case big_op_gt: return n > 0 ? Qtrue : Qfalse;
- case big_op_ge: return n >= 0 ? Qtrue : Qfalse;
- case big_op_lt: return n < 0 ? Qtrue : Qfalse;
- case big_op_le: return n <= 0 ? Qtrue : Qfalse;
+ case big_op_gt: return RBOOL(n > 0);
+ case big_op_ge: return RBOOL(n >= 0);
+ case big_op_lt: return RBOOL(n < 0);
+ case big_op_le: return RBOOL(n <= 0);
}
return Qundef;
}
@@ -5517,7 +5511,7 @@ VALUE
rb_big_eq(VALUE x, VALUE y)
{
if (FIXNUM_P(y)) {
- return bignorm(x) == y ? Qtrue : Qfalse;
+ return RBOOL(bignorm(x) == y);
}
else if (RB_BIGNUM_TYPE_P(y)) {
}
@@ -5529,8 +5523,7 @@ rb_big_eq(VALUE x, VALUE y)
}
if (BIGNUM_SIGN(x) != BIGNUM_SIGN(y)) return Qfalse;
if (BIGNUM_LEN(x) != BIGNUM_LEN(y)) return Qfalse;
- if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,BIGNUM_LEN(y)) != 0) return Qfalse;
- return Qtrue;
+ return RBOOL(MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,BIGNUM_LEN(y)) == 0);
}
VALUE
@@ -5539,8 +5532,7 @@ rb_big_eql(VALUE x, VALUE y)
if (!RB_BIGNUM_TYPE_P(y)) return Qfalse;
if (BIGNUM_SIGN(x) != BIGNUM_SIGN(y)) return Qfalse;
if (BIGNUM_LEN(x) != BIGNUM_LEN(y)) return Qfalse;
- if (MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,BIGNUM_LEN(y)) != 0) return Qfalse;
- return Qtrue;
+ return RBOOL(MEMCMP(BDIGITS(x),BDIGITS(y),BDIGIT,BIGNUM_LEN(y)) == 0);
}
VALUE
@@ -6823,10 +6815,7 @@ rb_big_bit_length(VALUE big)
VALUE
rb_big_odd_p(VALUE num)
{
- if (BIGNUM_LEN(num) != 0 && BDIGITS(num)[0] & 1) {
- return Qtrue;
- }
- return Qfalse;
+ return RBOOL(BIGNUM_LEN(num) != 0 && BDIGITS(num)[0] & 1);
}
VALUE
diff --git a/bootstraptest/test_fiber.rb b/bootstraptest/test_fiber.rb
index 35e1bf6..2614dd1 100644
--- a/bootstraptest/test_fiber.rb
+++ b/bootstraptest/test_fiber.rb
@@ -19,12 +19,12 @@ assert_equal %q{ok}, %q{
}
assert_equal %q{ok}, %q{
- 10_000.times.collect{Fiber.new{}}
+ 100.times.collect{Fiber.new{}}
:ok
}
assert_equal %q{ok}, %q{
- fibers = 100.times.collect{Fiber.new{Fiber.yield}}
+ fibers = 1000.times.collect{Fiber.new{Fiber.yield}}
fibers.each(&:resume)
fibers.each(&:resume)
:ok
diff --git a/bootstraptest/test_insns.rb b/bootstraptest/test_insns.rb
index 9052cad..31fdc29 100644
--- a/bootstraptest/test_insns.rb
+++ b/bootstraptest/test_insns.rb
@@ -384,7 +384,7 @@ tests = [
[ 'opt_empty_p', %q{ ''.empty? }, ],
[ 'opt_empty_p', %q{ [].empty? }, ],
[ 'opt_empty_p', %q{ {}.empty? }, ],
- [ 'opt_empty_p', %q{ Queue.new.empty? }, ],
+ [ 'opt_empty_p', %q{ Thread::Queue.new.empty? }, ],
[ 'opt_succ', %q{ 1.succ == 2 }, ],
if defined? $FIXNUM_MAX then
diff --git a/bootstraptest/test_ractor.rb b/bootstraptest/test_ractor.rb
index 7e77dfc..01d02dc 100644
--- a/bootstraptest/test_ractor.rb
+++ b/bootstraptest/test_ractor.rb
@@ -533,7 +533,7 @@ assert_equal '[RuntimeError, "ok", true]', %q{
# threads in a ractor will killed
assert_equal '{:ok=>3}', %q{
Ractor.new Ractor.current do |main|
- q = Queue.new
+ q = Thread::Queue.new
Thread.new do
q << true
loop{}
@@ -1405,4 +1405,32 @@ assert_equal "ok", %q{
end
}
+assert_equal "ok", %q{
+ GC.disable
+ Ractor.new {}
+ raise "not ok" unless GC.disable
+
+ foo = []
+ 10.times { foo << 1 }
+
+ GC.start
+
+ 'ok'
+}
+
+# Can yield back values while GC is sweeping [Bug #18117]
+assert_equal "ok", %q{
+ workers = (0...8).map do
+ Ractor.new do
+ loop do
+ 10_000.times.map { Object.new }
+ Ractor.yield Time.now
+ end
+ end
+ end
+
+ 1_000.times { idle_worker, tmp_reporter = Ractor.select(*workers) }
+ "ok"
+}
+
end # if !ENV['GITHUB_WORKFLOW']
diff --git a/class.c b/class.c
index 9ac2b3f..d2dd438 100644
--- a/class.c
+++ b/class.c
@@ -10,16 +10,7 @@
**********************************************************************/
/*!
- * \defgroup class Classes and their hierarchy.
- * \par Terminology
- * - class: same as in Ruby.
- * - singleton class: class for a particular object
- * - eigenclass: = singleton class
- * - metaclass: class of a class. metaclass is a kind of singleton class.
- * - metametaclass: class of a metaclass.
- * - meta^(n)-class: class of a meta^(n-1)-class.
- * - attached object: A singleton class knows its unique instance.
- * The instance is called the attached object for the singleton class.
+ * \addtogroup class
* \{
*/
@@ -27,6 +18,7 @@
#include <ctype.h>
#include "constant.h"
+#include "debug_counter.h"
#include "id_table.h"
#include "internal.h"
#include "internal/class.h"
@@ -43,6 +35,8 @@
#define METACLASS_OF(k) RBASIC(k)->klass
#define SET_METACLASS_OF(k, cls) RBASIC_SET_CLASS(k, cls)
+RUBY_EXTERN rb_serial_t ruby_vm_global_cvar_state;
+
void
rb_class_subclass_add(VALUE super, VALUE klass)
{
@@ -86,14 +80,14 @@ rb_module_add_to_subclasses_list(VALUE module, VALUE iclass)
void
rb_class_remove_from_super_subclasses(VALUE klass)
{
- rb_subclass_entry_t *entry;
+ rb_subclass_entry_t **prev = RCLASS_PARENT_SUBCLASSES(klass);
- if (RCLASS_PARENT_SUBCLASSES(klass)) {
- entry = *RCLASS_PARENT_SUBCLASSES(klass);
+ if (prev) {
+ rb_subclass_entry_t *entry = *prev, *next = entry->next;
- *RCLASS_PARENT_SUBCLASSES(klass) = entry->next;
- if (entry->next) {
- RCLASS_PARENT_SUBCLASSES(entry->next->klass) = RCLASS_PARENT_SUBCLASSES(klass);
+ *prev = next;
+ if (next) {
+ RCLASS_PARENT_SUBCLASSES(next->klass) = prev;
}
xfree(entry);
}
@@ -104,14 +98,14 @@ rb_class_remove_from_super_subclasses(VALUE klass)
void
rb_class_remove_from_module_subclasses(VALUE klass)
{
- rb_subclass_entry_t *entry;
+ rb_subclass_entry_t **prev = RCLASS_MODULE_SUBCLASSES(klass);
- if (RCLASS_MODULE_SUBCLASSES(klass)) {
- entry = *RCLASS_MODULE_SUBCLASSES(klass);
- *RCLASS_MODULE_SUBCLASSES(klass) = entry->next;
+ if (prev) {
+ rb_subclass_entry_t *entry = *prev, *next = entry->next;
- if (entry->next) {
- RCLASS_MODULE_SUBCLASSES(entry->next->klass) = RCLASS_MODULE_SUBCLASSES(klass);
+ *prev = next;
+ if (next) {
+ RCLASS_MODULE_SUBCLASSES(next->klass) = prev;
}
xfree(entry);
@@ -182,8 +176,7 @@ class_alloc(VALUE flags, VALUE klass)
RVARGC_NEWOBJ_OF(obj, struct RClass, klass, (flags & T_MASK) | FL_PROMOTED1 /* start from age == 2 */ | (RGENGC_WB_PROTECTED_CLASS ? FL_WB_PROTECTED : 0), payload_size);
#if USE_RVARGC
- obj->ptr = (rb_classext_t *)rb_rvargc_payload_data_ptr((VALUE)obj + rb_slot_size());
- RB_OBJ_WRITTEN(obj, Qundef, (VALUE)obj + rb_slot_size());
+ obj->ptr = (rb_classext_t *)rb_gc_rvargc_object_data((VALUE)obj);
#else
obj->ptr = ZALLOC(rb_classext_t);
#endif
@@ -232,13 +225,6 @@ rb_class_boot(VALUE super)
return (VALUE)klass;
}
-
-/*!
- * Ensures a class can be derived from super.
- *
- * \param super a reference to an object.
- * \exception TypeError if \a super is not a Class or \a super is a singleton class.
- */
void
rb_check_inheritable(VALUE super)
{
@@ -254,13 +240,6 @@ rb_check_inheritable(VALUE super)
}
}
-
-/*!
- * Creates a new class.
- * \param super a class from which the new class derives.
- * \exception TypeError \a super is not inheritable.
- * \exception TypeError \a super is the Class class.
- */
VALUE
rb_class_new(VALUE super)
{
@@ -534,10 +513,6 @@ rb_singleton_class_clone_and_attach(VALUE obj, VALUE attach)
}
}
-/*!
- * Attach a object to a singleton class.
- * @pre \a klass is the singleton class of \a obj.
- */
void
rb_singleton_class_attached(VALUE klass, VALUE obj)
{
@@ -695,17 +670,6 @@ rb_make_metaclass(VALUE obj, VALUE unused)
}
}
-
-/*!
- * Defines a new class.
- * \param id ignored
- * \param super A class from which the new class will derive. NULL means \c Object class.
- * \return the created class
- * \throw TypeError if super is not a \c Class object.
- *
- * \note the returned class will not be associated with \a id.
- * You must explicitly set a class name if necessary.
- */
VALUE
rb_define_class_id(ID id, VALUE super)
{
@@ -736,23 +700,6 @@ rb_class_inherited(VALUE super, VALUE klass)
return rb_funcall(super, inherited, 1, klass);
}
-
-
-/*!
- * Defines a top-level class.
- * \param name name of the class
- * \param super a class from which the new class will derive.
- * \return the created class
- * \throw TypeError if the constant name \a name is already taken but
- * the constant is not a \c Class.
- * \throw TypeError if the class is already defined but the class can not
- * be reopened because its superclass is not \a super.
- * \throw ArgumentError if the \a super is NULL.
- * \post top-level constant named \a name refers the returned class.
- *
- * \note if a class named \a name is already defined and its superclass is
- * \a super, the function just returns the defined class.
- */
VALUE
rb_define_class(const char *name, VALUE super)
{
@@ -785,48 +732,12 @@ rb_define_class(const char *name, VALUE super)
return klass;
}
-
-/*!
- * Defines a class under the namespace of \a outer.
- * \param outer a class which contains the new class.
- * \param name name of the new class
- * \param super a class from which the new class will derive.
- * NULL means \c Object class.
- * \return the created class
- * \throw TypeError if the constant name \a name is already taken but
- * the constant is not a \c Class.
- * \throw TypeError if the class is already defined but the class can not
- * be reopened because its superclass is not \a super.
- * \post top-level constant named \a name refers the returned class.
- *
- * \note if a class named \a name is already defined and its superclass is
- * \a super, the function just returns the defined class.
- * \note the compaction GC does not move classes returned by this function.
- */
VALUE
rb_define_class_under(VALUE outer, const char *name, VALUE super)
{
return rb_define_class_id_under(outer, rb_intern(name), super);
}
-
-/*!
- * Defines a class under the namespace of \a outer.
- * \param outer a class which contains the new class.
- * \param id name of the new class
- * \param super a class from which the new class will derive.
- * NULL means \c Object class.
- * \return the created class
- * \throw TypeError if the constant name \a name is already taken but
- * the constant is not a \c Class.
- * \throw TypeError if the class is already defined but the class can not
- * be reopened because its superclass is not \a super.
- * \post top-level constant named \a name refers the returned class.
- *
- * \note if a class named \a name is already defined and its superclass is
- * \a super, the function just returns the defined class.
- * \note the compaction GC does not move classes returned by this function.
- */
VALUE
rb_define_class_id_under(VALUE outer, ID id, VALUE super)
{
@@ -878,9 +789,6 @@ rb_define_module_id(ID id)
return rb_module_new();
}
-/*!
- * \note the compaction GC does not move modules returned by this function.
- */
VALUE
rb_define_module(const char *name)
{
@@ -905,9 +813,6 @@ rb_define_module(const char *name)
return module;
}
-/*!
- * \note the compaction GC does not move modules returned by this function.
- */
VALUE
rb_define_module_under(VALUE outer, const char *name)
{
@@ -957,6 +862,7 @@ rb_include_class_new(VALUE module, VALUE super)
RCLASS_CONST_TBL(module) = rb_id_table_create(0);
}
RCLASS_IV_TBL(klass) = RCLASS_IV_TBL(module);
+ RCLASS_CVC_TBL(klass) = RCLASS_CVC_TBL(module);
RCLASS_CONST_TBL(klass) = RCLASS_CONST_TBL(module);
RCLASS_SET_SUPER(klass, super);
@@ -1085,6 +991,8 @@ do_include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super
VALUE super_class = RCLASS_SUPER(c);
// invalidate inline method cache
+ RB_DEBUG_COUNTER_INC(cvar_include_invalidate);
+ ruby_vm_global_cvar_state++;
tbl = RCLASS_M_TBL(module);
if (tbl && rb_id_table_size(tbl)) {
if (search_super) { // include
@@ -1118,10 +1026,10 @@ do_include_modules_at(const VALUE klass, VALUE c, VALUE module, int search_super
add_subclass = FALSE;
}
- {
+ if (add_subclass) {
VALUE m = module;
if (BUILTIN_TYPE(m) == T_ICLASS) m = RBASIC(m)->klass;
- if (add_subclass) rb_module_add_to_subclasses_list(m, iclass);
+ rb_module_add_to_subclasses_list(m, iclass);
}
if (FL_TEST(klass, RMODULE_IS_REFINEMENT)) {
@@ -1341,8 +1249,13 @@ VALUE
rb_mod_ancestors(VALUE mod)
{
VALUE p, ary = rb_ary_new();
+ VALUE refined_class = Qnil;
+ if (FL_TEST(mod, RMODULE_IS_REFINEMENT)) {
+ refined_class = rb_refinement_module_get_refined_class(mod);
+ }
for (p = mod; p; p = RCLASS_SUPER(p)) {
+ if (p == refined_class) break;
if (p != RCLASS_ORIGIN(p)) continue;
if (BUILTIN_TYPE(p) == T_ICLASS) {
rb_ary_push(ary, RBASIC(p)->klass);
@@ -1425,6 +1338,7 @@ method_entry_i(ID key, VALUE value, void *data)
}
else {
type = METHOD_ENTRY_VISI(me);
+ RUBY_ASSERT(type != METHOD_VISI_UNDEF);
}
st_add_direct(arg->list, key, (st_data_t)type);
}
@@ -1724,56 +1638,7 @@ rb_obj_singleton_methods(int argc, const VALUE *argv, VALUE obj)
* \}
*/
/*!
- * \defgroup defmethod Defining methods
- * There are some APIs to define a method from C.
- * These API takes a C function as a method body.
- *
- * \par Method body functions
- * Method body functions must return a VALUE and
- * can be one of the following form:
- * <dl>
- * <dt>Fixed number of parameters</dt>
- * <dd>
- * This form is a normal C function, excepting it takes
- * a receiver object as the first argument.
- *
- * \code
- * static VALUE my_method(VALUE self, VALUE x, VALUE y);
- * \endcode
- * </dd>
- * <dt>argc and argv style</dt>
- * <dd>
- * This form takes three parameters: \a argc, \a argv and \a self.
- * \a self is the receiver. \a argc is the number of arguments.
- * \a argv is a pointer to an array of the arguments.
- *
- * \code
- * static VALUE my_method(int argc, VALUE *argv, VALUE self);
- * \endcode
- * </dd>
- * <dt>Ruby array style</dt>
- * <dd>
- * This form takes two parameters: self and args.
- * \a self is the receiver. \a args is an Array object which
- * contains the arguments.
- *
- * \code
- * static VALUE my_method(VALUE self, VALUE args);
- * \endcode
- * </dd>
- *
- * \par Number of parameters
- * Method defining APIs takes the number of parameters which the
- * method will takes. This number is called \a argc.
- * \a argc can be:
- * <dl>
- * <dt>zero or positive number</dt>
- * <dd>This means the method body function takes a fixed number of parameters</dd>
- * <dt>-1</dt>
- * <dd>This means the method body function is "argc and argv" style.</dd>
- * <dt>-2</dt>
- * <dd>This means the method body function is "self and args" style.</dd>
- * </dl>
+ * \addtogroup defmethod
* \{
*/
@@ -1943,23 +1808,6 @@ rb_singleton_class_get(VALUE obj)
return klass;
}
-/*!
- * Returns the singleton class of \a obj. Creates it if necessary.
- *
- * \param obj an arbitrary object.
- * \throw TypeError if \a obj is an Integer or a Symbol.
- * \return the singleton class.
- *
- * \post \a obj has its own singleton class.
- * \post if \a obj is a class,
- * the returned singleton class also has its own
- * singleton class in order to keep consistency of the
- * inheritance structure of metaclasses.
- * \note a new singleton class will be created
- * if \a obj does not have it.
- * \note the singleton classes for nil, true and false are:
- * NilClass, TrueClass and FalseClass.
- */
VALUE
rb_singleton_class(VALUE obj)
{
@@ -1983,13 +1831,6 @@ rb_singleton_class(VALUE obj)
#ifdef rb_define_singleton_method
#undef rb_define_singleton_method
#endif
-/*!
- * Defines a singleton method for \a obj.
- * \param obj an arbitrary object
- * \param name name of the singleton method
- * \param func the method body
- * \param argc the number of parameters, or -1 or -2. see \ref defmethod.
- */
void
rb_define_singleton_method(VALUE obj, const char *name, VALUE (*func)(ANYARGS), int argc)
{
@@ -1999,13 +1840,6 @@ rb_define_singleton_method(VALUE obj, const char *name, VALUE (*func)(ANYARGS),
#ifdef rb_define_module_function
#undef rb_define_module_function
#endif
-/*!
- * Defines a module function for \a module.
- * \param module an module or a class.
- * \param name name of the function
- * \param func the method body
- * \param argc the number of parameters, or -1 or -2. see \ref defmethod.
- */
void
rb_define_module_function(VALUE module, const char *name, VALUE (*func)(ANYARGS), int argc)
{
@@ -2016,38 +1850,18 @@ rb_define_module_function(VALUE module, const char *name, VALUE (*func)(ANYARGS)
#ifdef rb_define_global_function
#undef rb_define_global_function
#endif
-/*!
- * Defines a global function
- * \param name name of the function
- * \param func the method body
- * \param argc the number of parameters, or -1 or -2. see \ref defmethod.
- */
void
rb_define_global_function(const char *name, VALUE (*func)(ANYARGS), int argc)
{
rb_define_module_function(rb_mKernel, name, func, argc);
}
-
-/*!
- * Defines an alias of a method.
- * \param klass the class which the original method belongs to
- * \param name1 a new name for the method
- * \param name2 the original name of the method
- */
void
rb_define_alias(VALUE klass, const char *name1, const char *name2)
{
rb_alias(klass, rb_intern(name1), rb_intern(name2));
}
-/*!
- * Defines (a) public accessor method(s) for an attribute.
- * \param klass the class which the attribute will belongs to
- * \param name name of the attribute
- * \param read a getter method for the attribute will be defined if \a read is non-zero.
- * \param write a setter method for the attribute will be defined if \a write is non-zero.
- */
void
rb_define_attr(VALUE klass, const char *name, int read, int write)
{
@@ -2357,12 +2171,6 @@ rb_scan_args_kw(int kw_flag, int argc, const VALUE *argv, const char *fmt, ...)
return rb_scan_args_result(&arg, argc);
}
-int
-rb_class_has_methods(VALUE c)
-{
- return rb_id_table_size(RCLASS_M_TBL(c)) == 0 ? FALSE : TRUE;
-}
-
/*!
* \}
*/
diff --git a/common.mk b/common.mk
index 30380e0..33ba2ea 100644
--- a/common.mk
+++ b/common.mk
@@ -18,8 +18,8 @@ mflags = $(MFLAGS)
gnumake_recursive =
enable_shared = $(ENABLE_SHARED:no=)
-UNICODE_VERSION = 12.1.0
-UNICODE_EMOJI_VERSION = 12.1
+UNICODE_VERSION = 13.0.0
+UNICODE_EMOJI_VERSION = 13.1
UNICODE_BETA = NO
### set the following environment variable or uncomment the line if
@@ -164,7 +164,7 @@ EXPORTOBJS = $(DLNOBJ) \
OBJS = $(EXPORTOBJS) builtin.$(OBJEXT)
ALLOBJS = $(NORMALMAINOBJ) $(MINIOBJS) $(COMMONOBJS) $(INITOBJS)
-GOLFOBJS = goruby.$(OBJEXT) golf_prelude.$(OBJEXT)
+GOLFOBJS = goruby.$(OBJEXT)
DEFAULT_PRELUDES = $(GEM_PRELUDE)
PRELUDE_SCRIPTS = $(DEFAULT_PRELUDES)
@@ -213,7 +213,7 @@ MAKE_LINK = $(MINIRUBY) -rfileutils -e "include FileUtils::Verbose" \
all: $(SHOWFLAGS) main docs
-main: $(SHOWFLAGS) exts $(ENCSTATIC:static=lib)encs programs
+main: $(SHOWFLAGS) exts $(ENCSTATIC:static=lib)encs
@$(NULLCMD)
mjit-headers: $(MJIT_SUPPORT)-mjit-headers
@@ -326,7 +326,6 @@ $(GOLF): $(LIBRUBY) $(GOLFOBJS) PHONY
$(Q) $(MAKE) $(mflags) \
GOLF=_dummy_golf_target_to_avoid_conflict_just_in_case_ \
MAINOBJ=goruby.$(OBJEXT) \
- EXTOBJS="golf_prelude.$(OBJEXT) $(EXTOBJS)" \
PROGRAM=$(GORUBY)$(EXEEXT) \
V=$(V) \
program
@@ -472,7 +471,7 @@ what-where-nodoc: no-install-nodoc
no-install-nodoc: pre-no-install-nodoc dont-install-nodoc post-no-install-nodoc
pre-no-install-nodoc:: pre-no-install-local pre-no-install-ext
dont-install-nodoc: $(PREP)
- $(INSTRUBY) -n --make="$(MAKE)" $(INSTRUBY_ARGS)
+ $(INSTRUBY) -n --make="$(MAKE)" $(INSTRUBY_ARGS) --exclude=doc
post-no-install-nodoc:: post-no-install-local post-no-install-ext
what-where-local: no-install-local
@@ -742,7 +741,7 @@ check: main test test-tool test-all test-spec
if [ x"$(GIT)" != x ] && $(CHDIR) "$(srcdir)" && \
b=`$(GIT) symbolic-ref --short HEAD 2>&1` && \
u=`$(GIT) branch --list --format='%(upstream:short)' $$b`; then \
- set -x; $(GIT) --no-pager log --format=oneline -G "^ *# *include" $$u..HEAD --; \
+ set -x; $(GIT) --no-pager log --format=oneline -G '^ *# *include *("|<ruby)' $$u..HEAD --; \
fi
check-ruby: test test-ruby
@@ -761,35 +760,49 @@ $(arch)-fake.rb: $(srcdir)/template/fake.rb.in $(tooldir)/generic_erb.rb version
btest: $(TEST_RUNNABLE)-btest
no-btest: PHONY
yes-btest: fake miniruby$(EXEEXT) PHONY
+ $(ACTIONS_GROUP)
$(Q)$(exec) $(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(BTESTRUBY) $(RUN_OPTS)" $(OPTS) $(TESTOPTS) $(BTESTS)
+ $(ACTIONS_ENDGROUP)
btest-ruby: $(TEST_RUNNABLE)-btest-ruby
no-btest-ruby: PHONY
yes-btest-ruby: prog PHONY
+ $(ACTIONS_GROUP)
$(Q)$(exec) $(RUNRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(PROGRAM) -I$(srcdir)/lib $(RUN_OPTS)" -q $(OPTS) $(TESTOPTS) $(BTESTS)
+ $(ACTIONS_ENDGROUP)
rtest: fake miniruby$(EXEEXT) PHONY
+ $(ACTIONS_GROUP)
$(Q)$(exec) $(BOOTSTRAPRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(BTESTRUBY) $(RUN_OPTS)" --sets=ractor -v
+ $(ACTIONS_ENDGROUP)
test-basic: $(TEST_RUNNABLE)-test-basic
no-test-basic: PHONY
yes-test-basic: prog PHONY
+ $(ACTIONS_GROUP)
$(Q)$(exec) $(RUNRUBY) "$(srcdir)/basictest/runner.rb" --run-opt=$(RUN_OPTS) $(OPTS) $(TESTOPTS)
+ $(ACTIONS_ENDGROUP)
test-knownbugs: test-knownbug
test-knownbug: $(TEST_RUNNABLE)-test-knownbug
no-test-knownbug: PHONY
yes-test-knownbug: prog PHONY
+ $(ACTIONS_GROUP)
-$(exec) $(RUNRUBY) "$(srcdir)/bootstraptest/runner.rb" --ruby="$(PROGRAM) $(RUN_OPTS)" $(OPTS) $(TESTOPTS) $(srcdir)/KNOWNBUGS.rb
+ $(ACTIONS_ENDGROUP)
test-testframework: $(TEST_RUNNABLE)-test-testframework
yes-test-testframework: prog PHONY
- $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TOOL_TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TESTOPTS) testunit minitest
+ $(ACTIONS_GROUP)
+ $(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TOOL_TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TESTOPTS) testunit
+ $(ACTIONS_ENDGROUP)
no-test-testframework: PHONY
test-tool: $(TEST_RUNNABLE)-test-tool
yes-test-tool: prog PHONY
+ $(ACTIONS_GROUP)
$(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TOOL_TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TESTOPTS)
+ $(ACTIONS_ENDGROUP)
no-test-tool: PHONY
test-sample: test-basic # backward compatibility for mswin-build
@@ -800,7 +813,9 @@ test: test-short
# for example, make test-all TESTOPTS="-j2 -v -n test-name -- test-file-name"
test-all: $(TEST_RUNNABLE)-test-all
yes-test-all: programs PHONY
+ $(ACTIONS_GROUP)
$(gnumake_recursive)$(Q)$(exec) $(RUNRUBY) "$(TESTSDIR)/runner.rb" --ruby="$(RUNRUBY)" $(TEST_EXCLUDES) $(TESTOPTS) $(TESTS)
+ $(ACTIONS_ENDGROUP)
TESTS_BUILD = mkmf
no-test-all: PHONY
$(gnumake_recursive)$(MINIRUBY) -I"$(srcdir)/lib" "$(TESTSDIR)/runner.rb" $(TESTOPTS) $(TESTS_BUILD)
@@ -840,8 +855,10 @@ test-spec-precheck: programs
test-spec: $(TEST_RUNNABLE)-test-spec
yes-test-spec: test-spec-precheck
+ $(ACTIONS_GROUP)
$(gnumake_recursive)$(Q) \
- $(RUNRUBY) -r./$(arch)-fake $(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/default.mspec -I$(srcdir)/tool/lib $(MSPECOPT) $(SPECOPTS)
+ $(RUNRUBY) -r./$(arch)-fake $(srcdir)/spec/mspec/bin/mspec run -B $(srcdir)/spec/default.mspec $(MSPECOPT) $(SPECOPTS)
+ $(ACTIONS_ENDGROUP)
no-test-spec:
RUNNABLE = $(LIBRUBY_RELATIVE:no=un)-runnable
@@ -942,23 +959,28 @@ RUBY_H_INCLUDES = {$(VPATH)}ruby.h {$(VPATH)}config.h {$(VPATH)}defines.h \
acosh.$(OBJEXT): {$(VPATH)}acosh.c
alloca.$(OBJEXT): {$(VPATH)}alloca.c {$(VPATH)}config.h
+cbrt.$(OBJEXT): {$(VPATH)}cbrt.c
+close.$(OBJEXT): {$(VPATH)}close.c
crypt.$(OBJEXT): {$(VPATH)}crypt.c {$(VPATH)}crypt.h {$(VPATH)}missing/des_tables.c
-dup2.$(OBJEXT): {$(VPATH)}dup2.c
erf.$(OBJEXT): {$(VPATH)}erf.c
explicit_bzero.$(OBJEXT): {$(VPATH)}explicit_bzero.c
-finite.$(OBJEXT): {$(VPATH)}finite.c
+ffs.$(OBJEXT): {$(VPATH)}ffs.c
flock.$(OBJEXT): {$(VPATH)}flock.c
+hypot.$(OBJEXT): {$(VPATH)}hypot.c
+langinfo.$(OBJEXT): {$(VPATH)}langinfo.c
+lgamma_r.$(OBJEXT): {$(VPATH)}lgamma_r.c
memcmp.$(OBJEXT): {$(VPATH)}memcmp.c
memmove.$(OBJEXT): {$(VPATH)}memmove.c
-mkdir.$(OBJEXT): {$(VPATH)}mkdir.c
+nan.$(OBJEXT): {$(VPATH)}nan.c
+nextafter.$(OBJEXT): {$(VPATH)}nextafter.c
+procstat_vm.$(OBJEXT): {$(VPATH)}procstat_vm.c
setproctitle.$(OBJEXT): {$(VPATH)}setproctitle.c
strchr.$(OBJEXT): {$(VPATH)}strchr.c
-strdup.$(OBJEXT): {$(VPATH)}strdup.c
strerror.$(OBJEXT): {$(VPATH)}strerror.c
strlcat.$(OBJEXT): {$(VPATH)}strlcat.c
strlcpy.$(OBJEXT): {$(VPATH)}strlcpy.c
strstr.$(OBJEXT): {$(VPATH)}strstr.c
-nt.$(OBJEXT): {$(VPATH)}nt.c
+tgamma.$(OBJEXT): {$(VPATH)}tgamma.c
.coroutine_obj $(COROUTINE_OBJ): \
{$(VPATH)}$(COROUTINE_SRC) \
@@ -1338,7 +1360,7 @@ update-bundled_gems: PHONY
$(Q) $(RUNRUBY) -rrubygems \
$(tooldir)/update-bundled_gems.rb \
"$(srcdir)/gems/bundled_gems" | \
- "$(IFCHANGE)" "$(srcdir)/gems/bundled_gems" -
+ $(IFCHANGE) "$(srcdir)/gems/bundled_gems" -
git -C "$(srcdir)" diff --no-ext-diff --ignore-submodules --exit-code || \
git -C "$(srcdir)" commit -m "Update bundled_gems" gems/bundled_gems
@@ -1353,8 +1375,10 @@ test-bundled-gems-prepare: test-bundled-gems-precheck test-bundled-gems-fetch
test-bundled-gems-prepare: $(TEST_RUNNABLE)-test-bundled-gems-prepare
no-test-bundled-gems-prepare: no-test-bundled-gems-precheck
yes-test-bundled-gems-prepare: yes-test-bundled-gems-precheck
+ $(ACTIONS_GROUP)
$(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
- --install-dir .bundle --conservative "bundler" "minitest:~> 5" "test-unit" "rake" "hoe" "yard" "pry" "packnga" "rexml" "json-schema" "rbs"
+ --install-dir .bundle --conservative "bundler" "minitest:~> 5" "test-unit" "rake" "hoe" "yard" "pry" "packnga" "rexml" "json-schema"
+ $(ACTIONS_ENDGROUP)
PREPARE_BUNDLED_GEMS = test-bundled-gems-prepare
test-bundled-gems: $(TEST_RUNNABLE)-test-bundled-gems
@@ -1374,8 +1398,10 @@ yes-test-bundler-precheck: main
no-test-bundler-prepare: no-test-bundler-precheck
yes-test-bundler-prepare: yes-test-bundler-precheck
+ $(ACTIONS_GROUP)
$(XRUBY) -C "$(srcdir)" bin/gem install --no-document \
--install-dir .bundle --conservative "rspec:~> 3.8" "rake:~> 13.0" "parallel_tests:~> 2.29"
+ $(ACTIONS_ENDGROUP)
RSPECOPTS =
BUNDLER_SPECS =
@@ -1426,16 +1452,19 @@ UNICODE_AUXILIARY_FILES = \
$(UNICODE_SRC_DATA_DIR)/auxiliary/GraphemeBreakTest.txt \
$(empty)
+UNICODE_UCD_EMOJI_FILES = \
+ $(UNICODE_SRC_DATA_DIR)/emoji/emoji-data.txt \
+ $(UNICODE_SRC_DATA_DIR)/emoji/emoji-variation-sequences.txt \
+ $(empty)
+
UNICODE_EMOJI_FILES = \
- $(UNICODE_SRC_EMOJI_DATA_DIR)/emoji-data.txt \
$(UNICODE_SRC_EMOJI_DATA_DIR)/emoji-sequences.txt \
$(UNICODE_SRC_EMOJI_DATA_DIR)/emoji-test.txt \
- $(UNICODE_SRC_EMOJI_DATA_DIR)/emoji-variation-sequences.txt \
$(UNICODE_SRC_EMOJI_DATA_DIR)/emoji-zwj-sequences.txt \
$(empty)
update-unicode: $(UNICODE_FILES) $(UNICODE_PROPERTY_FILES) \
- $(UNICODE_AUXILIARY_FILES) $(UNICODE_EMOJI_FILES)
+ $(UNICODE_AUXILIARY_FILES) $(UNICODE_UCD_EMOJI_FILES) $(UNICODE_EMOJI_FILES)
CACHE_DIR = $(srcdir)/.downloaded-cache
UNICODE_DOWNLOAD = \
@@ -1452,6 +1481,13 @@ UNICODE_AUXILIARY_DOWNLOAD = \
-d $(UNICODE_SRC_DATA_DIR)/auxiliary \
-p $(UNICODE_VERSION)/ucd/auxiliary \
-e $(ALWAYS_UPDATE_UNICODE:yes=-a) unicode
+UNICODE_UCD_EMOJI_DOWNLOAD = \
+ $(BASERUBY) $(tooldir)/downloader.rb \
+ --cache-dir=$(CACHE_DIR) \
+ --unicode-beta $(UNICODE_BETA) \
+ -d $(UNICODE_SRC_DATA_DIR)/emoji \
+ -p $(UNICODE_VERSION)/ucd/emoji \
+ -e $(ALWAYS_UPDATE_UNICODE:yes=-a) unicode
UNICODE_EMOJI_DOWNLOAD = \
$(BASERUBY) $(tooldir)/downloader.rb \
--cache-dir=$(CACHE_DIR) \
@@ -1472,6 +1508,12 @@ update-unicode-auxiliary-files:
$(Q) $(MAKEDIRS) "$(UNICODE_SRC_DATA_DIR)/auxiliary"
$(Q) $(UNICODE_AUXILIARY_DOWNLOAD) $(UNICODE_AUXILIARY_FILES)
+$(UNICODE_UCD_EMOJI_FILES): update-unicode-ucd-emoji-files
+update-unicode-ucd-emoji-files:
+ $(ECHO) Downloading Unicode UCD emoji $(UNICODE_EMOJI_VERSION) files...
+ $(Q) $(MAKEDIRS) "$(UNICODE_SRC_DATA_DIR)/emoji"
+ $(Q) $(UNICODE_UCD_EMOJI_DOWNLOAD) $(UNICODE_UCD_EMOJI_FILES)
+
$(UNICODE_EMOJI_FILES): update-unicode-emoji-files
update-unicode-emoji-files:
$(ECHO) Downloading Unicode emoji $(UNICODE_EMOJI_VERSION) files...
@@ -1483,7 +1525,7 @@ $(srcdir)/lib/unicode_normalize/$(ALWAYS_UPDATE_UNICODE:yes=tables.rb): \
$(UNICODE_SRC_DATA_DIR)/$(ALWAYS_UPDATE_UNICODE:yes=.unicode-tables.time): \
$(UNICODE_FILES) $(UNICODE_PROPERTY_FILES) \
- $(UNICODE_AUXILIARY_FILES) $(UNICODE_EMOJI_FILES)
+ $(UNICODE_AUXILIARY_FILES) $(UNICODE_UCD_EMOJI_FILES) $(UNICODE_EMOJI_FILES)
touch-unicode-files:
$(MAKEDIRS) $(UNICODE_SRC_DATA_DIR)
@@ -2074,7 +2116,6 @@ bignum.$(OBJEXT): $(top_srcdir)/internal/object.h
bignum.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
bignum.$(OBJEXT): $(top_srcdir)/internal/serial.h
bignum.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-bignum.$(OBJEXT): $(top_srcdir)/internal/util.h
bignum.$(OBJEXT): $(top_srcdir)/internal/variable.h
bignum.$(OBJEXT): $(top_srcdir)/internal/vm.h
bignum.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -2460,6 +2501,7 @@ class.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
class.$(OBJEXT): {$(VPATH)}class.c
class.$(OBJEXT): {$(VPATH)}config.h
class.$(OBJEXT): {$(VPATH)}constant.h
+class.$(OBJEXT): {$(VPATH)}debug_counter.h
class.$(OBJEXT): {$(VPATH)}defines.h
class.$(OBJEXT): {$(VPATH)}encoding.h
class.$(OBJEXT): {$(VPATH)}id.h
@@ -3398,7 +3440,6 @@ debug.$(OBJEXT): $(top_srcdir)/internal/imemo.h
debug.$(OBJEXT): $(top_srcdir)/internal/serial.h
debug.$(OBJEXT): $(top_srcdir)/internal/signal.h
debug.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-debug.$(OBJEXT): $(top_srcdir)/internal/util.h
debug.$(OBJEXT): $(top_srcdir)/internal/vm.h
debug.$(OBJEXT): $(top_srcdir)/internal/warnings.h
debug.$(OBJEXT): {$(VPATH)}assert.h
@@ -5415,6 +5456,7 @@ eval.$(OBJEXT): {$(VPATH)}vm_debug.h
eval.$(OBJEXT): {$(VPATH)}vm_opts.h
explicit_bzero.$(OBJEXT): {$(VPATH)}config.h
explicit_bzero.$(OBJEXT): {$(VPATH)}explicit_bzero.c
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/attr/format.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
@@ -5425,6 +5467,7 @@ explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/config.h
explicit_bzero.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+explicit_bzero.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
explicit_bzero.$(OBJEXT): {$(VPATH)}missing.h
file.$(OBJEXT): $(hdrdir)/ruby.h
file.$(OBJEXT): $(hdrdir)/ruby/ruby.h
@@ -5843,192 +5886,22 @@ gc.$(OBJEXT): {$(VPATH)}vm_core.h
gc.$(OBJEXT): {$(VPATH)}vm_debug.h
gc.$(OBJEXT): {$(VPATH)}vm_opts.h
gc.$(OBJEXT): {$(VPATH)}vm_sync.h
-golf_prelude.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
-golf_prelude.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
-golf_prelude.$(OBJEXT): $(CCAN_DIR)/list/list.h
-golf_prelude.$(OBJEXT): $(CCAN_DIR)/str/str.h
-golf_prelude.$(OBJEXT): $(hdrdir)/ruby.h
-golf_prelude.$(OBJEXT): $(hdrdir)/ruby/ruby.h
-golf_prelude.$(OBJEXT): $(top_srcdir)/internal/array.h
-golf_prelude.$(OBJEXT): $(top_srcdir)/internal/compilers.h
-golf_prelude.$(OBJEXT): $(top_srcdir)/internal/gc.h
-golf_prelude.$(OBJEXT): $(top_srcdir)/internal/imemo.h
-golf_prelude.$(OBJEXT): $(top_srcdir)/internal/serial.h
-golf_prelude.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
-golf_prelude.$(OBJEXT): $(top_srcdir)/internal/vm.h
-golf_prelude.$(OBJEXT): $(top_srcdir)/internal/warnings.h
-golf_prelude.$(OBJEXT): {$(VPATH)}assert.h
-golf_prelude.$(OBJEXT): {$(VPATH)}atomic.h
-golf_prelude.$(OBJEXT): {$(VPATH)}backward/2/assume.h
-golf_prelude.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
-golf_prelude.$(OBJEXT): {$(VPATH)}backward/2/bool.h
-golf_prelude.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
-golf_prelude.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
-golf_prelude.$(OBJEXT): {$(VPATH)}backward/2/limits.h
-golf_prelude.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
-golf_prelude.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
-golf_prelude.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
-golf_prelude.$(OBJEXT): {$(VPATH)}config.h
-golf_prelude.$(OBJEXT): {$(VPATH)}defines.h
-golf_prelude.$(OBJEXT): {$(VPATH)}golf_prelude.c
-golf_prelude.$(OBJEXT): {$(VPATH)}golf_prelude.rb
-golf_prelude.$(OBJEXT): {$(VPATH)}id.h
-golf_prelude.$(OBJEXT): {$(VPATH)}intern.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/anyargs.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/assume.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/const.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/error.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/format.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/cast.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/config.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/constant_p.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/robject.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/ctype.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/dllexport.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/dosish.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/error.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/eval.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/event.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/fl_type.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/gc.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/glob.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/globals.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/has/extension.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/has/feature.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/has/warning.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/array.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/class.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/error.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/file.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/gc.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/io.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/load.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/object.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/process.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/random.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/range.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/re.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/select.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/string.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/time.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/interpreter.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/iterator.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/memory.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/method.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/module.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/newobj.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/rgengc.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/scan_args.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/special_consts.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/static_assert.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/stdalign.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/stdbool.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/symbol.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/value.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/value_type.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/variable.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/warning_push.h
-golf_prelude.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
-golf_prelude.$(OBJEXT): {$(VPATH)}iseq.h
-golf_prelude.$(OBJEXT): {$(VPATH)}method.h
-golf_prelude.$(OBJEXT): {$(VPATH)}missing.h
-golf_prelude.$(OBJEXT): {$(VPATH)}node.h
-golf_prelude.$(OBJEXT): {$(VPATH)}ruby_assert.h
-golf_prelude.$(OBJEXT): {$(VPATH)}ruby_atomic.h
-golf_prelude.$(OBJEXT): {$(VPATH)}st.h
-golf_prelude.$(OBJEXT): {$(VPATH)}subst.h
-golf_prelude.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
-golf_prelude.$(OBJEXT): {$(VPATH)}thread_native.h
-golf_prelude.$(OBJEXT): {$(VPATH)}vm_core.h
-golf_prelude.$(OBJEXT): {$(VPATH)}vm_opts.h
+goruby.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+goruby.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+goruby.$(OBJEXT): $(CCAN_DIR)/list/list.h
+goruby.$(OBJEXT): $(CCAN_DIR)/str/str.h
goruby.$(OBJEXT): $(hdrdir)/ruby.h
goruby.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/array.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/gc.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/serial.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/vm.h
+goruby.$(OBJEXT): $(top_srcdir)/internal/warnings.h
goruby.$(OBJEXT): {$(VPATH)}assert.h
+goruby.$(OBJEXT): {$(VPATH)}atomic.h
goruby.$(OBJEXT): {$(VPATH)}backward.h
goruby.$(OBJEXT): {$(VPATH)}backward/2/assume.h
goruby.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
@@ -6041,8 +5914,12 @@ goruby.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
goruby.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
goruby.$(OBJEXT): {$(VPATH)}config.h
goruby.$(OBJEXT): {$(VPATH)}defines.h
+goruby.$(OBJEXT): {$(VPATH)}golf_prelude.c
+goruby.$(OBJEXT): {$(VPATH)}golf_prelude.rb
goruby.$(OBJEXT): {$(VPATH)}goruby.c
+goruby.$(OBJEXT): {$(VPATH)}id.h
goruby.$(OBJEXT): {$(VPATH)}intern.h
+goruby.$(OBJEXT): {$(VPATH)}internal.h
goruby.$(OBJEXT): {$(VPATH)}internal/anyargs.h
goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
goruby.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
@@ -6182,12 +6059,20 @@ goruby.$(OBJEXT): {$(VPATH)}internal/value_type.h
goruby.$(OBJEXT): {$(VPATH)}internal/variable.h
goruby.$(OBJEXT): {$(VPATH)}internal/warning_push.h
goruby.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+goruby.$(OBJEXT): {$(VPATH)}iseq.h
goruby.$(OBJEXT): {$(VPATH)}main.c
+goruby.$(OBJEXT): {$(VPATH)}method.h
goruby.$(OBJEXT): {$(VPATH)}missing.h
goruby.$(OBJEXT): {$(VPATH)}node.h
+goruby.$(OBJEXT): {$(VPATH)}ruby_assert.h
+goruby.$(OBJEXT): {$(VPATH)}ruby_atomic.h
goruby.$(OBJEXT): {$(VPATH)}st.h
goruby.$(OBJEXT): {$(VPATH)}subst.h
+goruby.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+goruby.$(OBJEXT): {$(VPATH)}thread_native.h
+goruby.$(OBJEXT): {$(VPATH)}vm_core.h
goruby.$(OBJEXT): {$(VPATH)}vm_debug.h
+goruby.$(OBJEXT): {$(VPATH)}vm_opts.h
hash.$(OBJEXT): $(hdrdir)/ruby.h
hash.$(OBJEXT): $(hdrdir)/ruby/ruby.h
hash.$(OBJEXT): $(top_srcdir)/internal/array.h
@@ -8001,7 +7886,6 @@ math.$(OBJEXT): {$(VPATH)}st.h
math.$(OBJEXT): {$(VPATH)}subst.h
memory_view.$(OBJEXT): $(hdrdir)/ruby/ruby.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/hash.h
-memory_view.$(OBJEXT): $(top_srcdir)/internal/util.h
memory_view.$(OBJEXT): $(top_srcdir)/internal/variable.h
memory_view.$(OBJEXT): {$(VPATH)}assert.h
memory_view.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -8165,6 +8049,7 @@ memory_view.$(OBJEXT): {$(VPATH)}missing.h
memory_view.$(OBJEXT): {$(VPATH)}node.h
memory_view.$(OBJEXT): {$(VPATH)}st.h
memory_view.$(OBJEXT): {$(VPATH)}subst.h
+memory_view.$(OBJEXT): {$(VPATH)}util.h
memory_view.$(OBJEXT): {$(VPATH)}vm_debug.h
memory_view.$(OBJEXT): {$(VPATH)}vm_sync.h
miniinit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
@@ -9397,7 +9282,6 @@ pack.$(OBJEXT): $(top_srcdir)/internal/compilers.h
pack.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
pack.$(OBJEXT): $(top_srcdir)/internal/string.h
pack.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-pack.$(OBJEXT): $(top_srcdir)/internal/util.h
pack.$(OBJEXT): $(top_srcdir)/internal/variable.h
pack.$(OBJEXT): $(top_srcdir)/internal/warnings.h
pack.$(OBJEXT): {$(VPATH)}assert.h
@@ -9564,6 +9448,7 @@ pack.$(OBJEXT): {$(VPATH)}pack.c
pack.$(OBJEXT): {$(VPATH)}pack.rbinc
pack.$(OBJEXT): {$(VPATH)}st.h
pack.$(OBJEXT): {$(VPATH)}subst.h
+pack.$(OBJEXT): {$(VPATH)}util.h
parse.$(OBJEXT): $(hdrdir)/ruby.h
parse.$(OBJEXT): $(hdrdir)/ruby/ruby.h
parse.$(OBJEXT): $(top_srcdir)/internal/array.h
@@ -9587,7 +9472,6 @@ parse.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
parse.$(OBJEXT): $(top_srcdir)/internal/string.h
parse.$(OBJEXT): $(top_srcdir)/internal/symbol.h
parse.$(OBJEXT): $(top_srcdir)/internal/thread.h
-parse.$(OBJEXT): $(top_srcdir)/internal/util.h
parse.$(OBJEXT): $(top_srcdir)/internal/variable.h
parse.$(OBJEXT): $(top_srcdir)/internal/vm.h
parse.$(OBJEXT): $(top_srcdir)/internal/warnings.h
@@ -12877,7 +12761,6 @@ sprintf.$(OBJEXT): $(top_srcdir)/internal/serial.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/string.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/symbol.h
-sprintf.$(OBJEXT): $(top_srcdir)/internal/util.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/vm.h
sprintf.$(OBJEXT): $(top_srcdir)/internal/warnings.h
sprintf.$(OBJEXT): {$(VPATH)}assert.h
@@ -13045,6 +12928,7 @@ sprintf.$(OBJEXT): {$(VPATH)}regex.h
sprintf.$(OBJEXT): {$(VPATH)}sprintf.c
sprintf.$(OBJEXT): {$(VPATH)}st.h
sprintf.$(OBJEXT): {$(VPATH)}subst.h
+sprintf.$(OBJEXT): {$(VPATH)}util.h
sprintf.$(OBJEXT): {$(VPATH)}vsnprintf.c
st.$(OBJEXT): $(hdrdir)/ruby.h
st.$(OBJEXT): $(hdrdir)/ruby/ruby.h
@@ -13217,7 +13101,6 @@ strftime.$(OBJEXT): $(top_srcdir)/internal/compilers.h
strftime.$(OBJEXT): $(top_srcdir)/internal/serial.h
strftime.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
strftime.$(OBJEXT): $(top_srcdir)/internal/string.h
-strftime.$(OBJEXT): $(top_srcdir)/internal/util.h
strftime.$(OBJEXT): $(top_srcdir)/internal/vm.h
strftime.$(OBJEXT): {$(VPATH)}assert.h
strftime.$(OBJEXT): {$(VPATH)}backward/2/assume.h
@@ -13380,6 +13263,7 @@ strftime.$(OBJEXT): {$(VPATH)}st.h
strftime.$(OBJEXT): {$(VPATH)}strftime.c
strftime.$(OBJEXT): {$(VPATH)}subst.h
strftime.$(OBJEXT): {$(VPATH)}timev.h
+strftime.$(OBJEXT): {$(VPATH)}util.h
string.$(OBJEXT): $(hdrdir)/ruby.h
string.$(OBJEXT): $(hdrdir)/ruby/ruby.h
string.$(OBJEXT): $(top_srcdir)/internal/array.h
@@ -13582,6 +13466,7 @@ string.$(OBJEXT): {$(VPATH)}util.h
string.$(OBJEXT): {$(VPATH)}vm_debug.h
string.$(OBJEXT): {$(VPATH)}vm_sync.h
strlcat.$(OBJEXT): {$(VPATH)}config.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/attr/format.h
strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
@@ -13592,9 +13477,11 @@ strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
strlcat.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
strlcat.$(OBJEXT): {$(VPATH)}internal/config.h
strlcat.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+strlcat.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
strlcat.$(OBJEXT): {$(VPATH)}missing.h
strlcat.$(OBJEXT): {$(VPATH)}strlcat.c
strlcpy.$(OBJEXT): {$(VPATH)}config.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/attr/format.h
strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
@@ -13605,6 +13492,7 @@ strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
strlcpy.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
strlcpy.$(OBJEXT): {$(VPATH)}internal/config.h
strlcpy.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+strlcpy.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
strlcpy.$(OBJEXT): {$(VPATH)}missing.h
strlcpy.$(OBJEXT): {$(VPATH)}strlcpy.c
struct.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
@@ -15348,6 +15236,7 @@ vm.$(OBJEXT): $(top_srcdir)/internal/serial.h
vm.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
vm.$(OBJEXT): $(top_srcdir)/internal/string.h
vm.$(OBJEXT): $(top_srcdir)/internal/symbol.h
+vm.$(OBJEXT): $(top_srcdir)/internal/thread.h
vm.$(OBJEXT): $(top_srcdir)/internal/variable.h
vm.$(OBJEXT): $(top_srcdir)/internal/vm.h
vm.$(OBJEXT): $(top_srcdir)/internal/warnings.h
diff --git a/compar.c b/compar.c
index 04d4ff8..e9d1ac4 100644
--- a/compar.c
+++ b/compar.c
@@ -84,8 +84,7 @@ cmp_equal(VALUE x, VALUE y)
c = rb_exec_recursive_paired_outer(cmp_eq_recursive, x, y, y);
if (NIL_P(c)) return Qfalse;
- if (rb_cmpint(c, x, y) == 0) return Qtrue;
- return Qfalse;
+ return RBOOL(rb_cmpint(c, x, y) == 0);
}
static int
@@ -105,8 +104,7 @@ cmpint(VALUE x, VALUE y)
static VALUE
cmp_gt(VALUE x, VALUE y)
{
- if (cmpint(x, y) > 0) return Qtrue;
- return Qfalse;
+ return RBOOL(cmpint(x, y) > 0);
}
/*
@@ -120,8 +118,7 @@ cmp_gt(VALUE x, VALUE y)
static VALUE
cmp_ge(VALUE x, VALUE y)
{
- if (cmpint(x, y) >= 0) return Qtrue;
- return Qfalse;
+ return RBOOL(cmpint(x, y) >= 0);
}
/*
@@ -135,8 +132,7 @@ cmp_ge(VALUE x, VALUE y)
static VALUE
cmp_lt(VALUE x, VALUE y)
{
- if (cmpint(x, y) < 0) return Qtrue;
- return Qfalse;
+ return RBOOL(cmpint(x, y) < 0);
}
/*
@@ -150,8 +146,7 @@ cmp_lt(VALUE x, VALUE y)
static VALUE
cmp_le(VALUE x, VALUE y)
{
- if (cmpint(x, y) <= 0) return Qtrue;
- return Qfalse;
+ return RBOOL(cmpint(x, y) <= 0);
}
/*
@@ -289,6 +284,22 @@ cmp_clamp(int argc, VALUE *argv, VALUE x)
* s4.between?(s3, s5) #=> true
* [ s3, s2, s5, s4, s1 ].sort #=> [Z, YY, XXX, WWWW, VVVVV]
*
+ * == What's Here
+ *
+ * \Module \Comparable provides these methods, all of which use method <tt><=></tt>:
+ *
+ * - {<}[#method-i-3C]:: Returns whether +self+ is less than the given object.
+ * - {<=}[#method-i-3C-3D]:: Returns whether +self+ is less than or equal to
+ * the given object.
+ * - {==}[#method-i-3D-3D]:: Returns whether +self+ is equal to the given object.
+ * - {>}[#method-i-3E]:: Returns whether +self+ is greater than or equal to
+ * the given object.
+ * - {>=}[#method-i-3E-3D]:: Returns whether +self+ is greater than the given object.
+ * - #between? Returns +true+ if +self+ is between two given objects.
+ * - #clamp:: For given objects +min+ and +max+, or range <tt>(min..max)</tt>, returns:
+ * - +min+ if <tt>(self <=> min) < 0</tt>.
+ * - +max+ if <tt>(self <=> max) > 0</tt>.
+ * - +self+ otherwise.
*/
void
diff --git a/compile.c b/compile.c
index c3aa8f3..268bd8b 100644
--- a/compile.c
+++ b/compile.c
@@ -353,9 +353,9 @@ static void iseq_add_setlocal(rb_iseq_t *iseq, LINK_ANCHOR *const seq, const NOD
/* error */
#if CPDEBUG > 0
-NORETURN(static void append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...));
+RBIMPL_ATTR_NORETURN()
#endif
-
+RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
static void
append_compile_error(const rb_iseq_t *iseq, int line, const char *fmt, ...)
{
@@ -1633,7 +1633,7 @@ access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
if (isolated_depth && level >= isolated_depth) {
if (id == rb_intern("yield")) {
- COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc", rb_id2name(id));
+ COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not yield from isolated Proc");
}
else {
COMPILE_ERROR(iseq, ISEQ_LAST_LINE(iseq), "can not access variable `%s' from isolated Proc", rb_id2name(id));
@@ -1654,7 +1654,7 @@ access_outer_variables(const rb_iseq_t *iseq, int level, ID id, bool write)
}
}
else {
- rb_id_table_insert(iseq->body->outer_variables, id, write ? Qtrue : Qfalse);
+ rb_id_table_insert(iseq->body->outer_variables, id, RBOOL(write));
}
iseq = iseq->body->parent_iseq;
@@ -3088,6 +3088,7 @@ iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcal
*/
int stop_optimization =
ISEQ_COVERAGE(iseq) && ISEQ_LINE_COVERAGE(iseq) &&
+ nobj->link.type == ISEQ_ELEMENT_INSN &&
nobj->insn_info.events;
if (!stop_optimization) {
INSN *pobj = (INSN *)iobj->link.prev;
@@ -3440,13 +3441,14 @@ insn_set_specialized_instruction(rb_iseq_t *iseq, INSN *iobj, int insn_id)
{
iobj->insn_id = insn_id;
iobj->operand_size = insn_len(insn_id) - 1;
+ iobj->insn_info.events |= RUBY_EVENT_C_CALL | RUBY_EVENT_C_RETURN;
if (insn_id == BIN(opt_neq)) {
- VALUE *old_operands = iobj->operands;
+ VALUE original_ci = iobj->operands[0];
iobj->operand_size = 2;
iobj->operands = compile_data_calloc2(iseq, iobj->operand_size, sizeof(VALUE));
iobj->operands[0] = (VALUE)new_callinfo(iseq, idEq, 1, 0, NULL, FALSE);
- iobj->operands[1] = old_operands[0];
+ iobj->operands[1] = original_ci;
}
return COMPILE_OK;
@@ -3934,6 +3936,20 @@ compile_dstr_fragments(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *cons
}
static int
+compile_block(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
+{
+ while (node && nd_type(node) == NODE_BLOCK) {
+ CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
+ (node->nd_next ? 1 : popped)));
+ node = node->nd_next;
+ }
+ if (node) {
+ CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
+ }
+ return COMPILE_OK;
+}
+
+static int
compile_dstr(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node)
{
int cnt;
@@ -4087,7 +4103,7 @@ compile_keyword_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret,
seen_nodes++;
assert(nd_type(node) == NODE_LIST);
- if (key_node && nd_type(key_node) == NODE_LIT && RB_TYPE_P(key_node->nd_lit, T_SYMBOL)) {
+ if (key_node && nd_type(key_node) == NODE_LIT && SYMBOL_P(key_node->nd_lit)) {
/* can be keywords */
}
else {
@@ -4535,7 +4551,7 @@ rb_node_case_when_optimizable_literal(const NODE *const node)
case NODE_LIT: {
VALUE v = node->nd_lit;
double ival;
- if (RB_TYPE_P(v, T_FLOAT) &&
+ if (RB_FLOAT_TYPE_P(v) &&
modf(RFLOAT_VALUE(v), &ival) == 0.0) {
return FIXABLE(ival) ? LONG2FIX((long)ival) : rb_dbl2big(ival);
}
@@ -5480,7 +5496,7 @@ setup_args_core(rb_iseq_t *iseq, LINK_ANCHOR *const args, const NODE *argn,
switch (nd_type(argn)) {
case NODE_SPLAT: {
NO_CHECK(COMPILE(args, "args (splat)", argn->nd_head));
- ADD_INSN1(args, argn, splatarray, dup_rest ? Qtrue : Qfalse);
+ ADD_INSN1(args, argn, splatarray, RBOOL(dup_rest));
if (flag) *flag |= VM_CALL_ARGS_SPLAT;
return INT2FIX(1);
}
@@ -5938,12 +5954,22 @@ compile_case2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
return COMPILE_OK;
}
-static int iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos);
+static int iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache);
+
+static int iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *match_failed, bool in_single_pattern, int base_index);
+static int iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, bool in_single_pattern, int base_index, bool use_deconstructed_cache);
+static int iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index);
+static int iseq_compile_pattern_set_length_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, VALUE pattern_length, int base_index);
+static int iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index);
-static int iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, int deconstructed_pos);
+#define CASE3_BI_OFFSET_DECONSTRUCTED_CACHE 0
+#define CASE3_BI_OFFSET_ERROR_STRING 1
+#define CASE3_BI_OFFSET_KEY_ERROR_P 2
+#define CASE3_BI_OFFSET_KEY_ERROR_MATCHEE 3
+#define CASE3_BI_OFFSET_KEY_ERROR_KEY 4
static int
-iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *matched, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos)
+iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *matched, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache)
{
const int line = nd_line(node);
const NODE *line_node = node;
@@ -6021,31 +6047,32 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
if (use_rest_num) {
ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for rest_num */
ADD_INSN(ret, line_node, swap);
- if (deconstructed_pos) {
- deconstructed_pos++;
+ if (base_index) {
+ base_index++;
}
}
- if (node->nd_pconst) {
- ADD_INSN(ret, line_node, dup);
- CHECK(COMPILE(ret, "constant", node->nd_pconst));
- ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
- ADD_INSNL(ret, line_node, branchunless, match_failed);
- }
+ CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
- CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos));
+ CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
ADD_INSN(ret, line_node, dup);
ADD_SEND(ret, line_node, idLength, INT2FIX(0));
ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
- ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq, INT2FIX(1));
+ ADD_SEND(ret, line_node, apinfo->rest_arg ? idGE : idEq, INT2FIX(1)); // (1)
+ if (in_single_pattern) {
+ CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node,
+ apinfo->rest_arg ? rb_fstring_lit("%p length mismatch (given %p, expected %p+)") :
+ rb_fstring_lit("%p length mismatch (given %p, expected %p)"),
+ INT2FIX(min_argc), base_index + 1 /* (1) */));
+ }
ADD_INSNL(ret, line_node, branchunless, match_failed);
for (i = 0; i < pre_args_num; i++) {
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, INT2FIX(i));
- ADD_SEND(ret, line_node, idAREF, INT2FIX(1));
- CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_alt_pattern, FALSE));
+ ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (2)
+ CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (2) */, false));
args = args->nd_next;
}
@@ -6058,9 +6085,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, putobject, INT2FIX(min_argc));
ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
ADD_INSN1(ret, line_node, setn, INT2FIX(4));
- ADD_SEND(ret, line_node, idAREF, INT2FIX(2));
+ ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (3)
- CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_alt_pattern, FALSE));
+ CHECK(iseq_compile_pattern_match(iseq, ret, apinfo->rest_arg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (3) */, false));
}
else {
if (post_args_num > 0) {
@@ -6082,8 +6109,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
- ADD_SEND(ret, line_node, idAREF, INT2FIX(1));
- CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_alt_pattern, FALSE));
+ ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (4)
+ CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (4) */, false));
args = args->nd_next;
}
@@ -6172,19 +6199,17 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
deconstruct = NEW_LABEL(line);
deconstructed = NEW_LABEL(line);
- if (node->nd_pconst) {
- ADD_INSN(ret, line_node, dup);
- CHECK(COMPILE(ret, "constant", node->nd_pconst));
- ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
- ADD_INSNL(ret, line_node, branchunless, match_failed);
- }
+ CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
- CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, deconstructed_pos));
+ CHECK(iseq_compile_array_deconstruct(iseq, ret, node, deconstruct, deconstructed, match_failed, type_error, in_single_pattern, base_index, use_deconstructed_cache));
ADD_INSN(ret, line_node, dup);
ADD_SEND(ret, line_node, idLength, INT2FIX(0));
ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
- ADD_SEND(ret, line_node, idGE, INT2FIX(1));
+ ADD_SEND(ret, line_node, idGE, INT2FIX(1)); // (1)
+ if (in_single_pattern) {
+ CHECK(iseq_compile_pattern_set_length_errmsg(iseq, ret, node, rb_fstring_lit("%p length mismatch (given %p, expected %p+)"), INT2FIX(args_num), base_index + 1 /* (1) */));
+ }
ADD_INSNL(ret, line_node, branchunless, match_failed);
{
@@ -6195,13 +6220,13 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
int j;
ADD_INSN(ret, line_node, dup); /* allocate stack for len */
- ADD_SEND(ret, line_node, idLength, INT2FIX(0));
+ ADD_SEND(ret, line_node, idLength, INT2FIX(0)); // (2)
ADD_INSN(ret, line_node, dup); /* allocate stack for limit */
ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
- ADD_SEND(ret, line_node, idMINUS, INT2FIX(1));
+ ADD_SEND(ret, line_node, idMINUS, INT2FIX(1)); // (3)
- ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */
+ ADD_INSN1(ret, line_node, putobject, INT2FIX(0)); /* allocate stack for i */ // (4)
ADD_LABEL(ret, while_begin);
@@ -6217,9 +6242,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, putobject, INT2FIX(j));
ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
}
- ADD_SEND(ret, line_node, idAREF, INT2FIX(1));
+ ADD_SEND(ret, line_node, idAREF, INT2FIX(1)); // (5)
- CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_alt_pattern, FALSE));
+ CHECK(iseq_compile_pattern_match(iseq, ret, args->nd_head, next_loop, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (5) */, false));
args = args->nd_next;
}
@@ -6227,8 +6252,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
ADD_INSN1(ret, line_node, putobject, INT2FIX(0));
ADD_INSN1(ret, line_node, topn, INT2FIX(2));
- ADD_SEND(ret, line_node, idAREF, INT2FIX(2));
- CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_alt_pattern, FALSE));
+ ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (6)
+ CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->pre_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3), (4), (6) */, false));
}
if (NODE_NAMED_REST_P(fpinfo->post_rest_arg)) {
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
@@ -6236,8 +6261,8 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, putobject, INT2FIX(args_num));
ADD_SEND(ret, line_node, idPLUS, INT2FIX(1));
ADD_INSN1(ret, line_node, topn, INT2FIX(3));
- ADD_SEND(ret, line_node, idAREF, INT2FIX(2));
- CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_alt_pattern, FALSE));
+ ADD_SEND(ret, line_node, idAREF, INT2FIX(2)); // (7)
+ CHECK(iseq_compile_pattern_match(iseq, ret, fpinfo->post_rest_arg, find_failed, in_single_pattern, in_alt_pattern, base_index + 4 /* (2), (3),(4), (7) */, false));
}
ADD_INSNL(ret, line_node, jump, find_succeeded);
@@ -6247,16 +6272,25 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSNL(ret, line_node, jump, while_begin);
ADD_LABEL(ret, find_failed);
- ADD_INSN(ret, line_node, pop);
- ADD_INSN(ret, line_node, pop);
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
+ if (in_single_pattern) {
+ ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p does not match to find pattern"));
+ ADD_INSN1(ret, line_node, topn, INT2FIX(2));
+ ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (8)
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (8) */)); // (9)
+
+ ADD_INSN1(ret, line_node, putobject, Qfalse);
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (8), (9) */));
+
+ ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, line_node, pop);
+ }
ADD_INSNL(ret, line_node, jump, match_failed);
ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
ADD_LABEL(ret, find_succeeded);
- ADD_INSN(ret, line_node, pop);
- ADD_INSN(ret, line_node, pop);
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN1(ret, line_node, adjuststack, INT2FIX(3));
}
ADD_INSN(ret, line_node, pop);
@@ -6351,16 +6385,14 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
}
- if (node->nd_pconst) {
- ADD_INSN(ret, line_node, dup);
- CHECK(COMPILE(ret, "constant", node->nd_pconst));
- ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
- ADD_INSNL(ret, line_node, branchunless, match_failed);
- }
+ CHECK(iseq_compile_pattern_constant(iseq, ret, node, match_failed, in_single_pattern, base_index));
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct_keys")));
- ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1));
+ ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (1)
+ if (in_single_pattern) {
+ CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct_keys"), base_index + 1 /* (1) */));
+ }
ADD_INSNL(ret, line_node, branchunless, match_failed);
if (NIL_P(keys)) {
@@ -6370,7 +6402,7 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN1(ret, line_node, duparray, keys);
RB_OBJ_WRITTEN(iseq, Qundef, rb_obj_hide(keys));
}
- ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1));
+ ADD_SEND(ret, line_node, rb_intern("deconstruct_keys"), INT2FIX(1)); // (2)
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, checktype, INT2FIX(T_HASH));
@@ -6401,13 +6433,33 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, key);
- ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1));
+ ADD_SEND(ret, line_node, rb_intern("key?"), INT2FIX(1)); // (3)
+ if (in_single_pattern) {
+ LABEL *match_succeeded;
+ match_succeeded = NEW_LABEL(line);
+
+ ADD_INSN(ret, line_node, dup);
+ ADD_INSNL(ret, line_node, branchif, match_succeeded);
+
+ ADD_INSN1(ret, line_node, putobject, rb_str_freeze(rb_sprintf("key not found: %+"PRIsVALUE, key))); // (4)
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 2 /* (3), (4) */));
+ ADD_INSN1(ret, line_node, putobject, Qtrue); // (5)
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 3 /* (3), (4), (5) */));
+ ADD_INSN1(ret, line_node, topn, INT2FIX(3)); // (6)
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4 /* (3), (4), (5), (6) */));
+ ADD_INSN1(ret, line_node, putobject, key); // (7)
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_KEY + 5 /* (3), (4), (5), (6), (7) */));
+
+ ADD_INSN1(ret, line_node, adjuststack, INT2FIX(4));
+
+ ADD_LABEL(ret, match_succeeded);
+ }
ADD_INSNL(ret, line_node, branchunless, match_failed);
ADD_INSN(match_values, line_node, dup);
ADD_INSN1(match_values, line_node, putobject, key);
- ADD_SEND(match_values, line_node, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1));
- CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_alt_pattern, FALSE));
+ ADD_SEND(match_values, line_node, node->nd_pkwrestarg ? rb_intern("delete") : idAREF, INT2FIX(1)); // (8)
+ CHECK(iseq_compile_pattern_match(iseq, match_values, value_node, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (8) */, false));
args = args->nd_next->nd_next;
}
ADD_SEQ(ret, match_values);
@@ -6415,19 +6467,25 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
else {
ADD_INSN(ret, line_node, dup);
- ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0));
+ ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (9)
+ if (in_single_pattern) {
+ CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p is not empty"), base_index + 1 /* (9) */));
+ }
ADD_INSNL(ret, line_node, branchunless, match_failed);
}
if (node->nd_pkwrestarg) {
if (node->nd_pkwrestarg == NODE_SPECIAL_NO_REST_KEYWORD) {
ADD_INSN(ret, line_node, dup);
- ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0));
+ ADD_SEND(ret, line_node, idEmptyP, INT2FIX(0)); // (10)
+ if (in_single_pattern) {
+ CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("rest of %p is not empty"), base_index + 1 /* (10) */));
+ }
ADD_INSNL(ret, line_node, branchunless, match_failed);
}
else {
- ADD_INSN(ret, line_node, dup);
- CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_pkwrestarg, match_failed, in_alt_pattern, FALSE));
+ ADD_INSN(ret, line_node, dup); // (11)
+ CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_pkwrestarg, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (11) */, false));
}
}
@@ -6461,6 +6519,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
case NODE_CONST:
case NODE_LVAR:
case NODE_DVAR:
+ case NODE_IVAR:
+ case NODE_CVAR:
+ case NODE_GVAR:
case NODE_TRUE:
case NODE_FALSE:
case NODE_SELF:
@@ -6468,8 +6529,14 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
case NODE_COLON2:
case NODE_COLON3:
case NODE_BEGIN:
- CHECK(COMPILE(ret, "case in literal", node));
- ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE));
+ CHECK(COMPILE(ret, "case in literal", node)); // (1)
+ if (in_single_pattern) {
+ ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
+ }
+ ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (2)
+ if (in_single_pattern) {
+ CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 2 /* (1), (2) */));
+ }
ADD_INSNL(ret, line_node, branchif, matched);
ADD_INSNL(ret, line_node, jump, unmatched);
break;
@@ -6520,8 +6587,30 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
case NODE_UNLESS: {
LABEL *match_failed;
match_failed = unmatched;
- CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_body, unmatched, in_alt_pattern, deconstructed_pos));
+ CHECK(iseq_compile_pattern_match(iseq, ret, node->nd_body, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
CHECK(COMPILE(ret, "case in if", node->nd_cond));
+ if (in_single_pattern) {
+ LABEL *match_succeeded;
+ match_succeeded = NEW_LABEL(line);
+
+ ADD_INSN(ret, line_node, dup);
+ if (nd_type(node) == NODE_IF) {
+ ADD_INSNL(ret, line_node, branchif, match_succeeded);
+ }
+ else {
+ ADD_INSNL(ret, line_node, branchunless, match_succeeded);
+ }
+
+ ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("guard clause does not return true")); // (1)
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
+ ADD_INSN1(ret, line_node, putobject, Qfalse);
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
+
+ ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, line_node, pop);
+
+ ADD_LABEL(ret, match_succeeded);
+ }
if (nd_type(node) == NODE_IF) {
ADD_INSNL(ret, line_node, branchunless, match_failed);
}
@@ -6542,9 +6631,9 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
return COMPILE_NG;
}
- ADD_INSN(ret, line_node, dup);
- CHECK(iseq_compile_pattern_match(iseq, ret, n->nd_head, match_failed, in_alt_pattern, deconstructed_pos ? deconstructed_pos + 1 : FALSE));
- CHECK(iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, matched, match_failed, in_alt_pattern, FALSE));
+ ADD_INSN(ret, line_node, dup); // (1)
+ CHECK(iseq_compile_pattern_match(iseq, ret, n->nd_head, match_failed, in_single_pattern, in_alt_pattern, base_index + 1 /* (1) */, use_deconstructed_cache));
+ CHECK(iseq_compile_pattern_each(iseq, ret, n->nd_next->nd_head, matched, match_failed, in_single_pattern, in_alt_pattern, base_index, false));
ADD_INSN(ret, line_node, putnil);
ADD_LABEL(ret, match_failed);
@@ -6557,14 +6646,14 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
match_succeeded = NEW_LABEL(line);
fin = NEW_LABEL(line);
- ADD_INSN(ret, line_node, dup);
- CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_1st, match_succeeded, fin, TRUE, deconstructed_pos ? deconstructed_pos + 1 : FALSE));
+ ADD_INSN(ret, line_node, dup); // (1)
+ CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_1st, match_succeeded, fin, in_single_pattern, true, base_index + 1 /* (1) */, use_deconstructed_cache));
ADD_LABEL(ret, match_succeeded);
ADD_INSN(ret, line_node, pop);
ADD_INSNL(ret, line_node, jump, matched);
ADD_INSN(ret, line_node, putnil);
ADD_LABEL(ret, fin);
- CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_2nd, matched, unmatched, TRUE, deconstructed_pos));
+ CHECK(iseq_compile_pattern_each(iseq, ret, node->nd_2nd, matched, unmatched, in_single_pattern, true, base_index, use_deconstructed_cache));
break;
}
default:
@@ -6574,35 +6663,54 @@ iseq_compile_pattern_each(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *c
}
static int
-iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, int in_alt_pattern, int deconstructed_pos)
+iseq_compile_pattern_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *unmatched, bool in_single_pattern, bool in_alt_pattern, int base_index, bool use_deconstructed_cache)
{
LABEL *fin = NEW_LABEL(nd_line(node));
- CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_alt_pattern, deconstructed_pos));
+ CHECK(iseq_compile_pattern_each(iseq, ret, node, fin, unmatched, in_single_pattern, in_alt_pattern, base_index, use_deconstructed_cache));
ADD_LABEL(ret, fin);
return COMPILE_OK;
}
static int
-iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, int deconstructed_pos)
+iseq_compile_pattern_constant(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *match_failed, bool in_single_pattern, int base_index)
+{
+ const NODE *line_node = node;
+
+ if (node->nd_pconst) {
+ ADD_INSN(ret, line_node, dup); // (1)
+ CHECK(COMPILE(ret, "constant", node->nd_pconst)); // (2)
+ if (in_single_pattern) {
+ ADD_INSN1(ret, line_node, dupn, INT2FIX(2));
+ }
+ ADD_INSN1(ret, line_node, checkmatch, INT2FIX(VM_CHECKMATCH_TYPE_CASE)); // (3)
+ if (in_single_pattern) {
+ CHECK(iseq_compile_pattern_set_eqq_errmsg(iseq, ret, node, base_index + 3 /* (1), (2), (3) */));
+ }
+ ADD_INSNL(ret, line_node, branchunless, match_failed);
+ }
+ return COMPILE_OK;
+}
+
+
+static int
+iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, LABEL *deconstruct, LABEL *deconstructed, LABEL *match_failed, LABEL *type_error, bool in_single_pattern, int base_index, bool use_deconstructed_cache)
{
const NODE *line_node = node;
// NOTE: this optimization allows us to re-use the #deconstruct value
// (or its absence).
- // `deconstructed_pos` contains the distance to the stack relative location
- // where the value is stored.
- if (deconstructed_pos) {
+ if (use_deconstructed_cache) {
// If value is nil then we haven't tried to deconstruct
- ADD_INSN1(ret, line_node, topn, INT2FIX(deconstructed_pos));
+ ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
ADD_INSNL(ret, line_node, branchnil, deconstruct);
// If false then the value is not deconstructable
- ADD_INSN1(ret, line_node, topn, INT2FIX(deconstructed_pos));
+ ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
ADD_INSNL(ret, line_node, branchunless, match_failed);
// Drop value, add deconstructed to the stack and jump
- ADD_INSN(ret, line_node, pop);
- ADD_INSN1(ret, line_node, topn, INT2FIX(deconstructed_pos - 1));
+ ADD_INSN(ret, line_node, pop); // (1)
+ ADD_INSN1(ret, line_node, topn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE - 1 /* (1) */));
ADD_INSNL(ret, line_node, jump, deconstructed);
}
else {
@@ -6612,11 +6720,15 @@ iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NO
ADD_LABEL(ret, deconstruct);
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, putobject, ID2SYM(rb_intern("deconstruct")));
- ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1));
+ ADD_SEND(ret, line_node, idRespond_to, INT2FIX(1)); // (2)
// Cache the result of respond_to? (in case it's false is stays there, if true - it's overwritten after #deconstruct)
- if (deconstructed_pos) {
- ADD_INSN1(ret, line_node, setn, INT2FIX(deconstructed_pos + 1));
+ if (use_deconstructed_cache) {
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE + 1 /* (2) */));
+ }
+
+ if (in_single_pattern) {
+ CHECK(iseq_compile_pattern_set_general_errmsg(iseq, ret, node, rb_fstring_lit("%p does not respond to #deconstruct"), base_index + 1 /* (2) */));
}
ADD_INSNL(ret, line_node, branchunless, match_failed);
@@ -6624,14 +6736,13 @@ iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NO
ADD_SEND(ret, line_node, rb_intern("deconstruct"), INT2FIX(0));
// Cache the result (if it's cacheable - currently, only top-level array patterns)
- if (deconstructed_pos) {
- ADD_INSN1(ret, line_node, setn, INT2FIX(deconstructed_pos));
+ if (use_deconstructed_cache) {
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_DECONSTRUCTED_CACHE));
}
ADD_INSN(ret, line_node, dup);
ADD_INSN1(ret, line_node, checktype, INT2FIX(T_ARRAY));
ADD_INSNL(ret, line_node, branchunless, type_error);
- ADD_INSNL(ret, line_node, jump, deconstructed);
ADD_LABEL(ret, deconstructed);
@@ -6639,6 +6750,116 @@ iseq_compile_array_deconstruct(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NO
}
static int
+iseq_compile_pattern_set_general_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, int base_index)
+{
+ /*
+ * if match_succeeded?
+ * goto match_succeeded
+ * end
+ * error_string = FrozenCore.sprintf(errmsg, matchee)
+ * key_error_p = false
+ * match_succeeded:
+ */
+ const int line = nd_line(node);
+ const NODE *line_node = node;
+ LABEL *match_succeeded = NEW_LABEL(line);
+
+ ADD_INSN(ret, line_node, dup);
+ ADD_INSNL(ret, line_node, branchif, match_succeeded);
+
+ ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, line_node, putobject, errmsg);
+ ADD_INSN1(ret, line_node, topn, INT2FIX(3));
+ ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(2)); // (1)
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
+
+ ADD_INSN1(ret, line_node, putobject, Qfalse);
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
+
+ ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, line_node, pop);
+ ADD_LABEL(ret, match_succeeded);
+
+ return COMPILE_OK;
+}
+
+static int
+iseq_compile_pattern_set_length_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, VALUE errmsg, VALUE pattern_length, int base_index)
+{
+ /*
+ * if match_succeeded?
+ * goto match_succeeded
+ * end
+ * error_string = FrozenCore.sprintf(errmsg, matchee, matchee.length, pat.length)
+ * key_error_p = false
+ * match_succeeded:
+ */
+ const int line = nd_line(node);
+ const NODE *line_node = node;
+ LABEL *match_succeeded = NEW_LABEL(line);
+
+ ADD_INSN(ret, line_node, dup);
+ ADD_INSNL(ret, line_node, branchif, match_succeeded);
+
+ ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, line_node, putobject, errmsg);
+ ADD_INSN1(ret, line_node, topn, INT2FIX(3));
+ ADD_INSN(ret, line_node, dup);
+ ADD_SEND(ret, line_node, idLength, INT2FIX(0));
+ ADD_INSN1(ret, line_node, putobject, pattern_length);
+ ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(4)); // (1)
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
+
+ ADD_INSN1(ret, line_node, putobject, Qfalse);
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2/* (1), (2) */));
+
+ ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, line_node, pop);
+ ADD_LABEL(ret, match_succeeded);
+
+ return COMPILE_OK;
+}
+
+static int
+iseq_compile_pattern_set_eqq_errmsg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int base_index)
+{
+ /*
+ * if match_succeeded?
+ * goto match_succeeded
+ * end
+ * error_string = FrozenCore.sprintf("%p === %p does not return true", pat, matchee)
+ * key_error_p = false
+ * match_succeeded:
+ */
+ const int line = nd_line(node);
+ const NODE *line_node = node;
+ LABEL *match_succeeded = NEW_LABEL(line);
+
+ ADD_INSN(ret, line_node, dup);
+ ADD_INSNL(ret, line_node, branchif, match_succeeded);
+
+ ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, line_node, putobject, rb_fstring_lit("%p === %p does not return true"));
+ ADD_INSN1(ret, line_node, topn, INT2FIX(3));
+ ADD_INSN1(ret, line_node, topn, INT2FIX(5));
+ ADD_SEND(ret, line_node, id_core_sprintf, INT2FIX(3)); // (1)
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_ERROR_STRING + 1 /* (1) */)); // (2)
+
+ ADD_INSN1(ret, line_node, putobject, Qfalse);
+ ADD_INSN1(ret, line_node, setn, INT2FIX(base_index + CASE3_BI_OFFSET_KEY_ERROR_P + 2 /* (1), (2) */));
+
+ ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, line_node, pop);
+
+ ADD_LABEL(ret, match_succeeded);
+ ADD_INSN1(ret, line_node, setn, INT2FIX(2));
+ ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, line_node, pop);
+
+ return COMPILE_OK;
+}
+
+static int
compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_node, int popped)
{
const NODE *pattern;
@@ -6652,6 +6873,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
const NODE *line_node;
VALUE branches = 0;
int branch_id = 0;
+ bool single_pattern;
INIT_ANCHOR(head);
INIT_ANCHOR(body_seq);
@@ -6664,10 +6886,18 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
type = nd_type(node);
line = nd_line(node);
line_node = node;
+ single_pattern = !node->nd_next;
endlabel = NEW_LABEL(line);
elselabel = NEW_LABEL(line);
+ if (single_pattern) {
+ /* allocate stack for ... */
+ ADD_INSN(head, line_node, putnil); /* key_error_key */
+ ADD_INSN(head, line_node, putnil); /* key_error_matchee */
+ ADD_INSN1(head, line_node, putobject, Qfalse); /* key_error_p */
+ ADD_INSN(head, line_node, putnil); /* error_string */
+ }
ADD_INSN(head, line_node, putnil); /* allocate stack for cached #deconstruct value */
CHECK(COMPILE(head, "case base", orig_node->nd_head));
@@ -6682,8 +6912,7 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
}
l1 = NEW_LABEL(line);
ADD_LABEL(body_seq, l1);
- ADD_INSN(body_seq, line_node, pop);
- ADD_INSN(body_seq, line_node, pop); /* discard cached #deconstruct value */
+ ADD_INSN1(body_seq, line_node, adjuststack, INT2FIX(single_pattern ? 6 : 2));
add_trace_branch_coverage(
iseq,
body_seq,
@@ -6698,10 +6927,9 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
if (pattern) {
int pat_line = nd_line(pattern);
LABEL *next_pat = NEW_LABEL(pat_line);
- ADD_INSN (cond_seq, pattern, dup);
- // NOTE: set deconstructed_pos to the current cached value location
- // (it's "under" the matchee value, so it's position is 2)
- CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, FALSE, 2));
+ ADD_INSN (cond_seq, pattern, dup); /* dup case VAL */
+ // NOTE: set base_index (it's "under" the matchee value, so it's position is 2)
+ CHECK(iseq_compile_pattern_each(iseq, cond_seq, pattern, l1, next_pat, single_pattern, false, 2, true));
ADD_LABEL(cond_seq, next_pat);
LABEL_UNREMOVABLE(next_pat);
}
@@ -6736,17 +6964,62 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
ADD_LABEL(cond_seq, elselabel);
add_trace_branch_coverage(iseq, cond_seq, orig_node, branch_id, "else", branches);
ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
- ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
- ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
- ADD_INSN(cond_seq, orig_node, pop);
- ADD_INSN(cond_seq, orig_node, pop);
- ADD_INSN(cond_seq, orig_node, pop); /* discard cached #deconstruct value */
+
+ if (single_pattern) {
+ /*
+ * if key_error_p
+ * FrozenCore.raise NoMatchingPatternKeyError.new(FrozenCore.sprintf("%p: %s", case_val, error_string), matchee: key_error_matchee, key: key_error_key)
+ * else
+ * FrozenCore.raise NoMatchingPatternError, FrozenCore.sprintf("%p: %s", case_val, error_string)
+ * end
+ */
+ LABEL *key_error, *fin;
+ struct rb_callinfo_kwarg *kw_arg;
+
+ key_error = NEW_LABEL(line);
+ fin = NEW_LABEL(line);
+
+ kw_arg = rb_xmalloc_mul_add(2, sizeof(VALUE), sizeof(struct rb_callinfo_kwarg));
+ kw_arg->keyword_len = 2;
+ kw_arg->keywords[0] = ID2SYM(rb_intern("matchee"));
+ kw_arg->keywords[1] = ID2SYM(rb_intern("key"));
+
+ ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_P + 2));
+ ADD_INSNL(cond_seq, orig_node, branchif, key_error);
+ ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
+ ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
+ ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
+ ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
+ ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
+ ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
+ ADD_INSNL(cond_seq, orig_node, jump, fin);
+
+ ADD_LABEL(cond_seq, key_error);
+ ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternKeyError);
+ ADD_INSN1(cond_seq, orig_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(cond_seq, orig_node, putobject, rb_fstring_lit("%p: %s"));
+ ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(4)); /* case VAL */
+ ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_ERROR_STRING + 6));
+ ADD_SEND(cond_seq, orig_node, id_core_sprintf, INT2FIX(3));
+ ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_MATCHEE + 4));
+ ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(CASE3_BI_OFFSET_KEY_ERROR_KEY + 5));
+ ADD_SEND_R(cond_seq, orig_node, rb_intern("new"), INT2FIX(1), NULL, INT2FIX(VM_CALL_KWARG), kw_arg);
+ ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(1));
+
+ ADD_LABEL(cond_seq, fin);
+ }
+ else {
+ ADD_INSN1(cond_seq, orig_node, putobject, rb_eNoMatchingPatternError);
+ ADD_INSN1(cond_seq, orig_node, topn, INT2FIX(2));
+ ADD_SEND(cond_seq, orig_node, id_core_raise, INT2FIX(2));
+ }
+ ADD_INSN1(cond_seq, orig_node, adjuststack, INT2FIX(single_pattern ? 7 : 3));
if (!popped) {
ADD_INSN(cond_seq, orig_node, putnil);
}
ADD_INSNL(cond_seq, orig_node, jump, endlabel);
- ADD_INSN(cond_seq, line_node, putnil);
+ ADD_INSN1(cond_seq, orig_node, dupn, INT2FIX(single_pattern ? 5 : 1));
if (popped) {
ADD_INSN(cond_seq, line_node, putnil);
}
@@ -6758,6 +7031,12 @@ compile_case3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const orig_no
return COMPILE_OK;
}
+#undef CASE3_BI_OFFSET_DECONSTRUCTED_CACHE
+#undef CASE3_BI_OFFSET_ERROR_STRING
+#undef CASE3_BI_OFFSET_KEY_ERROR_P
+#undef CASE3_BI_OFFSET_KEY_ERROR_MATCHEE
+#undef CASE3_BI_OFFSET_KEY_ERROR_KEY
+
static int
compile_loop(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
{
@@ -7838,8 +8117,842 @@ compile_call(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, co
return COMPILE_OK;
}
+static int
+compile_op_asgn1(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+{
+ const int line = nd_line(node);
+ VALUE argc;
+ unsigned int flag = 0;
+ int asgnflag = 0;
+ ID id = node->nd_mid;
+ int boff = 0;
+
+ /*
+ * a[x] (op)= y
+ *
+ * nil # nil
+ * eval a # nil a
+ * eval x # nil a x
+ * dupn 2 # nil a x a x
+ * send :[] # nil a x a[x]
+ * eval y # nil a x a[x] y
+ * send op # nil a x ret
+ * setn 3 # ret a x ret
+ * send []= # ret ?
+ * pop # ret
+ */
+
+ /*
+ * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
+ * NODE_OP_ASGN nd_recv
+ * nd_args->nd_head
+ * nd_args->nd_body
+ * nd_mid
+ */
+
+ if (!popped) {
+ ADD_INSN(ret, node, putnil);
+ }
+ asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
+ CHECK(asgnflag != -1);
+ switch (nd_type(node->nd_args->nd_head)) {
+ case NODE_ZLIST:
+ argc = INT2FIX(0);
+ break;
+ case NODE_BLOCK_PASS:
+ boff = 1;
+ /* fall through */
+ default:
+ argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
+ CHECK(!NIL_P(argc));
+ }
+ ADD_INSN1(ret, node, dupn, FIXNUM_INC(argc, 1 + boff));
+ flag |= asgnflag;
+ ADD_SEND_WITH_FLAG(ret, node, idAREF, argc, INT2FIX(flag));
+
+ if (id == idOROP || id == idANDOP) {
+ /* a[x] ||= y or a[x] &&= y
+
+ unless/if a[x]
+ a[x]= y
+ else
+ nil
+ end
+ */
+ LABEL *label = NEW_LABEL(line);
+ LABEL *lfin = NEW_LABEL(line);
+
+ ADD_INSN(ret, node, dup);
+ if (id == idOROP) {
+ ADD_INSNL(ret, node, branchif, label);
+ }
+ else { /* idANDOP */
+ ADD_INSNL(ret, node, branchunless, label);
+ }
+ ADD_INSN(ret, node, pop);
+
+ CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
+ if (!popped) {
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
+ }
+ if (flag & VM_CALL_ARGS_SPLAT) {
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ if (boff > 0) {
+ ADD_INSN1(ret, node, dupn, INT2FIX(3));
+ ADD_INSN(ret, node, swap);
+ ADD_INSN(ret, node, pop);
+ }
+ ADD_INSN(ret, node, concatarray);
+ if (boff > 0) {
+ ADD_INSN1(ret, node, setn, INT2FIX(3));
+ ADD_INSN(ret, node, pop);
+ ADD_INSN(ret, node, pop);
+ }
+ ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
+ }
+ else {
+ if (boff > 0)
+ ADD_INSN(ret, node, swap);
+ ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
+ }
+ ADD_INSN(ret, node, pop);
+ ADD_INSNL(ret, node, jump, lfin);
+ ADD_LABEL(ret, label);
+ if (!popped) {
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
+ }
+ ADD_INSN1(ret, node, adjuststack, FIXNUM_INC(argc, 2+boff));
+ ADD_LABEL(ret, lfin);
+ }
+ else {
+ CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
+ ADD_SEND(ret, node, id, INT2FIX(1));
+ if (!popped) {
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2+boff));
+ }
+ if (flag & VM_CALL_ARGS_SPLAT) {
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ if (boff > 0) {
+ ADD_INSN1(ret, node, dupn, INT2FIX(3));
+ ADD_INSN(ret, node, swap);
+ ADD_INSN(ret, node, pop);
+ }
+ ADD_INSN(ret, node, concatarray);
+ if (boff > 0) {
+ ADD_INSN1(ret, node, setn, INT2FIX(3));
+ ADD_INSN(ret, node, pop);
+ ADD_INSN(ret, node, pop);
+ }
+ ADD_SEND_WITH_FLAG(ret, node, idASET, argc, INT2FIX(flag));
+ }
+ else {
+ if (boff > 0)
+ ADD_INSN(ret, node, swap);
+ ADD_SEND_WITH_FLAG(ret, node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
+ }
+ ADD_INSN(ret, node, pop);
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_op_asgn2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+{
+ const int line = nd_line(node);
+ ID atype = node->nd_next->nd_mid;
+ ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
+ int asgnflag;
+ LABEL *lfin = NEW_LABEL(line);
+ LABEL *lcfin = NEW_LABEL(line);
+ LABEL *lskip = 0;
+ /*
+ class C; attr_accessor :c; end
+ r = C.new
+ r.a &&= v # asgn2
+
+ eval r # r
+ dup # r r
+ eval r.a # r o
+
+ # or
+ dup # r o o
+ if lcfin # r o
+ pop # r
+ eval v # r v
+ swap # v r
+ topn 1 # v r v
+ send a= # v ?
+ jump lfin # v ?
+
+ lcfin: # r o
+ swap # o r
+
+ lfin: # o ?
+ pop # o
+
+ # and
+ dup # r o o
+ unless lcfin
+ pop # r
+ eval v # r v
+ swap # v r
+ topn 1 # v r v
+ send a= # v ?
+ jump lfin # v ?
+
+ # others
+ eval v # r o v
+ send ?? # r w
+ send a= # w
+
+ */
+
+ asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
+ CHECK(asgnflag != -1);
+ if (node->nd_next->nd_aid) {
+ lskip = NEW_LABEL(line);
+ ADD_INSN(ret, node, dup);
+ ADD_INSNL(ret, node, branchnil, lskip);
+ }
+ ADD_INSN(ret, node, dup);
+ ADD_SEND_WITH_FLAG(ret, node, vid, INT2FIX(0), INT2FIX(asgnflag));
+
+ if (atype == idOROP || atype == idANDOP) {
+ ADD_INSN(ret, node, dup);
+ if (atype == idOROP) {
+ ADD_INSNL(ret, node, branchif, lcfin);
+ }
+ else { /* idANDOP */
+ ADD_INSNL(ret, node, branchunless, lcfin);
+ }
+ ADD_INSN(ret, node, pop);
+ CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
+ ADD_INSN(ret, node, swap);
+ ADD_INSN1(ret, node, topn, INT2FIX(1));
+ ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
+ ADD_INSNL(ret, node, jump, lfin);
+
+ ADD_LABEL(ret, lcfin);
+ ADD_INSN(ret, node, swap);
+
+ ADD_LABEL(ret, lfin);
+ ADD_INSN(ret, node, pop);
+ if (lskip) {
+ ADD_LABEL(ret, lskip);
+ }
+ if (popped) {
+ /* we can apply more optimize */
+ ADD_INSN(ret, node, pop);
+ }
+ }
+ else {
+ CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
+ ADD_SEND(ret, node, atype, INT2FIX(1));
+ if (!popped) {
+ ADD_INSN(ret, node, swap);
+ ADD_INSN1(ret, node, topn, INT2FIX(1));
+ }
+ ADD_SEND_WITH_FLAG(ret, node, aid, INT2FIX(1), INT2FIX(asgnflag));
+ if (lskip && popped) {
+ ADD_LABEL(ret, lskip);
+ }
+ ADD_INSN(ret, node, pop);
+ if (lskip && !popped) {
+ ADD_LABEL(ret, lskip);
+ }
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_op_cdecl(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+{
+ const int line = nd_line(node);
+ LABEL *lfin = 0;
+ LABEL *lassign = 0;
+ ID mid;
+
+ switch (nd_type(node->nd_head)) {
+ case NODE_COLON3:
+ ADD_INSN1(ret, node, putobject, rb_cObject);
+ break;
+ case NODE_COLON2:
+ CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
+ break;
+ default:
+ COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
+ ruby_node_name(nd_type(node->nd_head)));
+ return COMPILE_NG;
+ }
+ mid = node->nd_head->nd_mid;
+ /* cref */
+ if (node->nd_aid == idOROP) {
+ lassign = NEW_LABEL(line);
+ ADD_INSN(ret, node, dup); /* cref cref */
+ ADD_INSN3(ret, node, defined, INT2FIX(DEFINED_CONST_FROM),
+ ID2SYM(mid), Qtrue); /* cref bool */
+ ADD_INSNL(ret, node, branchunless, lassign); /* cref */
+ }
+ ADD_INSN(ret, node, dup); /* cref cref */
+ ADD_INSN1(ret, node, putobject, Qtrue);
+ ADD_INSN1(ret, node, getconstant, ID2SYM(mid)); /* cref obj */
+
+ if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
+ lfin = NEW_LABEL(line);
+ if (!popped) ADD_INSN(ret, node, dup); /* cref [obj] obj */
+ if (node->nd_aid == idOROP)
+ ADD_INSNL(ret, node, branchif, lfin);
+ else /* idANDOP */
+ ADD_INSNL(ret, node, branchunless, lfin);
+ /* cref [obj] */
+ if (!popped) ADD_INSN(ret, node, pop); /* cref */
+ if (lassign) ADD_LABEL(ret, lassign);
+ CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
+ /* cref value */
+ if (popped)
+ ADD_INSN1(ret, node, topn, INT2FIX(1)); /* cref value cref */
+ else {
+ ADD_INSN1(ret, node, dupn, INT2FIX(2)); /* cref value cref value */
+ ADD_INSN(ret, node, swap); /* cref value value cref */
+ }
+ ADD_INSN1(ret, node, setconstant, ID2SYM(mid)); /* cref [value] */
+ ADD_LABEL(ret, lfin); /* cref [value] */
+ if (!popped) ADD_INSN(ret, node, swap); /* [value] cref */
+ ADD_INSN(ret, node, pop); /* [value] */
+ }
+ else {
+ CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
+ /* cref obj value */
+ ADD_CALL(ret, node, node->nd_aid, INT2FIX(1));
+ /* cref value */
+ ADD_INSN(ret, node, swap); /* value cref */
+ if (!popped) {
+ ADD_INSN1(ret, node, topn, INT2FIX(1)); /* value cref value */
+ ADD_INSN(ret, node, swap); /* value value cref */
+ }
+ ADD_INSN1(ret, node, setconstant, ID2SYM(mid));
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_op_log(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
+{
+ const int line = nd_line(node);
+ LABEL *lfin = NEW_LABEL(line);
+ LABEL *lassign;
+
+ if (type == NODE_OP_ASGN_OR && nd_type(node->nd_head) != NODE_IVAR) {
+ LABEL *lfinish[2];
+ lfinish[0] = lfin;
+ lfinish[1] = 0;
+ defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
+ lassign = lfinish[1];
+ if (!lassign) {
+ lassign = NEW_LABEL(line);
+ }
+ ADD_INSNL(ret, node, branchunless, lassign);
+ }
+ else {
+ lassign = NEW_LABEL(line);
+ }
+
+ CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
+ ADD_INSN(ret, node, dup);
+
+ if (type == NODE_OP_ASGN_AND) {
+ ADD_INSNL(ret, node, branchunless, lfin);
+ }
+ else {
+ ADD_INSNL(ret, node, branchif, lfin);
+ }
+
+ ADD_INSN(ret, node, pop);
+ ADD_LABEL(ret, lassign);
+ CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value));
+ ADD_LABEL(ret, lfin);
+
+ if (popped) {
+ /* we can apply more optimize */
+ ADD_INSN(ret, node, pop);
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_super(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
+{
+ struct rb_iseq_constant_body *const body = iseq->body;
+ DECL_ANCHOR(args);
+ int argc;
+ unsigned int flag = 0;
+ struct rb_callinfo_kwarg *keywords = NULL;
+ const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
+
+ INIT_ANCHOR(args);
+ ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
+ if (type == NODE_SUPER) {
+ VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
+ CHECK(!NIL_P(vargc));
+ argc = FIX2INT(vargc);
+ }
+ else {
+ /* NODE_ZSUPER */
+ int i;
+ const rb_iseq_t *liseq = body->local_iseq;
+ const struct rb_iseq_constant_body *const local_body = liseq->body;
+ const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
+ int lvar_level = get_lvar_level(iseq);
+
+ argc = local_body->param.lead_num;
+
+ /* normal arguments */
+ for (i = 0; i < local_body->param.lead_num; i++) {
+ int idx = local_body->local_table_size - i;
+ ADD_GETLOCAL(args, node, idx, lvar_level);
+ }
+
+ if (local_body->param.flags.has_opt) {
+ /* optional arguments */
+ int j;
+ for (j = 0; j < local_body->param.opt_num; j++) {
+ int idx = local_body->local_table_size - (i + j);
+ ADD_GETLOCAL(args, node, idx, lvar_level);
+ }
+ i += j;
+ argc = i;
+ }
+ if (local_body->param.flags.has_rest) {
+ /* rest argument */
+ int idx = local_body->local_table_size - local_body->param.rest_start;
+ ADD_GETLOCAL(args, node, idx, lvar_level);
+ ADD_INSN1(args, node, splatarray, Qfalse);
+
+ argc = local_body->param.rest_start + 1;
+ flag |= VM_CALL_ARGS_SPLAT;
+ }
+ if (local_body->param.flags.has_post) {
+ /* post arguments */
+ int post_len = local_body->param.post_num;
+ int post_start = local_body->param.post_start;
+
+ if (local_body->param.flags.has_rest) {
+ int j;
+ for (j=0; j<post_len; j++) {
+ int idx = local_body->local_table_size - (post_start + j);
+ ADD_GETLOCAL(args, node, idx, lvar_level);
+ }
+ ADD_INSN1(args, node, newarray, INT2FIX(j));
+ ADD_INSN (args, node, concatarray);
+ /* argc is settled at above */
+ }
+ else {
+ int j;
+ for (j=0; j<post_len; j++) {
+ int idx = local_body->local_table_size - (post_start + j);
+ ADD_GETLOCAL(args, node, idx, lvar_level);
+ }
+ argc = post_len + post_start;
+ }
+ }
+
+ if (local_body->param.flags.has_kw) { /* TODO: support keywords */
+ int local_size = local_body->local_table_size;
+ argc++;
+
+ ADD_INSN1(args, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+
+ if (local_body->param.flags.has_kwrest) {
+ int idx = local_body->local_table_size - local_kwd->rest_start;
+ ADD_GETLOCAL(args, node, idx, lvar_level);
+ if (local_kwd->num > 0) {
+ ADD_SEND (args, node, rb_intern("dup"), INT2FIX(0));
+ flag |= VM_CALL_KW_SPLAT_MUT;
+ }
+ }
+ else {
+ ADD_INSN1(args, node, newhash, INT2FIX(0));
+ flag |= VM_CALL_KW_SPLAT_MUT;
+ }
+ for (i = 0; i < local_kwd->num; ++i) {
+ ID id = local_kwd->table[i];
+ int idx = local_size - get_local_var_idx(liseq, id);
+ ADD_INSN1(args, node, putobject, ID2SYM(id));
+ ADD_GETLOCAL(args, node, idx, lvar_level);
+ }
+ ADD_SEND(args, node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
+ if (local_body->param.flags.has_rest) {
+ ADD_INSN1(args, node, newarray, INT2FIX(1));
+ ADD_INSN (args, node, concatarray);
+ --argc;
+ }
+ flag |= VM_CALL_KW_SPLAT;
+ }
+ else if (local_body->param.flags.has_kwrest) {
+ int idx = local_body->local_table_size - local_kwd->rest_start;
+ ADD_GETLOCAL(args, node, idx, lvar_level);
+
+ if (local_body->param.flags.has_rest) {
+ ADD_INSN1(args, node, newarray, INT2FIX(1));
+ ADD_INSN (args, node, concatarray);
+ }
+ else {
+ argc++;
+ }
+ flag |= VM_CALL_KW_SPLAT;
+ }
+ }
+
+ flag |= VM_CALL_SUPER | VM_CALL_FCALL;
+ if (type == NODE_ZSUPER) flag |= VM_CALL_ZSUPER;
+ ADD_INSN(ret, node, putself);
+ ADD_SEQ(ret, args);
+ ADD_INSN2(ret, node, invokesuper,
+ new_callinfo(iseq, 0, argc, flag, keywords, parent_block != NULL),
+ parent_block);
+
+ if (popped) {
+ ADD_INSN(ret, node, pop);
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_yield(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+{
+ DECL_ANCHOR(args);
+ VALUE argc;
+ unsigned int flag = 0;
+ struct rb_callinfo_kwarg *keywords = NULL;
-static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped);
+ INIT_ANCHOR(args);
+
+ switch (iseq->body->local_iseq->body->type) {
+ case ISEQ_TYPE_TOP:
+ case ISEQ_TYPE_MAIN:
+ case ISEQ_TYPE_CLASS:
+ COMPILE_ERROR(ERROR_ARGS "Invalid yield");
+ return COMPILE_NG;
+ default: /* valid */;
+ }
+
+ if (node->nd_head) {
+ argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
+ CHECK(!NIL_P(argc));
+ }
+ else {
+ argc = INT2FIX(0);
+ }
+
+ ADD_SEQ(ret, args);
+ ADD_INSN1(ret, node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
+
+ if (popped) {
+ ADD_INSN(ret, node, pop);
+ }
+
+ int level = 0;
+ const rb_iseq_t *tmp_iseq = iseq;
+ for (; tmp_iseq != iseq->body->local_iseq; level++ ) {
+ tmp_iseq = tmp_iseq->body->parent_iseq;
+ }
+ if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
+
+ return COMPILE_OK;
+}
+
+static int
+compile_match(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const enum node_type type)
+{
+ DECL_ANCHOR(recv);
+ DECL_ANCHOR(val);
+
+ INIT_ANCHOR(recv);
+ INIT_ANCHOR(val);
+ switch ((int)type) {
+ case NODE_MATCH:
+ ADD_INSN1(recv, node, putobject, node->nd_lit);
+ ADD_INSN2(val, node, getspecial, INT2FIX(0),
+ INT2FIX(0));
+ break;
+ case NODE_MATCH2:
+ CHECK(COMPILE(recv, "receiver", node->nd_recv));
+ CHECK(COMPILE(val, "value", node->nd_value));
+ break;
+ case NODE_MATCH3:
+ CHECK(COMPILE(recv, "receiver", node->nd_value));
+ CHECK(COMPILE(val, "value", node->nd_recv));
+ break;
+ }
+
+ ADD_SEQ(ret, recv);
+ ADD_SEQ(ret, val);
+ ADD_SEND(ret, node, idEqTilde, INT2FIX(1));
+
+ if (node->nd_args) {
+ compile_named_capture_assign(iseq, ret, node->nd_args);
+ }
+
+ if (popped) {
+ ADD_INSN(ret, node, pop);
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_colon2(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+{
+ const int line = nd_line(node);
+ if (rb_is_const_id(node->nd_mid)) {
+ /* constant */
+ LABEL *lend = NEW_LABEL(line);
+ int ic_index = iseq->body->is_size++;
+
+ DECL_ANCHOR(pref);
+ DECL_ANCHOR(body);
+
+ INIT_ANCHOR(pref);
+ INIT_ANCHOR(body);
+ CHECK(compile_const_prefix(iseq, node, pref, body));
+ if (LIST_INSN_SIZE_ZERO(pref)) {
+ if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
+ ADD_INSN2(ret, node, opt_getinlinecache, lend, INT2FIX(ic_index));
+ }
+ else {
+ ADD_INSN(ret, node, putnil);
+ }
+
+ ADD_SEQ(ret, body);
+
+ if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
+ ADD_INSN1(ret, node, opt_setinlinecache, INT2FIX(ic_index));
+ ADD_LABEL(ret, lend);
+ }
+ }
+ else {
+ ADD_SEQ(ret, pref);
+ ADD_SEQ(ret, body);
+ }
+ }
+ else {
+ /* function call */
+ ADD_CALL_RECEIVER(ret, node);
+ CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
+ ADD_CALL(ret, node, node->nd_mid, INT2FIX(1));
+ }
+ if (popped) {
+ ADD_INSN(ret, node, pop);
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_colon3(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+{
+ const int line = nd_line(node);
+ LABEL *lend = NEW_LABEL(line);
+ int ic_index = iseq->body->is_size++;
+
+ debugi("colon3#nd_mid", node->nd_mid);
+
+ /* add cache insn */
+ if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
+ ADD_INSN2(ret, node, opt_getinlinecache, lend, INT2FIX(ic_index));
+ ADD_INSN(ret, node, pop);
+ }
+
+ ADD_INSN1(ret, node, putobject, rb_cObject);
+ ADD_INSN1(ret, node, putobject, Qtrue);
+ ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_mid));
+
+ if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
+ ADD_INSN1(ret, node, opt_setinlinecache, INT2FIX(ic_index));
+ ADD_LABEL(ret, lend);
+ }
+
+ if (popped) {
+ ADD_INSN(ret, node, pop);
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_dots(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped, const int excl)
+{
+ VALUE flag = INT2FIX(excl);
+ const NODE *b = node->nd_beg;
+ const NODE *e = node->nd_end;
+
+ if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
+ if (!popped) {
+ VALUE bv = nd_type(b) == NODE_LIT ? b->nd_lit : Qnil;
+ VALUE ev = nd_type(e) == NODE_LIT ? e->nd_lit : Qnil;
+ VALUE val = rb_range_new(bv, ev, excl);
+ ADD_INSN1(ret, node, putobject, val);
+ RB_OBJ_WRITTEN(iseq, Qundef, val);
+ }
+ }
+ else {
+ CHECK(COMPILE_(ret, "min", b, popped));
+ CHECK(COMPILE_(ret, "max", e, popped));
+ if (!popped) {
+ ADD_INSN1(ret, node, newrange, flag);
+ }
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_errinfo(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+{
+ if (!popped) {
+ if (iseq->body->type == ISEQ_TYPE_RESCUE) {
+ ADD_GETLOCAL(ret, node, LVAR_ERRINFO, 0);
+ }
+ else {
+ const rb_iseq_t *ip = iseq;
+ int level = 0;
+ while (ip) {
+ if (ip->body->type == ISEQ_TYPE_RESCUE) {
+ break;
+ }
+ ip = ip->body->parent_iseq;
+ level++;
+ }
+ if (ip) {
+ ADD_GETLOCAL(ret, node, LVAR_ERRINFO, level);
+ }
+ else {
+ ADD_INSN(ret, node, putnil);
+ }
+ }
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_kw_arg(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+{
+ struct rb_iseq_constant_body *const body = iseq->body;
+ LABEL *end_label = NEW_LABEL(nd_line(node));
+ const NODE *default_value = node->nd_body->nd_value;
+
+ if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
+ /* required argument. do nothing */
+ COMPILE_ERROR(ERROR_ARGS "unreachable");
+ return COMPILE_NG;
+ }
+ else if (nd_type(default_value) == NODE_LIT ||
+ nd_type(default_value) == NODE_NIL ||
+ nd_type(default_value) == NODE_TRUE ||
+ nd_type(default_value) == NODE_FALSE) {
+ COMPILE_ERROR(ERROR_ARGS "unreachable");
+ return COMPILE_NG;
+ }
+ else {
+ /* if keywordcheck(_kw_bits, nth_keyword)
+ * kw = default_value
+ * end
+ */
+ int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
+ int keyword_idx = body->param.keyword->num;
+
+ ADD_INSN2(ret, node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
+ ADD_INSNL(ret, node, branchif, end_label);
+ CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
+ ADD_LABEL(ret, end_label);
+ }
+ return COMPILE_OK;
+}
+
+static int
+compile_attrasgn(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
+{
+ DECL_ANCHOR(recv);
+ DECL_ANCHOR(args);
+ unsigned int flag = 0;
+ ID mid = node->nd_mid;
+ VALUE argc;
+ LABEL *else_label = NULL;
+ VALUE branches = Qfalse;
+
+ /* optimization shortcut
+ * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
+ */
+ if (mid == idASET && !private_recv_p(node) && node->nd_args &&
+ nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 2 &&
+ nd_type(node->nd_args->nd_head) == NODE_STR &&
+ ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
+ !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
+ ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
+ {
+ VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
+ CHECK(COMPILE(ret, "recv", node->nd_recv));
+ CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
+ if (!popped) {
+ ADD_INSN(ret, node, swap);
+ ADD_INSN1(ret, node, topn, INT2FIX(1));
+ }
+ ADD_INSN2(ret, node, opt_aset_with, str,
+ new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
+ RB_OBJ_WRITTEN(iseq, Qundef, str);
+ ADD_INSN(ret, node, pop);
+ return COMPILE_OK;
+ }
+
+ INIT_ANCHOR(recv);
+ INIT_ANCHOR(args);
+ argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
+ CHECK(!NIL_P(argc));
+
+ int asgnflag = COMPILE_RECV(recv, "recv", node);
+ CHECK(asgnflag != -1);
+ flag |= (unsigned int)asgnflag;
+
+ debugp_param("argc", argc);
+ debugp_param("nd_mid", ID2SYM(mid));
+
+ if (!rb_is_attrset_id(mid)) {
+ /* safe nav attr */
+ mid = rb_id_attrset(mid);
+ else_label = qcall_branch_start(iseq, recv, &branches, node, node);
+ }
+ if (!popped) {
+ ADD_INSN(ret, node, putnil);
+ ADD_SEQ(ret, recv);
+ ADD_SEQ(ret, args);
+
+ if (flag & VM_CALL_ARGS_BLOCKARG) {
+ ADD_INSN1(ret, node, topn, INT2FIX(1));
+ if (flag & VM_CALL_ARGS_SPLAT) {
+ ADD_INSN1(ret, node, putobject, INT2FIX(-1));
+ ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
+ }
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 3));
+ ADD_INSN (ret, node, pop);
+ }
+ else if (flag & VM_CALL_ARGS_SPLAT) {
+ ADD_INSN(ret, node, dup);
+ ADD_INSN1(ret, node, putobject, INT2FIX(-1));
+ ADD_SEND_WITH_FLAG(ret, node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 2));
+ ADD_INSN (ret, node, pop);
+ }
+ else {
+ ADD_INSN1(ret, node, setn, FIXNUM_INC(argc, 1));
+ }
+ }
+ else {
+ ADD_SEQ(ret, recv);
+ ADD_SEQ(ret, args);
+ }
+ ADD_SEND_WITH_FLAG(ret, node, mid, argc, INT2FIX(flag));
+ qcall_branch_end(iseq, ret, else_label, branches, node, node);
+ ADD_INSN(ret, node, pop);
+ return COMPILE_OK;
+}
+
+static int iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped);
/**
compile each node
@@ -7864,23 +8977,9 @@ iseq_compile_each(rb_iseq_t *iseq, LINK_ANCHOR *ret, const NODE *node, int poppe
}
static int
-check_yield_place(const rb_iseq_t *iseq)
-{
- switch (iseq->body->local_iseq->body->type) {
- case ISEQ_TYPE_TOP:
- case ISEQ_TYPE_MAIN:
- case ISEQ_TYPE_CLASS:
- return FALSE;
- default:
- return TRUE;
- }
-}
-
-static int
-iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, int popped)
+iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *const node, int popped)
{
const int line = (int)nd_line(node);
- const NODE *line_node = node;
const enum node_type type = nd_type(node);
struct rb_iseq_constant_body *const body = iseq->body;
@@ -7903,17 +9002,9 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
#define BEFORE_RETURN debug_node_end()
switch (type) {
- case NODE_BLOCK:{
- while (node && nd_type(node) == NODE_BLOCK) {
- CHECK(COMPILE_(ret, "BLOCK body", node->nd_head,
- (node->nd_next ? 1 : popped)));
- node = node->nd_next;
- }
- if (node) {
- CHECK(COMPILE_(ret, "BLOCK next", node->nd_next, popped));
- }
+ case NODE_BLOCK:
+ CHECK(compile_block(iseq, ret, node, popped));
break;
- }
case NODE_IF:
case NODE_UNLESS:
CHECK(compile_if(iseq, ret, node, popped, type));
@@ -7969,16 +9060,16 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
LABEL *end_label = NEW_LABEL(line);
CHECK(COMPILE(ret, "nd_1st", node->nd_1st));
if (!popped) {
- ADD_INSN(ret, line_node, dup);
+ ADD_INSN(ret, node, dup);
}
if (type == NODE_AND) {
- ADD_INSNL(ret, line_node, branchunless, end_label);
+ ADD_INSNL(ret, node, branchunless, end_label);
}
else {
- ADD_INSNL(ret, line_node, branchif, end_label);
+ ADD_INSNL(ret, node, branchif, end_label);
}
if (!popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
CHECK(COMPILE_(ret, "nd_2nd", node->nd_2nd, popped));
ADD_LABEL(ret, end_label);
@@ -7998,9 +9089,9 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
CHECK(COMPILE(ret, "rvalue", node->nd_value));
if (!popped) {
- ADD_INSN(ret, line_node, dup);
+ ADD_INSN(ret, node, dup);
}
- ADD_SETLOCAL(ret, line_node, idx, get_lvar_level(iseq));
+ ADD_SETLOCAL(ret, node, idx, get_lvar_level(iseq));
break;
}
case NODE_DASGN:
@@ -8011,7 +9102,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
debugi("dassn id", rb_id2str(id) ? id : '*');
if (!popped) {
- ADD_INSN(ret, line_node, dup);
+ ADD_INSN(ret, node, dup);
}
idx = get_dyna_var_idx(iseq, id, &lv, &ls);
@@ -8021,24 +9112,24 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
rb_id2str(id));
goto ng;
}
- ADD_SETLOCAL(ret, line_node, ls - idx, lv);
+ ADD_SETLOCAL(ret, node, ls - idx, lv);
break;
}
case NODE_GASGN:{
CHECK(COMPILE(ret, "lvalue", node->nd_value));
if (!popped) {
- ADD_INSN(ret, line_node, dup);
+ ADD_INSN(ret, node, dup);
}
- ADD_INSN1(ret, line_node, setglobal, ID2SYM(node->nd_entry));
+ ADD_INSN1(ret, node, setglobal, ID2SYM(node->nd_entry));
break;
}
case NODE_IASGN:{
CHECK(COMPILE(ret, "lvalue", node->nd_value));
if (!popped) {
- ADD_INSN(ret, line_node, dup);
+ ADD_INSN(ret, node, dup);
}
- ADD_INSN2(ret, line_node, setinstancevariable,
+ ADD_INSN2(ret, node, setinstancevariable,
ID2SYM(node->nd_vid),
get_ivar_ic_value(iseq,node->nd_vid));
break;
@@ -8047,530 +9138,66 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
CHECK(COMPILE(ret, "lvalue", node->nd_value));
if (!popped) {
- ADD_INSN(ret, line_node, dup);
+ ADD_INSN(ret, node, dup);
}
if (node->nd_vid) {
- ADD_INSN1(ret, line_node, putspecialobject,
+ ADD_INSN1(ret, node, putspecialobject,
INT2FIX(VM_SPECIAL_OBJECT_CONST_BASE));
- ADD_INSN1(ret, line_node, setconstant, ID2SYM(node->nd_vid));
+ ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_vid));
}
else {
compile_cpath(ret, iseq, node->nd_else);
- ADD_INSN1(ret, line_node, setconstant, ID2SYM(node->nd_else->nd_mid));
+ ADD_INSN1(ret, node, setconstant, ID2SYM(node->nd_else->nd_mid));
}
break;
}
case NODE_CVASGN:{
CHECK(COMPILE(ret, "cvasgn val", node->nd_value));
if (!popped) {
- ADD_INSN(ret, line_node, dup);
+ ADD_INSN(ret, node, dup);
}
- ADD_INSN1(ret, line_node, setclassvariable,
- ID2SYM(node->nd_vid));
+ ADD_INSN2(ret, node, setclassvariable,
+ ID2SYM(node->nd_vid),
+ get_ivar_ic_value(iseq,node->nd_vid));
break;
}
- case NODE_OP_ASGN1: {
- VALUE argc;
- unsigned int flag = 0;
- int asgnflag = 0;
- ID id = node->nd_mid;
- int boff = 0;
-
- /*
- * a[x] (op)= y
- *
- * nil # nil
- * eval a # nil a
- * eval x # nil a x
- * dupn 2 # nil a x a x
- * send :[] # nil a x a[x]
- * eval y # nil a x a[x] y
- * send op # nil a x ret
- * setn 3 # ret a x ret
- * send []= # ret ?
- * pop # ret
- */
-
- /*
- * nd_recv[nd_args->nd_body] (nd_mid)= nd_args->nd_head;
- * NODE_OP_ASGN nd_recv
- * nd_args->nd_head
- * nd_args->nd_body
- * nd_mid
- */
-
- if (!popped) {
- ADD_INSN(ret, line_node, putnil);
- }
- asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN1 recv", node);
- CHECK(asgnflag != -1);
- switch (nd_type(node->nd_args->nd_head)) {
- case NODE_ZLIST:
- argc = INT2FIX(0);
- break;
- case NODE_BLOCK_PASS:
- boff = 1;
- /* fall through */
- default:
- argc = setup_args(iseq, ret, node->nd_args->nd_head, &flag, NULL);
- CHECK(!NIL_P(argc));
- }
- ADD_INSN1(ret, line_node, dupn, FIXNUM_INC(argc, 1 + boff));
- flag |= asgnflag;
- ADD_SEND_WITH_FLAG(ret, line_node, idAREF, argc, INT2FIX(flag));
-
- if (id == idOROP || id == idANDOP) {
- /* a[x] ||= y or a[x] &&= y
-
- unless/if a[x]
- a[x]= y
- else
- nil
- end
- */
- LABEL *label = NEW_LABEL(line);
- LABEL *lfin = NEW_LABEL(line);
-
- ADD_INSN(ret, line_node, dup);
- if (id == idOROP) {
- ADD_INSNL(ret, line_node, branchif, label);
- }
- else { /* idANDOP */
- ADD_INSNL(ret, line_node, branchunless, label);
- }
- ADD_INSN(ret, line_node, pop);
-
- CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
- if (!popped) {
- ADD_INSN1(ret, line_node, setn, FIXNUM_INC(argc, 2+boff));
- }
- if (flag & VM_CALL_ARGS_SPLAT) {
- ADD_INSN1(ret, line_node, newarray, INT2FIX(1));
- if (boff > 0) {
- ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
- ADD_INSN(ret, line_node, swap);
- ADD_INSN(ret, line_node, pop);
- }
- ADD_INSN(ret, line_node, concatarray);
- if (boff > 0) {
- ADD_INSN1(ret, line_node, setn, INT2FIX(3));
- ADD_INSN(ret, line_node, pop);
- ADD_INSN(ret, line_node, pop);
- }
- ADD_SEND_WITH_FLAG(ret, line_node, idASET, argc, INT2FIX(flag));
- }
- else {
- if (boff > 0)
- ADD_INSN(ret, line_node, swap);
- ADD_SEND_WITH_FLAG(ret, line_node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
- }
- ADD_INSN(ret, line_node, pop);
- ADD_INSNL(ret, line_node, jump, lfin);
- ADD_LABEL(ret, label);
- if (!popped) {
- ADD_INSN1(ret, line_node, setn, FIXNUM_INC(argc, 2+boff));
- }
- ADD_INSN1(ret, line_node, adjuststack, FIXNUM_INC(argc, 2+boff));
- ADD_LABEL(ret, lfin);
- }
- else {
- CHECK(COMPILE(ret, "NODE_OP_ASGN1 args->body: ", node->nd_args->nd_body));
- ADD_SEND(ret, line_node, id, INT2FIX(1));
- if (!popped) {
- ADD_INSN1(ret, line_node, setn, FIXNUM_INC(argc, 2+boff));
- }
- if (flag & VM_CALL_ARGS_SPLAT) {
- ADD_INSN1(ret, line_node, newarray, INT2FIX(1));
- if (boff > 0) {
- ADD_INSN1(ret, line_node, dupn, INT2FIX(3));
- ADD_INSN(ret, line_node, swap);
- ADD_INSN(ret, line_node, pop);
- }
- ADD_INSN(ret, line_node, concatarray);
- if (boff > 0) {
- ADD_INSN1(ret, line_node, setn, INT2FIX(3));
- ADD_INSN(ret, line_node, pop);
- ADD_INSN(ret, line_node, pop);
- }
- ADD_SEND_WITH_FLAG(ret, line_node, idASET, argc, INT2FIX(flag));
- }
- else {
- if (boff > 0)
- ADD_INSN(ret, line_node, swap);
- ADD_SEND_WITH_FLAG(ret, line_node, idASET, FIXNUM_INC(argc, 1), INT2FIX(flag));
- }
- ADD_INSN(ret, line_node, pop);
- }
-
+ case NODE_OP_ASGN1:
+ CHECK(compile_op_asgn1(iseq, ret, node, popped));
break;
- }
- case NODE_OP_ASGN2:{
- ID atype = node->nd_next->nd_mid;
- ID vid = node->nd_next->nd_vid, aid = rb_id_attrset(vid);
- int asgnflag;
- LABEL *lfin = NEW_LABEL(line);
- LABEL *lcfin = NEW_LABEL(line);
- LABEL *lskip = 0;
- /*
- class C; attr_accessor :c; end
- r = C.new
- r.a &&= v # asgn2
-
- eval r # r
- dup # r r
- eval r.a # r o
-
- # or
- dup # r o o
- if lcfin # r o
- pop # r
- eval v # r v
- swap # v r
- topn 1 # v r v
- send a= # v ?
- jump lfin # v ?
-
- lcfin: # r o
- swap # o r
-
- lfin: # o ?
- pop # o
-
- # and
- dup # r o o
- unless lcfin
- pop # r
- eval v # r v
- swap # v r
- topn 1 # v r v
- send a= # v ?
- jump lfin # v ?
-
- # others
- eval v # r o v
- send ?? # r w
- send a= # w
-
- */
-
- asgnflag = COMPILE_RECV(ret, "NODE_OP_ASGN2#recv", node);
- CHECK(asgnflag != -1);
- if (node->nd_next->nd_aid) {
- lskip = NEW_LABEL(line);
- ADD_INSN(ret, line_node, dup);
- ADD_INSNL(ret, line_node, branchnil, lskip);
- }
- ADD_INSN(ret, line_node, dup);
- ADD_SEND_WITH_FLAG(ret, line_node, vid, INT2FIX(0), INT2FIX(asgnflag));
-
- if (atype == idOROP || atype == idANDOP) {
- ADD_INSN(ret, line_node, dup);
- if (atype == idOROP) {
- ADD_INSNL(ret, line_node, branchif, lcfin);
- }
- else { /* idANDOP */
- ADD_INSNL(ret, line_node, branchunless, lcfin);
- }
- ADD_INSN(ret, line_node, pop);
- CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
- ADD_INSN(ret, line_node, swap);
- ADD_INSN1(ret, line_node, topn, INT2FIX(1));
- ADD_SEND_WITH_FLAG(ret, line_node, aid, INT2FIX(1), INT2FIX(asgnflag));
- ADD_INSNL(ret, line_node, jump, lfin);
-
- ADD_LABEL(ret, lcfin);
- ADD_INSN(ret, line_node, swap);
-
- ADD_LABEL(ret, lfin);
- ADD_INSN(ret, line_node, pop);
- if (lskip) {
- ADD_LABEL(ret, lskip);
- }
- if (popped) {
- /* we can apply more optimize */
- ADD_INSN(ret, line_node, pop);
- }
- }
- else {
- CHECK(COMPILE(ret, "NODE_OP_ASGN2 val", node->nd_value));
- ADD_SEND(ret, line_node, atype, INT2FIX(1));
- if (!popped) {
- ADD_INSN(ret, line_node, swap);
- ADD_INSN1(ret, line_node, topn, INT2FIX(1));
- }
- ADD_SEND_WITH_FLAG(ret, line_node, aid, INT2FIX(1), INT2FIX(asgnflag));
- if (lskip && popped) {
- ADD_LABEL(ret, lskip);
- }
- ADD_INSN(ret, line_node, pop);
- if (lskip && !popped) {
- ADD_LABEL(ret, lskip);
- }
- }
+ case NODE_OP_ASGN2:
+ CHECK(compile_op_asgn2(iseq, ret, node, popped));
break;
- }
- case NODE_OP_CDECL: {
- LABEL *lfin = 0;
- LABEL *lassign = 0;
- ID mid;
-
- switch (nd_type(node->nd_head)) {
- case NODE_COLON3:
- ADD_INSN1(ret, line_node, putobject, rb_cObject);
- break;
- case NODE_COLON2:
- CHECK(COMPILE(ret, "NODE_OP_CDECL/colon2#nd_head", node->nd_head->nd_head));
- break;
- default:
- COMPILE_ERROR(ERROR_ARGS "%s: invalid node in NODE_OP_CDECL",
- ruby_node_name(nd_type(node->nd_head)));
- goto ng;
- }
- mid = node->nd_head->nd_mid;
- /* cref */
- if (node->nd_aid == idOROP) {
- lassign = NEW_LABEL(line);
- ADD_INSN(ret, line_node, dup); /* cref cref */
- ADD_INSN3(ret, line_node, defined, INT2FIX(DEFINED_CONST_FROM),
- ID2SYM(mid), Qtrue); /* cref bool */
- ADD_INSNL(ret, line_node, branchunless, lassign); /* cref */
- }
- ADD_INSN(ret, line_node, dup); /* cref cref */
- ADD_INSN1(ret, line_node, putobject, Qtrue);
- ADD_INSN1(ret, line_node, getconstant, ID2SYM(mid)); /* cref obj */
-
- if (node->nd_aid == idOROP || node->nd_aid == idANDOP) {
- lfin = NEW_LABEL(line);
- if (!popped) ADD_INSN(ret, line_node, dup); /* cref [obj] obj */
- if (node->nd_aid == idOROP)
- ADD_INSNL(ret, line_node, branchif, lfin);
- else /* idANDOP */
- ADD_INSNL(ret, line_node, branchunless, lfin);
- /* cref [obj] */
- if (!popped) ADD_INSN(ret, line_node, pop); /* cref */
- if (lassign) ADD_LABEL(ret, lassign);
- CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
- /* cref value */
- if (popped)
- ADD_INSN1(ret, line_node, topn, INT2FIX(1)); /* cref value cref */
- else {
- ADD_INSN1(ret, line_node, dupn, INT2FIX(2)); /* cref value cref value */
- ADD_INSN(ret, line_node, swap); /* cref value value cref */
- }
- ADD_INSN1(ret, line_node, setconstant, ID2SYM(mid)); /* cref [value] */
- ADD_LABEL(ret, lfin); /* cref [value] */
- if (!popped) ADD_INSN(ret, line_node, swap); /* [value] cref */
- ADD_INSN(ret, line_node, pop); /* [value] */
- }
- else {
- CHECK(COMPILE(ret, "NODE_OP_CDECL#nd_value", node->nd_value));
- /* cref obj value */
- ADD_CALL(ret, line_node, node->nd_aid, INT2FIX(1));
- /* cref value */
- ADD_INSN(ret, line_node, swap); /* value cref */
- if (!popped) {
- ADD_INSN1(ret, line_node, topn, INT2FIX(1)); /* value cref value */
- ADD_INSN(ret, line_node, swap); /* value value cref */
- }
- ADD_INSN1(ret, line_node, setconstant, ID2SYM(mid));
- }
+ case NODE_OP_CDECL:
+ CHECK(compile_op_cdecl(iseq, ret, node, popped));
break;
- }
case NODE_OP_ASGN_AND:
- case NODE_OP_ASGN_OR:{
- LABEL *lfin = NEW_LABEL(line);
- LABEL *lassign;
-
- if (nd_type(node) == NODE_OP_ASGN_OR && nd_type(node->nd_head) != NODE_IVAR) {
- LABEL *lfinish[2];
- lfinish[0] = lfin;
- lfinish[1] = 0;
- defined_expr(iseq, ret, node->nd_head, lfinish, Qfalse);
- lassign = lfinish[1];
- if (!lassign) {
- lassign = NEW_LABEL(line);
- }
- ADD_INSNL(ret, line_node, branchunless, lassign);
- }
- else {
- lassign = NEW_LABEL(line);
- }
-
- CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_head", node->nd_head));
- ADD_INSN(ret, line_node, dup);
-
- if (nd_type(node) == NODE_OP_ASGN_AND) {
- ADD_INSNL(ret, line_node, branchunless, lfin);
- }
- else {
- ADD_INSNL(ret, line_node, branchif, lfin);
- }
-
- ADD_INSN(ret, line_node, pop);
- ADD_LABEL(ret, lassign);
- CHECK(COMPILE(ret, "NODE_OP_ASGN_AND/OR#nd_value", node->nd_value));
- ADD_LABEL(ret, lfin);
-
- if (popped) {
- /* we can apply more optimize */
- ADD_INSN(ret, line_node, pop);
- }
+ case NODE_OP_ASGN_OR:
+ CHECK(compile_op_log(iseq, ret, node, popped, type));
break;
- }
case NODE_CALL: /* obj.foo */
case NODE_OPCALL: /* foo[] */
- if (compile_call_precheck_freeze(iseq, ret, node, line_node, popped) == TRUE) {
+ if (compile_call_precheck_freeze(iseq, ret, node, node, popped) == TRUE) {
break;
}
case NODE_QCALL: /* obj&.foo */
case NODE_FCALL: /* foo() */
case NODE_VCALL: /* foo (variable or call) */
- if (compile_call(iseq, ret, node, type, line_node, popped, false) == COMPILE_NG) {
+ if (compile_call(iseq, ret, node, type, node, popped, false) == COMPILE_NG) {
goto ng;
}
break;
case NODE_SUPER:
- case NODE_ZSUPER:{
- DECL_ANCHOR(args);
- int argc;
- unsigned int flag = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
- const rb_iseq_t *parent_block = ISEQ_COMPILE_DATA(iseq)->current_block;
-
- INIT_ANCHOR(args);
- ISEQ_COMPILE_DATA(iseq)->current_block = NULL;
- if (type == NODE_SUPER) {
- VALUE vargc = setup_args(iseq, args, node->nd_args, &flag, &keywords);
- CHECK(!NIL_P(vargc));
- argc = FIX2INT(vargc);
- }
- else {
- /* NODE_ZSUPER */
- int i;
- const rb_iseq_t *liseq = body->local_iseq;
- const struct rb_iseq_constant_body *const local_body = liseq->body;
- const struct rb_iseq_param_keyword *const local_kwd = local_body->param.keyword;
- int lvar_level = get_lvar_level(iseq);
-
- argc = local_body->param.lead_num;
-
- /* normal arguments */
- for (i = 0; i < local_body->param.lead_num; i++) {
- int idx = local_body->local_table_size - i;
- ADD_GETLOCAL(args, line_node, idx, lvar_level);
- }
-
- if (local_body->param.flags.has_opt) {
- /* optional arguments */
- int j;
- for (j = 0; j < local_body->param.opt_num; j++) {
- int idx = local_body->local_table_size - (i + j);
- ADD_GETLOCAL(args, line_node, idx, lvar_level);
- }
- i += j;
- argc = i;
- }
- if (local_body->param.flags.has_rest) {
- /* rest argument */
- int idx = local_body->local_table_size - local_body->param.rest_start;
-
- ADD_GETLOCAL(args, line_node, idx, lvar_level);
- ADD_INSN1(args, line_node, splatarray, Qfalse);
-
- argc = local_body->param.rest_start + 1;
- flag |= VM_CALL_ARGS_SPLAT;
- }
- if (local_body->param.flags.has_post) {
- /* post arguments */
- int post_len = local_body->param.post_num;
- int post_start = local_body->param.post_start;
-
- if (local_body->param.flags.has_rest) {
- int j;
- for (j=0; j<post_len; j++) {
- int idx = local_body->local_table_size - (post_start + j);
- ADD_GETLOCAL(args, line_node, idx, lvar_level);
- }
- ADD_INSN1(args, line_node, newarray, INT2FIX(j));
- ADD_INSN (args, line_node, concatarray);
- /* argc is settled at above */
- }
- else {
- int j;
- for (j=0; j<post_len; j++) {
- int idx = local_body->local_table_size - (post_start + j);
- ADD_GETLOCAL(args, line_node, idx, lvar_level);
- }
- argc = post_len + post_start;
- }
- }
-
- if (local_body->param.flags.has_kw) { /* TODO: support keywords */
- int local_size = local_body->local_table_size;
- argc++;
-
- ADD_INSN1(args, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
-
- if (local_body->param.flags.has_kwrest) {
- int idx = local_body->local_table_size - local_kwd->rest_start;
- ADD_GETLOCAL(args, line_node, idx, lvar_level);
- if (local_kwd->num > 0) {
- ADD_SEND(args, line_node, rb_intern("dup"), INT2FIX(0));
- flag |= VM_CALL_KW_SPLAT_MUT;
- }
- }
- else {
- ADD_INSN1(args, line_node, newhash, INT2FIX(0));
- flag |= VM_CALL_KW_SPLAT_MUT;
- }
- for (i = 0; i < local_kwd->num; ++i) {
- ID id = local_kwd->table[i];
- int idx = local_size - get_local_var_idx(liseq, id);
- ADD_INSN1(args, line_node, putobject, ID2SYM(id));
- ADD_GETLOCAL(args, line_node, idx, lvar_level);
- }
- ADD_SEND(args, line_node, id_core_hash_merge_ptr, INT2FIX(i * 2 + 1));
- if (local_body->param.flags.has_rest) {
- ADD_INSN1(args, line_node, newarray, INT2FIX(1));
- ADD_INSN (args, line_node, concatarray);
- --argc;
- }
- flag |= VM_CALL_KW_SPLAT;
- }
- else if (local_body->param.flags.has_kwrest) {
- int idx = local_body->local_table_size - local_kwd->rest_start;
- ADD_GETLOCAL(args, line_node, idx, lvar_level);
-
- if (local_body->param.flags.has_rest) {
- ADD_INSN1(args, line_node, newarray, INT2FIX(1));
- ADD_INSN (args, line_node, concatarray);
- }
- else {
- argc++;
- }
- flag |= VM_CALL_KW_SPLAT;
- }
- }
-
- ADD_INSN(ret, line_node, putself);
- ADD_SEQ(ret, args);
- ADD_INSN2(ret, line_node, invokesuper,
- new_callinfo(iseq, 0, argc, flag | VM_CALL_SUPER | (type == NODE_ZSUPER ? VM_CALL_ZSUPER : 0) | VM_CALL_FCALL, keywords, parent_block != NULL),
- parent_block);
-
- if (popped) {
- ADD_INSN(ret, line_node, pop);
- }
+ case NODE_ZSUPER:
+ CHECK(compile_super(iseq, ret, node, popped, type));
break;
- }
case NODE_LIST:{
CHECK(compile_array(iseq, ret, node, popped) >= 0);
break;
}
case NODE_ZLIST:{
if (!popped) {
- ADD_INSN1(ret, line_node, newarray, INT2FIX(0));
+ ADD_INSN1(ret, node, newarray, INT2FIX(0));
}
break;
}
@@ -8583,7 +9210,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
CHECK(COMPILE(ret, "values item", n->nd_head));
n = n->nd_next;
}
- ADD_INSN1(ret, line_node, newarray, INT2FIX(node->nd_alen));
+ ADD_INSN1(ret, node, newarray, INT2FIX(node->nd_alen));
break;
}
case NODE_HASH:
@@ -8592,45 +9219,12 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
case NODE_RETURN:
CHECK(compile_return(iseq, ret, node, popped));
break;
- case NODE_YIELD:{
- DECL_ANCHOR(args);
- VALUE argc;
- unsigned int flag = 0;
- struct rb_callinfo_kwarg *keywords = NULL;
-
- INIT_ANCHOR(args);
-
- if (check_yield_place(iseq) == FALSE) {
- COMPILE_ERROR(ERROR_ARGS "Invalid yield");
- goto ng;
- }
-
- if (node->nd_head) {
- argc = setup_args(iseq, args, node->nd_head, &flag, &keywords);
- CHECK(!NIL_P(argc));
- }
- else {
- argc = INT2FIX(0);
- }
-
- ADD_SEQ(ret, args);
- ADD_INSN1(ret, line_node, invokeblock, new_callinfo(iseq, 0, FIX2INT(argc), flag, keywords, FALSE));
-
- if (popped) {
- ADD_INSN(ret, line_node, pop);
- }
-
- int level = 0;
- const rb_iseq_t *tmp_iseq = iseq;
- for (; tmp_iseq != iseq->body->local_iseq; level++ ) {
- tmp_iseq = tmp_iseq->body->parent_iseq;
- }
- if (level > 0) access_outer_variables(iseq, level, rb_intern("yield"), true);
+ case NODE_YIELD:
+ CHECK(compile_yield(iseq, ret, node, popped));
break;
- }
case NODE_LVAR:{
if (!popped) {
- compile_lvar(iseq, ret, line_node, node->nd_vid);
+ compile_lvar(iseq, ret, node, node->nd_vid);
}
break;
}
@@ -8644,21 +9238,21 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
rb_id2str(node->nd_vid));
goto ng;
}
- ADD_GETLOCAL(ret, line_node, ls - idx, lv);
+ ADD_GETLOCAL(ret, node, ls - idx, lv);
}
break;
}
case NODE_GVAR:{
- ADD_INSN1(ret, line_node, getglobal, ID2SYM(node->nd_entry));
+ ADD_INSN1(ret, node, getglobal, ID2SYM(node->nd_entry));
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
case NODE_IVAR:{
debugi("nd_vid", node->nd_vid);
if (!popped) {
- ADD_INSN2(ret, line_node, getinstancevariable,
+ ADD_INSN2(ret, node, getinstancevariable,
ID2SYM(node->nd_vid),
get_ivar_ic_value(iseq,node->nd_vid));
}
@@ -8671,89 +9265,58 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
LABEL *lend = NEW_LABEL(line);
int ic_index = body->is_size++;
- ADD_INSN2(ret, line_node, opt_getinlinecache, lend, INT2FIX(ic_index));
- ADD_INSN1(ret, line_node, putobject, Qtrue);
- ADD_INSN1(ret, line_node, getconstant, ID2SYM(node->nd_vid));
- ADD_INSN1(ret, line_node, opt_setinlinecache, INT2FIX(ic_index));
+ ADD_INSN2(ret, node, opt_getinlinecache, lend, INT2FIX(ic_index));
+ ADD_INSN1(ret, node, putobject, Qtrue);
+ ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_vid));
+ ADD_INSN1(ret, node, opt_setinlinecache, INT2FIX(ic_index));
ADD_LABEL(ret, lend);
}
else {
- ADD_INSN(ret, line_node, putnil);
- ADD_INSN1(ret, line_node, putobject, Qtrue);
- ADD_INSN1(ret, line_node, getconstant, ID2SYM(node->nd_vid));
+ ADD_INSN(ret, node, putnil);
+ ADD_INSN1(ret, node, putobject, Qtrue);
+ ADD_INSN1(ret, node, getconstant, ID2SYM(node->nd_vid));
}
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
case NODE_CVAR:{
if (!popped) {
- ADD_INSN1(ret, line_node, getclassvariable,
- ID2SYM(node->nd_vid));
+ ADD_INSN2(ret, node, getclassvariable,
+ ID2SYM(node->nd_vid),
+ get_ivar_ic_value(iseq,node->nd_vid));
}
break;
}
case NODE_NTH_REF:{
if (!popped) {
if (!node->nd_nth) {
- ADD_INSN(ret, line_node, putnil);
+ ADD_INSN(ret, node, putnil);
break;
}
- ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */,
+ ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
INT2FIX(node->nd_nth << 1));
}
break;
}
case NODE_BACK_REF:{
if (!popped) {
- ADD_INSN2(ret, line_node, getspecial, INT2FIX(1) /* '~' */,
+ ADD_INSN2(ret, node, getspecial, INT2FIX(1) /* '~' */,
INT2FIX(0x01 | (node->nd_nth << 1)));
}
break;
}
case NODE_MATCH:
case NODE_MATCH2:
- case NODE_MATCH3:{
- DECL_ANCHOR(recv);
- DECL_ANCHOR(val);
-
- INIT_ANCHOR(recv);
- INIT_ANCHOR(val);
- switch (nd_type(node)) {
- case NODE_MATCH:
- ADD_INSN1(recv, line_node, putobject, node->nd_lit);
- ADD_INSN2(val, line_node, getspecial, INT2FIX(0),
- INT2FIX(0));
- break;
- case NODE_MATCH2:
- CHECK(COMPILE(recv, "receiver", node->nd_recv));
- CHECK(COMPILE(val, "value", node->nd_value));
- break;
- case NODE_MATCH3:
- CHECK(COMPILE(recv, "receiver", node->nd_value));
- CHECK(COMPILE(val, "value", node->nd_recv));
- break;
- }
-
- ADD_SEQ(ret, recv);
- ADD_SEQ(ret, val);
- ADD_SEND(ret, line_node, idEqTilde, INT2FIX(1));
-
- if (node->nd_args) {
- compile_named_capture_assign(iseq, ret, node->nd_args);
- }
-
- if (popped) {
- ADD_INSN(ret, line_node, pop);
- }
+ case NODE_MATCH3:
+ CHECK(compile_match(iseq, ret, node, popped, type));
break;
- }
case NODE_LIT:{
debugp_param("lit", node->nd_lit);
if (!popped) {
- ADD_INSN1(ret, line_node, putobject, node->nd_lit);
+ ADD_INSN1(ret, node, putobject, node->nd_lit);
RB_OBJ_WRITTEN(iseq, Qundef, node->nd_lit);
}
break;
@@ -8764,7 +9327,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
VALUE lit = node->nd_lit;
if (!ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal) {
lit = rb_fstring(lit);
- ADD_INSN1(ret, line_node, putstring, lit);
+ ADD_INSN1(ret, node, putstring, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
else {
@@ -8777,7 +9340,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
else {
lit = rb_fstring(lit);
}
- ADD_INSN1(ret, line_node, putobject, lit);
+ ADD_INSN1(ret, node, putobject, lit);
RB_OBJ_WRITTEN(iseq, Qundef, lit);
}
}
@@ -8787,29 +9350,29 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
compile_dstr(iseq, ret, node);
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
case NODE_XSTR:{
- ADD_CALL_RECEIVER(ret, line_node);
+ ADD_CALL_RECEIVER(ret, node);
VALUE str = rb_fstring(node->nd_lit);
- ADD_INSN1(ret, line_node, putobject, str);
+ ADD_INSN1(ret, node, putobject, str);
RB_OBJ_WRITTEN(iseq, Qundef, str);
- ADD_CALL(ret, line_node, idBackquote, INT2FIX(1));
+ ADD_CALL(ret, node, idBackquote, INT2FIX(1));
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
case NODE_DXSTR:{
- ADD_CALL_RECEIVER(ret, line_node);
+ ADD_CALL_RECEIVER(ret, node);
compile_dstr(iseq, ret, node);
- ADD_CALL(ret, line_node, idBackquote, INT2FIX(1));
+ ADD_CALL(ret, node, idBackquote, INT2FIX(1));
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
@@ -8820,7 +9383,7 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
compile_dregx(iseq, ret, node);
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
@@ -8829,51 +9392,51 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
const rb_iseq_t *block_iseq;
block_iseq = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_PLAIN, line);
- ADD_INSN2(ret, line_node, once, block_iseq, INT2FIX(ic_index));
+ ADD_INSN2(ret, node, once, block_iseq, INT2FIX(ic_index));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block_iseq);
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
case NODE_ARGSCAT:{
if (popped) {
CHECK(COMPILE(ret, "argscat head", node->nd_head));
- ADD_INSN1(ret, line_node, splatarray, Qfalse);
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN1(ret, node, splatarray, Qfalse);
+ ADD_INSN(ret, node, pop);
CHECK(COMPILE(ret, "argscat body", node->nd_body));
- ADD_INSN1(ret, line_node, splatarray, Qfalse);
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN1(ret, node, splatarray, Qfalse);
+ ADD_INSN(ret, node, pop);
}
else {
CHECK(COMPILE(ret, "argscat head", node->nd_head));
CHECK(COMPILE(ret, "argscat body", node->nd_body));
- ADD_INSN(ret, line_node, concatarray);
+ ADD_INSN(ret, node, concatarray);
}
break;
}
case NODE_ARGSPUSH:{
if (popped) {
CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
- ADD_INSN1(ret, line_node, splatarray, Qfalse);
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN1(ret, node, splatarray, Qfalse);
+ ADD_INSN(ret, node, pop);
CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
}
else {
CHECK(COMPILE(ret, "arsgpush head", node->nd_head));
CHECK(COMPILE_(ret, "argspush body", node->nd_body, popped));
- ADD_INSN1(ret, line_node, newarray, INT2FIX(1));
- ADD_INSN(ret, line_node, concatarray);
+ ADD_INSN1(ret, node, newarray, INT2FIX(1));
+ ADD_INSN(ret, node, concatarray);
}
break;
}
case NODE_SPLAT:{
CHECK(COMPILE(ret, "splat", node->nd_head));
- ADD_INSN1(ret, line_node, splatarray, Qtrue);
+ ADD_INSN1(ret, node, splatarray, Qtrue);
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
@@ -8884,11 +9447,11 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
ISEQ_TYPE_METHOD, line);
debugp_param("defn/iseq", rb_iseqw_new(method_iseq));
- ADD_INSN2(ret, line_node, definemethod, ID2SYM(mid), method_iseq);
+ ADD_INSN2(ret, node, definemethod, ID2SYM(mid), method_iseq);
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)method_iseq);
if (!popped) {
- ADD_INSN1(ret, line_node, putobject, ID2SYM(mid));
+ ADD_INSN1(ret, node, putobject, ID2SYM(mid));
}
break;
@@ -8901,45 +9464,45 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
debugp_param("defs/iseq", rb_iseqw_new(singleton_method_iseq));
CHECK(COMPILE(ret, "defs: recv", node->nd_recv));
- ADD_INSN2(ret, line_node, definesmethod, ID2SYM(mid), singleton_method_iseq);
+ ADD_INSN2(ret, node, definesmethod, ID2SYM(mid), singleton_method_iseq);
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_method_iseq);
if (!popped) {
- ADD_INSN1(ret, line_node, putobject, ID2SYM(mid));
+ ADD_INSN1(ret, node, putobject, ID2SYM(mid));
}
break;
}
case NODE_ALIAS:{
- ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
CHECK(COMPILE(ret, "alias arg1", node->nd_1st));
CHECK(COMPILE(ret, "alias arg2", node->nd_2nd));
- ADD_SEND(ret, line_node, id_core_set_method_alias, INT2FIX(3));
+ ADD_SEND(ret, node, id_core_set_method_alias, INT2FIX(3));
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
case NODE_VALIAS:{
- ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, line_node, putobject, ID2SYM(node->nd_alias));
- ADD_INSN1(ret, line_node, putobject, ID2SYM(node->nd_orig));
- ADD_SEND(ret, line_node, id_core_set_variable_alias, INT2FIX(2));
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_alias));
+ ADD_INSN1(ret, node, putobject, ID2SYM(node->nd_orig));
+ ADD_SEND(ret, node, id_core_set_variable_alias, INT2FIX(2));
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
case NODE_UNDEF:{
- ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_CBASE));
CHECK(COMPILE(ret, "undef arg", node->nd_undef));
- ADD_SEND(ret, line_node, id_core_undef_method, INT2FIX(2));
+ ADD_SEND(ret, node, id_core_undef_method, INT2FIX(2));
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
@@ -8952,11 +9515,11 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
compile_cpath(ret, iseq, node->nd_cpath);
CHECK(COMPILE(ret, "super", node->nd_super));
- ADD_INSN3(ret, line_node, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
+ ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), class_iseq, INT2FIX(flags));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)class_iseq);
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
@@ -8967,12 +9530,12 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
const int flags = VM_DEFINECLASS_TYPE_MODULE |
compile_cpath(ret, iseq, node->nd_cpath);
- ADD_INSN (ret, line_node, putnil); /* dummy */
- ADD_INSN3(ret, line_node, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
+ ADD_INSN (ret, node, putnil); /* dummy */
+ ADD_INSN3(ret, node, defineclass, ID2SYM(node->nd_cpath->nd_mid), module_iseq, INT2FIX(flags));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)module_iseq);
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
@@ -8982,112 +9545,30 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
ISEQ_TYPE_CLASS, line);
CHECK(COMPILE(ret, "sclass#recv", node->nd_recv));
- ADD_INSN (ret, line_node, putnil);
+ ADD_INSN (ret, node, putnil);
CONST_ID(singletonclass, "singletonclass");
- ADD_INSN3(ret, line_node, defineclass,
+ ADD_INSN3(ret, node, defineclass,
ID2SYM(singletonclass), singleton_class,
INT2FIX(VM_DEFINECLASS_TYPE_SINGLETON_CLASS));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)singleton_class);
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
- case NODE_COLON2:{
- if (rb_is_const_id(node->nd_mid)) {
- /* constant */
- LABEL *lend = NEW_LABEL(line);
- int ic_index = body->is_size++;
-
- DECL_ANCHOR(pref);
- DECL_ANCHOR(body);
-
- INIT_ANCHOR(pref);
- INIT_ANCHOR(body);
- CHECK(compile_const_prefix(iseq, node, pref, body));
- if (LIST_INSN_SIZE_ZERO(pref)) {
- if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
- ADD_INSN2(ret, line_node, opt_getinlinecache, lend, INT2FIX(ic_index));
- }
- else {
- ADD_INSN(ret, line_node, putnil);
- }
-
- ADD_SEQ(ret, body);
-
- if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
- ADD_INSN1(ret, line_node, opt_setinlinecache, INT2FIX(ic_index));
- ADD_LABEL(ret, lend);
- }
- }
- else {
- ADD_SEQ(ret, pref);
- ADD_SEQ(ret, body);
- }
- }
- else {
- /* function call */
- ADD_CALL_RECEIVER(ret, line_node);
- CHECK(COMPILE(ret, "colon2#nd_head", node->nd_head));
- ADD_CALL(ret, line_node, node->nd_mid, INT2FIX(1));
- }
- if (popped) {
- ADD_INSN(ret, line_node, pop);
- }
+ case NODE_COLON2:
+ CHECK(compile_colon2(iseq, ret, node, popped));
break;
- }
- case NODE_COLON3:{
- LABEL *lend = NEW_LABEL(line);
- int ic_index = body->is_size++;
-
- debugi("colon3#nd_mid", node->nd_mid);
-
- /* add cache insn */
- if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
- ADD_INSN2(ret, line_node, opt_getinlinecache, lend, INT2FIX(ic_index));
- ADD_INSN(ret, line_node, pop);
- }
-
- ADD_INSN1(ret, line_node, putobject, rb_cObject);
- ADD_INSN1(ret, line_node, putobject, Qtrue);
- ADD_INSN1(ret, line_node, getconstant, ID2SYM(node->nd_mid));
-
- if (ISEQ_COMPILE_DATA(iseq)->option->inline_const_cache) {
- ADD_INSN1(ret, line_node, opt_setinlinecache, INT2FIX(ic_index));
- ADD_LABEL(ret, lend);
- }
-
- if (popped) {
- ADD_INSN(ret, line_node, pop);
- }
+ case NODE_COLON3:
+ CHECK(compile_colon3(iseq, ret, node, popped));
break;
- }
case NODE_DOT2:
- case NODE_DOT3:{
- int excl = type == NODE_DOT3;
- VALUE flag = INT2FIX(excl);
- const NODE *b = node->nd_beg;
- const NODE *e = node->nd_end;
-
- if (optimizable_range_item_p(b) && optimizable_range_item_p(e)) {
- if (!popped) {
- VALUE bv = nd_type(b) == NODE_LIT ? b->nd_lit : Qnil;
- VALUE ev = nd_type(e) == NODE_LIT ? e->nd_lit : Qnil;
- VALUE val = rb_range_new(bv, ev, excl);
- ADD_INSN1(ret, line_node, putobject, val);
- RB_OBJ_WRITTEN(iseq, Qundef, val);
- }
- }
- else {
- CHECK(COMPILE_(ret, "min", b, popped));
- CHECK(COMPILE_(ret, "max", e, popped));
- if (!popped) {
- ADD_INSN1(ret, line_node, newrange, flag);
- }
- }
+ CHECK(compile_dots(iseq, ret, node, popped, FALSE));
+ break;
+ case NODE_DOT3:
+ CHECK(compile_dots(iseq, ret, node, popped, TRUE));
break;
- }
case NODE_FLIP2:
case NODE_FLIP3:{
LABEL *lend = NEW_LABEL(line);
@@ -9096,62 +9577,40 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
CHECK(compile_flip_flop(iseq, ret, node, type == NODE_FLIP2,
ltrue, lfalse));
ADD_LABEL(ret, ltrue);
- ADD_INSN1(ret, line_node, putobject, Qtrue);
- ADD_INSNL(ret, line_node, jump, lend);
+ ADD_INSN1(ret, node, putobject, Qtrue);
+ ADD_INSNL(ret, node, jump, lend);
ADD_LABEL(ret, lfalse);
- ADD_INSN1(ret, line_node, putobject, Qfalse);
+ ADD_INSN1(ret, node, putobject, Qfalse);
ADD_LABEL(ret, lend);
break;
}
case NODE_SELF:{
if (!popped) {
- ADD_INSN(ret, line_node, putself);
+ ADD_INSN(ret, node, putself);
}
break;
}
case NODE_NIL:{
if (!popped) {
- ADD_INSN(ret, line_node, putnil);
+ ADD_INSN(ret, node, putnil);
}
break;
}
case NODE_TRUE:{
if (!popped) {
- ADD_INSN1(ret, line_node, putobject, Qtrue);
+ ADD_INSN1(ret, node, putobject, Qtrue);
}
break;
}
case NODE_FALSE:{
if (!popped) {
- ADD_INSN1(ret, line_node, putobject, Qfalse);
+ ADD_INSN1(ret, node, putobject, Qfalse);
}
break;
}
- case NODE_ERRINFO:{
- if (!popped) {
- if (body->type == ISEQ_TYPE_RESCUE) {
- ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, 0);
- }
- else {
- const rb_iseq_t *ip = iseq;
- int level = 0;
- while (ip) {
- if (ip->body->type == ISEQ_TYPE_RESCUE) {
- break;
- }
- ip = ip->body->parent_iseq;
- level++;
- }
- if (ip) {
- ADD_GETLOCAL(ret, line_node, LVAR_ERRINFO, level);
- }
- else {
- ADD_INSN(ret, line_node, putnil);
- }
- }
- }
+ case NODE_ERRINFO:
+ CHECK(compile_errinfo(iseq, ret, node, popped));
break;
- }
case NODE_DEFINED:
if (!popped) {
CHECK(compile_defined_expr(iseq, ret, node, Qtrue));
@@ -9168,153 +9627,41 @@ iseq_compile_each0(rb_iseq_t *iseq, LINK_ANCHOR *const ret, const NODE *node, in
new_child_iseq_with_callback(iseq, ifunc,
rb_fstring(make_name_for_block(iseq)), iseq, ISEQ_TYPE_BLOCK, line);
- ADD_INSN2(ret, line_node, once, once_iseq, INT2FIX(is_index));
+ ADD_INSN2(ret, node, once, once_iseq, INT2FIX(is_index));
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)once_iseq);
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
case NODE_KW_ARG:
- {
- LABEL *end_label = NEW_LABEL(nd_line(node));
- const NODE *default_value = node->nd_body->nd_value;
-
- if (default_value == NODE_SPECIAL_REQUIRED_KEYWORD) {
- /* required argument. do nothing */
- COMPILE_ERROR(ERROR_ARGS "unreachable");
- goto ng;
- }
- else if (nd_type(default_value) == NODE_LIT ||
- nd_type(default_value) == NODE_NIL ||
- nd_type(default_value) == NODE_TRUE ||
- nd_type(default_value) == NODE_FALSE) {
- COMPILE_ERROR(ERROR_ARGS "unreachable");
- goto ng;
- }
- else {
- /* if keywordcheck(_kw_bits, nth_keyword)
- * kw = default_value
- * end
- */
- int kw_bits_idx = body->local_table_size - body->param.keyword->bits_start;
- int keyword_idx = body->param.keyword->num;
-
- ADD_INSN2(ret, line_node, checkkeyword, INT2FIX(kw_bits_idx + VM_ENV_DATA_SIZE - 1), INT2FIX(keyword_idx));
- ADD_INSNL(ret, line_node, branchif, end_label);
- CHECK(COMPILE_POPPED(ret, "keyword default argument", node->nd_body));
- ADD_LABEL(ret, end_label);
- }
-
- break;
- }
+ CHECK(compile_kw_arg(iseq, ret, node, popped));
+ break;
case NODE_DSYM:{
compile_dstr(iseq, ret, node);
if (!popped) {
- ADD_INSN(ret, line_node, intern);
+ ADD_INSN(ret, node, intern);
}
else {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
- case NODE_ATTRASGN:{
- DECL_ANCHOR(recv);
- DECL_ANCHOR(args);
- unsigned int flag = 0;
- ID mid = node->nd_mid;
- VALUE argc;
- LABEL *else_label = NULL;
- VALUE branches = Qfalse;
-
- /* optimization shortcut
- * obj["literal"] = value -> opt_aset_with(obj, "literal", value)
- */
- if (mid == idASET && !private_recv_p(node) && node->nd_args &&
- nd_type(node->nd_args) == NODE_LIST && node->nd_args->nd_alen == 2 &&
- nd_type(node->nd_args->nd_head) == NODE_STR &&
- ISEQ_COMPILE_DATA(iseq)->current_block == NULL &&
- !ISEQ_COMPILE_DATA(iseq)->option->frozen_string_literal &&
- ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction)
- {
- VALUE str = rb_fstring(node->nd_args->nd_head->nd_lit);
- CHECK(COMPILE(ret, "recv", node->nd_recv));
- CHECK(COMPILE(ret, "value", node->nd_args->nd_next->nd_head));
- if (!popped) {
- ADD_INSN(ret, line_node, swap);
- ADD_INSN1(ret, line_node, topn, INT2FIX(1));
- }
- ADD_INSN2(ret, line_node, opt_aset_with, str,
- new_callinfo(iseq, idASET, 2, 0, NULL, FALSE));
- RB_OBJ_WRITTEN(iseq, Qundef, str);
- ADD_INSN(ret, line_node, pop);
- break;
- }
-
- INIT_ANCHOR(recv);
- INIT_ANCHOR(args);
- argc = setup_args(iseq, args, node->nd_args, &flag, NULL);
- CHECK(!NIL_P(argc));
-
- int asgnflag = COMPILE_RECV(recv, "recv", node);
- CHECK(asgnflag != -1);
- flag |= (unsigned int)asgnflag;
-
- debugp_param("argc", argc);
- debugp_param("nd_mid", ID2SYM(mid));
-
- if (!rb_is_attrset_id(mid)) {
- /* safe nav attr */
- mid = rb_id_attrset(mid);
- else_label = qcall_branch_start(iseq, recv, &branches, node, line_node);
- }
- if (!popped) {
- ADD_INSN(ret, line_node, putnil);
- ADD_SEQ(ret, recv);
- ADD_SEQ(ret, args);
-
- if (flag & VM_CALL_ARGS_BLOCKARG) {
- ADD_INSN1(ret, line_node, topn, INT2FIX(1));
- if (flag & VM_CALL_ARGS_SPLAT) {
- ADD_INSN1(ret, line_node, putobject, INT2FIX(-1));
- ADD_SEND_WITH_FLAG(ret, line_node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
- }
- ADD_INSN1(ret, line_node, setn, FIXNUM_INC(argc, 3));
- ADD_INSN (ret, line_node, pop);
- }
- else if (flag & VM_CALL_ARGS_SPLAT) {
- ADD_INSN(ret, line_node, dup);
- ADD_INSN1(ret, line_node, putobject, INT2FIX(-1));
- ADD_SEND_WITH_FLAG(ret, line_node, idAREF, INT2FIX(1), INT2FIX(asgnflag));
- ADD_INSN1(ret, line_node, setn, FIXNUM_INC(argc, 2));
- ADD_INSN (ret, line_node, pop);
- }
- else {
- ADD_INSN1(ret, line_node, setn, FIXNUM_INC(argc, 1));
- }
- }
- else {
- ADD_SEQ(ret, recv);
- ADD_SEQ(ret, args);
- }
- ADD_SEND_WITH_FLAG(ret, line_node, mid, argc, INT2FIX(flag));
- qcall_branch_end(iseq, ret, else_label, branches, node, line_node);
- ADD_INSN(ret, line_node, pop);
-
+ case NODE_ATTRASGN:
+ CHECK(compile_attrasgn(iseq, ret, node, popped));
break;
- }
case NODE_LAMBDA:{
/* compile same as lambda{...} */
const rb_iseq_t *block = NEW_CHILD_ISEQ(node->nd_body, make_name_for_block(iseq), ISEQ_TYPE_BLOCK, line);
VALUE argc = INT2FIX(0);
- ADD_INSN1(ret, line_node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
- ADD_CALL_WITH_BLOCK(ret, line_node, idLambda, argc, block);
+ ADD_INSN1(ret, node, putspecialobject, INT2FIX(VM_SPECIAL_OBJECT_VMCORE));
+ ADD_CALL_WITH_BLOCK(ret, node, idLambda, argc, block);
RB_OBJ_WRITTEN(iseq, Qundef, (VALUE)block);
if (popped) {
- ADD_INSN(ret, line_node, pop);
+ ADD_INSN(ret, node, pop);
}
break;
}
@@ -10794,6 +11141,11 @@ ibf_load_code(const struct ibf_load *load, rb_iseq_t *iseq, ibf_offset_t bytecod
rb_hash_rehash(v); // hash function changed
freeze_hide_obj(v);
+ // Overwrite the existing hash in the object list. This
+ // is to keep the object alive during load time.
+ // [Bug #17984] [ruby-core:104259]
+ pinned_list_store(load->current_buffer->obj_list, (long)op, v);
+
code[code_index] = v;
RB_OBJ_WRITTEN(iseqv, Qundef, v);
FL_SET(iseqv, ISEQ_MARKABLE_ISEQ);
@@ -11547,6 +11899,7 @@ enum ibf_object_class_index {
IBF_OBJECT_CLASS_STANDARD_ERROR,
IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_ERROR,
IBF_OBJECT_CLASS_TYPE_ERROR,
+ IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR,
};
struct ibf_object_regexp {
@@ -11636,6 +11989,9 @@ ibf_dump_object_class(struct ibf_dump *dump, VALUE obj)
else if (obj == rb_eTypeError) {
cindex = IBF_OBJECT_CLASS_TYPE_ERROR;
}
+ else if (obj == rb_eNoMatchingPatternKeyError) {
+ cindex = IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR;
+ }
else {
rb_obj_info_dump(obj);
rb_p(obj);
@@ -11660,6 +12016,8 @@ ibf_load_object_class(const struct ibf_load *load, const struct ibf_object_heade
return rb_eNoMatchingPatternError;
case IBF_OBJECT_CLASS_TYPE_ERROR:
return rb_eTypeError;
+ case IBF_OBJECT_CLASS_NO_MATCHING_PATTERN_KEY_ERROR:
+ return rb_eNoMatchingPatternKeyError;
}
rb_raise(rb_eArgError, "ibf_load_object_class: unknown class (%d)", (int)cindex);
@@ -12048,8 +12406,8 @@ ibf_dump_object_object(struct ibf_dump *dump, VALUE obj)
current_offset = ibf_dump_pos(dump);
if (SPECIAL_CONST_P(obj) &&
- ! (RB_TYPE_P(obj, T_SYMBOL) ||
- RB_TYPE_P(obj, T_FLOAT))) {
+ ! (SYMBOL_P(obj) ||
+ RB_FLOAT_TYPE_P(obj))) {
obj_header.special_const = TRUE;
obj_header.frozen = TRUE;
obj_header.internal = TRUE;
diff --git a/complex.c b/complex.c
index 09e47f8..ea3c137 100644
--- a/complex.c
+++ b/complex.c
@@ -34,10 +34,6 @@
#else
static VALUE RFLOAT_0;
#endif
-#if defined(HAVE_SIGNBIT) && defined(__GNUC__) && defined(__sun) && \
- !defined(signbit)
-extern int signbit(double);
-#endif
VALUE rb_cComplex;
@@ -54,8 +50,6 @@ static ID id_abs, id_arg,
#define id_quo idQuo
#define id_fdiv idFdiv
-#define f_boolcast(x) ((x) ? Qtrue : Qfalse)
-
#define fun1(n) \
inline static VALUE \
f_##n(VALUE x)\
@@ -340,36 +334,38 @@ f_zero_p(VALUE x)
#define f_nonzero_p(x) (!f_zero_p(x))
+static inline bool
+always_finite_type_p(VALUE x)
+{
+ if (FIXNUM_P(x)) return true;
+ if (FLONUM_P(x)) return true; /* Infinity can't be a flonum */
+ return (RB_INTEGER_TYPE_P(x) || RB_TYPE_P(x, T_RATIONAL));
+}
+
VALUE rb_flo_is_finite_p(VALUE num);
inline static int
f_finite_p(VALUE x)
{
- if (RB_INTEGER_TYPE_P(x)) {
+ if (always_finite_type_p(x)) {
return TRUE;
}
else if (RB_FLOAT_TYPE_P(x)) {
- return (int)rb_flo_is_finite_p(x);
- }
- else if (RB_TYPE_P(x, T_RATIONAL)) {
- return TRUE;
+ return isfinite(RFLOAT_VALUE(x));
}
return RTEST(rb_funcallv(x, id_finite_p, 0, 0));
}
VALUE rb_flo_is_infinite_p(VALUE num);
-inline static VALUE
+inline static int
f_infinite_p(VALUE x)
{
- if (RB_INTEGER_TYPE_P(x)) {
- return Qnil;
+ if (always_finite_type_p(x)) {
+ return FALSE;
}
else if (RB_FLOAT_TYPE_P(x)) {
- return rb_flo_is_infinite_p(x);
- }
- else if (RB_TYPE_P(x, T_RATIONAL)) {
- return Qnil;
+ return isinf(RFLOAT_VALUE(x));
}
- return rb_funcallv(x, id_infinite_p, 0, 0);
+ return RTEST(rb_funcallv(x, id_infinite_p, 0, 0));
}
inline static int
@@ -1062,7 +1058,7 @@ rb_complex_pow(VALUE self, VALUE other)
if (k_numeric_p(other) && f_real_p(other)) {
VALUE r, theta;
- if (RB_TYPE_P(other, T_BIGNUM))
+ if (RB_BIGNUM_TYPE_P(other))
rb_warn("in a**b, b may be too big");
r = f_abs(self);
@@ -1092,15 +1088,15 @@ nucomp_eqeq_p(VALUE self, VALUE other)
if (RB_TYPE_P(other, T_COMPLEX)) {
get_dat2(self, other);
- return f_boolcast(f_eqeq_p(adat->real, bdat->real) &&
+ return RBOOL(f_eqeq_p(adat->real, bdat->real) &&
f_eqeq_p(adat->imag, bdat->imag));
}
if (k_numeric_p(other) && f_real_p(other)) {
get_dat1(self);
- return f_boolcast(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
+ return RBOOL(f_eqeq_p(dat->real, other) && f_zero_p(dat->imag));
}
- return f_boolcast(f_eqeq_p(other, self));
+ return RBOOL(f_eqeq_p(other, self));
}
static bool
@@ -1354,7 +1350,7 @@ nucomp_eql_p(VALUE self, VALUE other)
if (RB_TYPE_P(other, T_COMPLEX)) {
get_dat2(self, other);
- return f_boolcast((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
+ return RBOOL((CLASS_OF(adat->real) == CLASS_OF(bdat->real)) &&
(CLASS_OF(adat->imag) == CLASS_OF(bdat->imag)) &&
f_eqeq_p(self, other));
@@ -1455,10 +1451,7 @@ rb_complex_finite_p(VALUE self)
{
get_dat1(self);
- if (f_finite_p(dat->real) && f_finite_p(dat->imag)) {
- return Qtrue;
- }
- return Qfalse;
+ return RBOOL(f_finite_p(dat->real) && f_finite_p(dat->imag));
}
/*
@@ -1478,7 +1471,7 @@ rb_complex_infinite_p(VALUE self)
{
get_dat1(self);
- if (NIL_P(f_infinite_p(dat->real)) && NIL_P(f_infinite_p(dat->imag))) {
+ if (!f_infinite_p(dat->real) && !f_infinite_p(dat->imag)) {
return Qnil;
}
return ONE;
@@ -1528,8 +1521,6 @@ nucomp_marshal_load(VALUE self, VALUE a)
return self;
}
-/* --- */
-
VALUE
rb_complex_raw(VALUE x, VALUE y)
{
@@ -1563,13 +1554,6 @@ rb_Complex(VALUE x, VALUE y)
return nucomp_s_convert(2, a, rb_cComplex);
}
-/*!
- * Creates a Complex object.
- *
- * \param real real part value
- * \param imag imaginary part value
- * \return a new Complex object
- */
VALUE
rb_dbl_complex_new(double real, double imag)
{
@@ -2152,8 +2136,6 @@ nucomp_s_convert(int argc, VALUE *argv, VALUE klass)
return nucomp_convert(klass, a1, a2, TRUE);
}
-/* --- */
-
/*
* call-seq:
* num.real -> self
@@ -2408,8 +2390,6 @@ Init_Complex(void)
rb_define_private_method(compat, "marshal_load", nucomp_marshal_load, 1);
rb_marshal_define_compat(rb_cComplex, compat, nucomp_dumper, nucomp_loader);
- /* --- */
-
rb_define_method(rb_cComplex, "to_i", nucomp_to_i, 0);
rb_define_method(rb_cComplex, "to_f", nucomp_to_f, 0);
rb_define_method(rb_cComplex, "to_r", nucomp_to_r, 0);
@@ -2422,8 +2402,6 @@ Init_Complex(void)
rb_define_private_method(CLASS_OF(rb_cComplex), "convert", nucomp_s_convert, -1);
- /* --- */
-
rb_define_method(rb_cNumeric, "real", numeric_real, 0);
rb_define_method(rb_cNumeric, "imaginary", numeric_imag, 0);
rb_define_method(rb_cNumeric, "imag", numeric_imag, 0);
diff --git a/configure.ac b/configure.ac
index 38ab4bd..1112c6f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -799,7 +799,7 @@ AS_IF([test "$GCC" = yes], [
])
],
[cygwin*|msys*|darwin*|netbsd*], [
- # need lgamma_r(), finite()
+ # need lgamma_r()
])
# ANSI (no XCFLAGS because this is C only)
@@ -962,6 +962,8 @@ AS_CASE(["$target_os"], [*android*], [
AS_UNSET(ORIG_LIBS)
POSTLINK=:
AC_SUBST(POSTLINK)
+cleanlibs=
+AC_SUBST(cleanlibs)
AS_CASE(["$target_os"],
[nextstep*], [ ],
[openstep*], [ ],
@@ -1060,6 +1062,7 @@ main()
AC_CHECK_HEADERS(crt_externs.h, [], [], [
#include <crt_externs.h>
])
+ cleanlibs='$(TARGET_SO).dSYM'
],
[hpux*], [ LIBS="-lm $LIBS"
ac_cv_c_inline=no],
@@ -1294,42 +1297,53 @@ AC_ARG_WITH([jemalloc],
[AS_HELP_STRING([--with-jemalloc],[use jemalloc allocator])],
[with_jemalloc=$withval], [with_jemalloc=no])
AS_IF([test "x$with_jemalloc" != xno],[
- AC_SEARCH_LIBS([malloc_conf], [jemalloc],
- [
- AC_DEFINE(HAVE_LIBJEMALLOC, 1)
- with_jemalloc=yes
- ],
- [test x$with_jemalloc = xyes && with_jemalloc=no])
- AC_CHECK_HEADER(jemalloc/jemalloc.h, [
- AC_DEFINE(RUBY_ALTERNATIVE_MALLOC_HEADER, [<jemalloc/jemalloc.h>])
- ],
- [test x$with_jemalloc = xyes && with_jemalloc=no])
- AS_IF([test "x$with_jemalloc" != xyes], [
- AC_CACHE_CHECK([for jemalloc with JEMALLOC_MANGLE], rb_cv_jemalloc_demangle,
- [AC_LINK_IFELSE([AC_LANG_PROGRAM([@%:@define JEMALLOC_MANGLE 1
- @%:@ifdef RUBY_ALTERNATIVE_MALLOC_HEADER
- @%:@include RUBY_ALTERNATIVE_MALLOC_HEADER
- @%:@else
- @%:@include <jemalloc.h>
- @%:@endif], [return !&malloc_conf])],
- [rb_cv_jemalloc_demangle=yes],
- [rb_cv_jemalloc_demangle=no])
- ])
+ # find jemalloc header first
+ malloc_header=
+ AC_CHECK_HEADER(jemalloc/jemalloc.h, [malloc_header=jemalloc/jemalloc.h], [
+ AC_CHECK_HEADER(jemalloc.h, [malloc_header=jemalloc.h])
])
- AS_IF([test "x$rb_cv_jemalloc_demangle" = xyes], [
- AC_DEFINE(JEMALLOC_MANGLE)
- with_jemalloc=yes
+ AS_IF([test "$malloc_header" != ""], [
+ AC_DEFINE_UNQUOTED(RUBY_ALTERNATIVE_MALLOC_HEADER, [<$malloc_header>])
+ ])
+ save_LIBS="$LIBS"
+ AC_CACHE_CHECK([for jemalloc library], rb_cv_jemalloc_library, [
+ rb_cv_jemalloc_library=no
+ # try [with mangle, without mangle] x [no more additional
+ # libraries, adding jemalloc] combination, using the jemalloc
+ # header found above.
+ for mangle in '' mangle; do
+ for lib in '' -ljemalloc; do
+ LIBS="${lib:+$lib }$LIBS"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([${mangle:+@%:@define JEMALLOC_MANGLE 1}
+ @%:@include <stdio.h>
+ @%:@ifdef RUBY_ALTERNATIVE_MALLOC_HEADER
+ @%:@include RUBY_ALTERNATIVE_MALLOC_HEADER
+ @%:@else
+ extern const char *malloc_conf;
+ @%:@endif],
+ [/* access at runtime not to be optimized away */
+ if (malloc_conf) printf("malloc_conf=%s\n", malloc_conf);])],
+ [rb_cv_jemalloc_library="${lib:-none required}${mangle:+ with mangle}"])
+ LIBS="$save_LIBS"
+ test "${rb_cv_jemalloc_library}" = no || break 2
+ done
+ done
])
+ with_jemalloc=${rb_cv_jemalloc_library}
AS_CASE(["$with_jemalloc"],
- [yes],
- [
- AC_DEFINE(HAVE_MALLOC_CONF)
- ac_cv_func_malloc_usable_size=yes
- ],
- [no],
- [AC_MSG_ERROR([jemalloc requested but not found])
+ [no],
+ [AC_MSG_ERROR([jemalloc requested but not found])],
+ [-l*], [
+ set dummy $with_jemalloc
+ LIBS="$2 $LIBS"
])
-])
+ AS_CASE(["$with_jemalloc"],
+ [*" with mangle"], [
+ AC_DEFINE(JEMALLOC_MANGLE)
+ ])
+ AC_DEFINE(HAVE_MALLOC_CONF)
+ ac_cv_func_malloc_usable_size=yes
+]) # with_jemalloc
dnl check for large file stuff
mv confdefs.h confdefs1.h
@@ -1648,7 +1662,7 @@ AC_CACHE_CHECK(for function name string predefined identifier,
RUBY_WERROR_FLAG([
for func in __func__ __FUNCTION__; do
AC_LINK_IFELSE([AC_LANG_PROGRAM([[@%:@include <stdio.h>]],
- [[puts($func);]])],
+ [[puts($func);]])],
[rb_cv_function_name_string=$func
break])
done
@@ -1892,9 +1906,7 @@ AC_REPLACE_FUNCS(strlcpy)
AC_REPLACE_FUNCS(strstr)
AC_REPLACE_FUNCS(tgamma)
-RUBY_REPLACE_FUNC([finite], [@%:@include <math.h>])
-RUBY_REPLACE_FUNC([isinf], [@%:@include <math.h>])
-RUBY_REPLACE_FUNC([isnan], [@%:@include <math.h>])
+AC_DEFINE(HAVE_ISFINITE) # C99; backward compatibility
# for missing/setproctitle.c
AS_CASE(["$target_os"],
@@ -1904,17 +1916,7 @@ AS_CASE(["$target_os"],
AC_CHECK_HEADERS(sys/pstat.h)
-AC_CACHE_CHECK(for signbit, rb_cv_have_signbit,
- [AC_LINK_IFELSE([AC_LANG_PROGRAM([[
-#include <math.h>
-]], [[int v = signbit(-0.0);]])],
- rb_cv_have_signbit=yes,
- rb_cv_have_signbit=no)])
-AS_IF([test "$rb_cv_have_signbit" = yes], [
- AC_DEFINE(HAVE_SIGNBIT)
-], [
- AC_LIBOBJ([signbit])
-])
+AC_DEFINE(HAVE_SIGNBIT) # C99; backward compatibility
AC_FUNC_FORK
@@ -2483,7 +2485,6 @@ AC_ARG_WITH(coroutine,
AS_HELP_STRING([--with-coroutine=IMPLEMENTATION], [specify the coroutine implementation to use]),
[coroutine_type=$withval], [coroutine_type=])
AS_CASE([$coroutine_type], [yes|''], [
- AC_MSG_CHECKING(native coroutine implementation for ${target_cpu}-${target_os})
coroutine_type=
AS_CASE(["$target_cpu-$target_os"],
[universal-darwin*], [
@@ -2523,6 +2524,24 @@ AS_CASE([$coroutine_type], [yes|''], [
[riscv64-linux*], [
coroutine_type=riscv64
],
+ [x86_64-freebsd*], [
+ coroutine_type=amd64
+ ],
+ [i386-freebsd*], [
+ coroutine_type=x86
+ ],
+ [aarch64-freebsd*], [
+ coroutine_type=arm64
+ ],
+ [x86_64-netbsd*], [
+ coroutine_type=amd64
+ ],
+ [i386-netbsd*], [
+ coroutine_type=x86
+ ],
+ [aarch64-netbsd*], [
+ coroutine_type=arm64
+ ],
[x86_64-openbsd*], [
coroutine_type=amd64
],
@@ -2530,10 +2549,13 @@ AS_CASE([$coroutine_type], [yes|''], [
coroutine_type=x86
],
[*-openbsd*], [
- coroutine_type=copy
+ coroutine_type=pthread
+ ],
+ [x86_64-dragonfly*], [
+ coroutine_type=amd64
],
[*-haiku*], [
- coroutine_type=copy
+ coroutine_type=pthread
],
[*-emscripten*], [
coroutine_type=emscripten
@@ -2541,23 +2563,19 @@ AS_CASE([$coroutine_type], [yes|''], [
[
AC_CHECK_FUNCS([getcontext swapcontext makecontext],
[coroutine_type=ucontext],
- [coroutine_type=copy; break]
+ [coroutine_type=pthread; break]
)
]
)
+ AC_MSG_CHECKING(native coroutine implementation for ${target_cpu}-${target_os})
AC_MSG_RESULT(${coroutine_type})
])
COROUTINE_H=coroutine/$coroutine_type/Context.h
AS_IF([test ! -f "$srcdir/$COROUTINE_H"],
[AC_MSG_ERROR('$coroutine_type' is not supported as coroutine)])
-AS_CASE([$coroutine_type],
- [copy|ucontext], [
- COROUTINE_SRC=coroutine/$coroutine_type/Context.c
- ],
- [
- COROUTINE_SRC=coroutine/$coroutine_type/Context.'$(ASMEXT)'
- ]
-)
+COROUTINE_SRC=coroutine/$coroutine_type/Context.c
+AS_IF([test ! -f "$srcdir/$COROUTINE_SRC"],
+ [COROUTINE_SRC=coroutine/$coroutine_type/Context.'$(ASMEXT)'])
AC_DEFINE_UNQUOTED(COROUTINE_H, ["$COROUTINE_H"])
AC_SUBST(X_COROUTINE_H, [$COROUTINE_H])
AC_SUBST(X_COROUTINE_SRC, [$COROUTINE_SRC])
@@ -2847,7 +2865,6 @@ AC_SUBST(CCDLFLAGS)dnl
AC_SUBST(LDSHARED)dnl
AC_SUBST(LDSHAREDXX)dnl
AC_SUBST(DLEXT)dnl
-AC_SUBST(DLEXT2)dnl
AC_SUBST(LIBEXT)dnl
AC_SUBST(ASMEXT, S)dnl
@@ -3167,10 +3184,8 @@ AS_IF([test x"$LOAD_RELATIVE" = x1], [
len=2 # .rb
n=`expr "$DLEXT" : '.*'`; test "$n" -gt "$len" && len=$n
-n=`expr "$DLEXT2" : '.*'`; test "$n" -gt "$len" && len=$n
AC_DEFINE_UNQUOTED(DLEXT_MAXLEN, `expr $len + 1`)
test ".$DLEXT" = "." || AC_DEFINE_UNQUOTED(DLEXT, ".$DLEXT")
-test ".$DLEXT2" = "." || AC_DEFINE_UNQUOTED(DLEXT2, ".$DLEXT2")
AC_SUBST(DLEXT)
: "strip" && {
@@ -3377,6 +3392,17 @@ AS_CASE("$enable_shared", [yes], [
AC_DEFINE_UNQUOTED(LIBDIR_BASENAME, ["${libdir_basename}"])
libdir_basename="${libdir_basename}"${multiarch+'/${arch}'}
+ # Debian bullseye reportedly has its ld(1) patched, which breaks
+ # --enable-shared --with-jemalloc combination. We might have to deal with
+ # the ld(1) change sooner or later, but in the meantime let us force it
+ # the old way.
+ #
+ # See https://github.com/ruby/ruby/pull/4627
+ RUBY_TRY_LDFLAGS([${linker_flag}--no-as-needed], [no_as_needed=yes], [no_as_needed=no])
+ AS_IF([test "$no_as_needed" = yes], [
+ RUBY_APPEND_OPTIONS(LDFLAGS, [${linker_flag}--no-as-needed])
+ ])
+
AS_CASE(["$target_os"],
[freebsd*|dragonfly*], [],
[
@@ -3407,6 +3433,10 @@ AS_CASE("$enable_shared", [yes], [
AS_IF([test "$rb_cv_binary_elf" != "yes" ], [
LIBRUBY_SO="$LIBRUBY_SO.\$(TEENY)"
LIBRUBY_ALIASES=''
+ ], [test "$load_relative" = yes], [
+ libprefix="'\$\$ORIGIN/../${libdir_basename}'"
+ LIBRUBY_RPATHFLAGS="-Wl,-rpath,${libprefix}"
+ LIBRUBY_RELATIVE=yes
])
],
[netbsd*], [
@@ -3721,7 +3751,7 @@ AS_CASE(["$target_os"],
LIBRUBY_DLDFLAGS="${LIBRUBY_DLDFLAGS}"' $(RUBYDEF)'
])
EXPORT_PREFIX=' '
- DLDFLAGS="${DLDFLAGS}"' $(DEFFILE)'
+ EXTDLDFLAGS='$(DEFFILE)'
AC_LIBOBJ([win32/win32])
AC_LIBOBJ([win32/file])
COMMON_LIBS=m
@@ -3840,6 +3870,7 @@ AS_IF([test -n "${LIBS}"], [
MAINFLAGS=`echo " $MAINLIBS " | sed "s|$libspat"'||;s/^ *//;s/ *$//'`
])
LIBRUBYARG_STATIC="${LIBRUBYARG_STATIC} \$(MAINLIBS)"
+LIBRUBYARG_SHARED="${LIBRUBYARG_SHARED} \$(MAINLIBS)"
CPPFLAGS="$CPPFLAGS "'$(DEFS)'
test -z "$CPPFLAGS" || CPPFLAGS="$CPPFLAGS "; CPPFLAGS="$CPPFLAGS"'${cppflags}'
AS_IF([test -n "${cflags+set}"], [
@@ -4144,7 +4175,7 @@ guard=INCLUDE_RUBY_CONFIG_H
} | tr -d '\015' |
(
AS_IF([test "x$CONFIGURE_TTY" = xyes], [color=--color], [color=])
- exec ${tooldir}/ifchange $color "${config_h}" -
+ exec ${SHELL} ${tooldir}/ifchange $color "${config_h}" -
) >&AS_MESSAGE_FD || AC_MSG_ERROR([failed to create ${config_h}])
tr -d '\015' < largefile.h > confdefs.h
rm largefile.h
@@ -4241,21 +4272,6 @@ AC_ARG_WITH(destdir,
[DESTDIR="$withval"])
AC_SUBST(DESTDIR)
-AC_CONFIG_FILES($ruby_pc:template/ruby.pc.in,
- [
- AS_IF([sed ['s/\$(\([A-Za-z_][A-Za-z0-9_]*\))/${\1}/g;s/@[A-Za-z_][A-Za-z0-9_]*@//'] $ruby_pc > ruby.tmp.pc &&
- {
- test -z "$PKG_CONFIG" ||
- PKG_CONFIG_PATH=. $PKG_CONFIG --print-errors ruby.tmp
- }],
- [
- mv -f ruby.tmp.pc $ruby_pc
- ], [
- exit 1
- ])
- ],
- [ruby_pc='$ruby_pc' PKG_CONFIG='$PKG_CONFIG'])
-
AC_OUTPUT
}
}
diff --git a/cont.c b/cont.c
index 00ab1e9..164e9c7 100644
--- a/cont.c
+++ b/cont.c
@@ -561,7 +561,7 @@ fiber_pool_allocation_free(struct fiber_pool_allocation * allocation)
VM_ASSERT(allocation->used == 0);
- if (DEBUG) fprintf(stderr, "fiber_pool_allocation_free: %p base=%p count=%"PRIuSIZE"\n", allocation, allocation->base, allocation->count);
+ if (DEBUG) fprintf(stderr, "fiber_pool_allocation_free: %p base=%p count=%"PRIuSIZE"\n", (void*)allocation, allocation->base, allocation->count);
size_t i;
for (i = 0; i < allocation->count; i += 1) {
@@ -711,10 +711,49 @@ fiber_pool_stack_release(struct fiber_pool_stack * stack)
#endif
}
+static inline void
+ec_switch(rb_thread_t *th, rb_fiber_t *fiber)
+{
+ rb_execution_context_t *ec = &fiber->cont.saved_ec;
+ rb_ractor_set_current_ec(th->ractor, th->ec = ec);
+ // ruby_current_execution_context_ptr = th->ec = ec;
+
+ /*
+ * timer-thread may set trap interrupt on previous th->ec at any time;
+ * ensure we do not delay (or lose) the trap interrupt handling.
+ */
+ if (th->vm->ractor.main_thread == th &&
+ rb_signal_buff_size() > 0) {
+ RUBY_VM_SET_TRAP_INTERRUPT(ec);
+ }
+
+ VM_ASSERT(ec->fiber_ptr->cont.self == 0 || ec->vm_stack != NULL);
+}
+
+static inline void
+fiber_restore_thread(rb_thread_t *th, rb_fiber_t *fiber)
+{
+ ec_switch(th, fiber);
+ VM_ASSERT(th->ec->fiber_ptr == fiber);
+}
+
static COROUTINE
fiber_entry(struct coroutine_context * from, struct coroutine_context * to)
{
- rb_fiber_start();
+ rb_fiber_t *fiber = to->argument;
+ rb_thread_t *thread = fiber->cont.saved_ec.thread_ptr;
+
+#ifdef COROUTINE_PTHREAD_CONTEXT
+ ruby_thread_set_native(thread);
+#endif
+
+ fiber_restore_thread(thread, fiber);
+
+ rb_fiber_start(fiber);
+
+#ifndef COROUTINE_PTHREAD_CONTEXT
+ VM_UNREACHABLE(fiber_entry);
+#endif
}
// Initialize a fiber's coroutine's machine stack and vm stack.
@@ -731,22 +770,13 @@ fiber_initialize_coroutine(rb_fiber_t *fiber, size_t * vm_stack_size)
vm_stack = fiber_pool_stack_alloca(&fiber->stack, fiber_pool->vm_stack_size);
*vm_stack_size = fiber_pool->vm_stack_size;
-#ifdef COROUTINE_PRIVATE_STACK
- coroutine_initialize(&fiber->context, fiber_entry, fiber_pool_stack_base(&fiber->stack), fiber->stack.available, sec->machine.stack_start);
- // The stack for this execution context is still the main machine stack, so don't adjust it.
- // If this is not managed correctly, you will fail in `rb_ec_stack_check`.
-
- // We limit the machine stack usage to the fiber stack size.
- if (sec->machine.stack_maxsize > fiber->stack.available) {
- sec->machine.stack_maxsize = fiber->stack.available;
- }
-#else
coroutine_initialize(&fiber->context, fiber_entry, fiber_pool_stack_base(&fiber->stack), fiber->stack.available);
// The stack for this execution context is the one we allocated:
sec->machine.stack_start = fiber->stack.current;
sec->machine.stack_maxsize = fiber->stack.available;
-#endif
+
+ fiber->context.argument = (void*)fiber;
return vm_stack;
}
@@ -815,25 +845,6 @@ fiber_status_set(rb_fiber_t *fiber, enum fiber_status s)
fiber->status = s;
}
-static inline void
-ec_switch(rb_thread_t *th, rb_fiber_t *fiber)
-{
- rb_execution_context_t *ec = &fiber->cont.saved_ec;
- rb_ractor_set_current_ec(th->ractor, th->ec = ec);
- // ruby_current_execution_context_ptr = th->ec = ec;
-
- /*
- * timer-thread may set trap interrupt on previous th->ec at any time;
- * ensure we do not delay (or lose) the trap interrupt handling.
- */
- if (th->vm->ractor.main_thread == th &&
- rb_signal_buff_size() > 0) {
- RUBY_VM_SET_TRAP_INTERRUPT(ec);
- }
-
- VM_ASSERT(ec->fiber_ptr->cont.self == 0 || ec->vm_stack != NULL);
-}
-
static rb_context_t *
cont_ptr(VALUE obj)
{
@@ -1041,7 +1052,7 @@ fiber_free(void *ptr)
rb_fiber_t *fiber = ptr;
RUBY_FREE_ENTER("fiber");
- //if (DEBUG) fprintf(stderr, "fiber_free: %p[%p]\n", fiber, fiber->stack.base);
+ if (DEBUG) fprintf(stderr, "fiber_free: %p[%p]\n", (void *)fiber, fiber->stack.base);
if (fiber->cont.saved_ec.local_storage) {
rb_id_table_free(fiber->cont.saved_ec.local_storage);
@@ -1072,12 +1083,7 @@ fiber_memsize(const void *ptr)
VALUE
rb_obj_is_fiber(VALUE obj)
{
- if (rb_typeddata_is_kind_of(obj, &fiber_data_type)) {
- return Qtrue;
- }
- else {
- return Qfalse;
- }
+ return RBOOL(rb_typeddata_is_kind_of(obj, &fiber_data_type));
}
static void
@@ -1163,12 +1169,14 @@ cont_new(VALUE klass)
return cont;
}
-VALUE rb_fiberptr_self(struct rb_fiber_struct *fiber)
+VALUE
+rb_fiberptr_self(struct rb_fiber_struct *fiber)
{
return fiber->cont.self;
}
-unsigned int rb_fiberptr_blocking(struct rb_fiber_struct *fiber)
+unsigned int
+rb_fiberptr_blocking(struct rb_fiber_struct *fiber)
{
return fiber->blocking;
}
@@ -1278,13 +1286,6 @@ cont_capture(volatile int *volatile stat)
COMPILER_WARNING_POP
static inline void
-fiber_restore_thread(rb_thread_t *th, rb_fiber_t *fiber)
-{
- ec_switch(th, fiber);
- VM_ASSERT(th->ec->fiber_ptr == fiber);
-}
-
-static inline void
cont_restore_thread(rb_context_t *cont)
{
rb_thread_t *th = GET_THREAD();
@@ -1326,7 +1327,6 @@ cont_restore_thread(rb_context_t *cont)
th->ec->cfp = sec->cfp;
th->ec->raised_flag = sec->raised_flag;
th->ec->tag = sec->tag;
- th->ec->protect_tag = sec->protect_tag;
th->ec->root_lep = sec->root_lep;
th->ec->root_svar = sec->root_svar;
th->ec->ensure_list = sec->ensure_list;
@@ -1367,16 +1367,20 @@ fiber_setcontext(rb_fiber_t *new_fiber, rb_fiber_t *old_fiber)
/* old_fiber->machine.stack_end should be NULL */
old_fiber->cont.saved_ec.machine.stack_end = NULL;
- /* restore thread context */
- fiber_restore_thread(th, new_fiber);
-
- // if (DEBUG) fprintf(stderr, "fiber_setcontext: %p[%p] -> %p[%p]\n", old_fiber, old_fiber->stack.base, new_fiber, new_fiber->stack.base);
+ // if (DEBUG) fprintf(stderr, "fiber_setcontext: %p[%p] -> %p[%p]\n", (void*)old_fiber, old_fiber->stack.base, (void*)new_fiber, new_fiber->stack.base);
/* swap machine context */
- coroutine_transfer(&old_fiber->context, &new_fiber->context);
+ struct coroutine_context * from = coroutine_transfer(&old_fiber->context, &new_fiber->context);
+
+ if (from == NULL) {
+ rb_syserr_fail(errno, "coroutine_transfer");
+ }
+
+ /* restore thread context */
+ fiber_restore_thread(th, old_fiber);
// It's possible to get here, and new_fiber is already freed.
- // if (DEBUG) fprintf(stderr, "fiber_setcontext: %p[%p] <- %p[%p]\n", old_fiber, old_fiber->stack.base, new_fiber, new_fiber->stack.base);
+ // if (DEBUG) fprintf(stderr, "fiber_setcontext: %p[%p] <- %p[%p]\n", (void*)old_fiber, old_fiber->stack.base, (void*)new_fiber, new_fiber->stack.base);
}
NOINLINE(NORETURN(static void cont_restore_1(rb_context_t *)));
@@ -1670,9 +1674,6 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
if (cont_thread_value(cont) != th->self) {
rb_raise(rb_eRuntimeError, "continuation called across threads");
}
- if (cont->saved_ec.protect_tag != th->ec->protect_tag) {
- rb_raise(rb_eRuntimeError, "continuation called across stack rewinding barrier");
- }
if (cont->saved_ec.fiber_ptr) {
if (th->ec->fiber_ptr != cont->saved_ec.fiber_ptr) {
rb_raise(rb_eRuntimeError, "continuation called across fiber");
@@ -1757,8 +1758,8 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval)
* The concept of <em>non-blocking fiber</em> was introduced in Ruby 3.0.
* A non-blocking fiber, when reaching a operation that would normally block
* the fiber (like <code>sleep</code>, or wait for another process or I/O)
- # will yield control to other fibers and allow the <em>scheduler</em> to
- # handle blocking and waking up (resuming) this fiber when it can proceed.
+ * will yield control to other fibers and allow the <em>scheduler</em> to
+ * handle blocking and waking up (resuming) this fiber when it can proceed.
*
* For a Fiber to behave as non-blocking, it need to be created in Fiber.new with
* <tt>blocking: false</tt> (which is the default), and Fiber.scheduler
@@ -2031,13 +2032,13 @@ rb_fiber_set_scheduler(VALUE klass, VALUE scheduler)
return rb_fiber_scheduler_set(scheduler);
}
-NORETURN(static void rb_fiber_terminate(rb_fiber_t *fiber, int need_interrupt, VALUE err));
+static void rb_fiber_terminate(rb_fiber_t *fiber, int need_interrupt, VALUE err);
void
-rb_fiber_start(void)
+rb_fiber_start(rb_fiber_t *fiber)
{
- rb_thread_t * volatile th = GET_THREAD();
- rb_fiber_t *fiber = th->ec->fiber_ptr;
+ rb_thread_t * volatile th = fiber->cont.saved_ec.thread_ptr;
+
rb_proc_t *proc;
enum ruby_tag_type state;
int need_interrupt = TRUE;
@@ -2084,7 +2085,6 @@ rb_fiber_start(void)
}
rb_fiber_terminate(fiber, need_interrupt, err);
- VM_UNREACHABLE(rb_fiber_start);
}
static rb_fiber_t *
@@ -2101,12 +2101,7 @@ root_fiber_alloc(rb_thread_t *th)
DATA_PTR(fiber_value) = fiber;
fiber->cont.self = fiber_value;
-#ifdef COROUTINE_PRIVATE_STACK
- fiber->stack = fiber_pool_stack_acquire(&shared_fiber_pool);
- coroutine_initialize_main(&fiber->context, fiber_pool_stack_base(&fiber->stack), fiber->stack.available, th->ec->machine.stack_start);
-#else
coroutine_initialize_main(&fiber->context);
-#endif
return fiber;
}
@@ -2255,10 +2250,8 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, VALUE
if (cont_thread_value(cont) != th->self) {
rb_raise(rb_eFiberError, "fiber called across threads");
}
- else if (cont->saved_ec.protect_tag != th->ec->protect_tag) {
- rb_raise(rb_eFiberError, "fiber called across stack rewinding barrier");
- }
- else if (FIBER_TERMINATED_P(fiber)) {
+
+ if (FIBER_TERMINATED_P(fiber)) {
value = rb_exc_new2(rb_eFiberError, "dead fiber called");
if (!FIBER_TERMINATED_P(th->ec->fiber_ptr)) {
@@ -2307,9 +2300,12 @@ fiber_switch(rb_fiber_t *fiber, int argc, const VALUE *argv, int kw_splat, VALUE
fiber_store(fiber, th);
+ // We cannot free the stack until the pthread is joined:
+#ifndef COROUTINE_PTHREAD_CONTEXT
if (RTEST(resuming_fiber) && FIBER_TERMINATED_P(fiber)) {
fiber_stack_release(fiber);
}
+#endif
if (fiber_current()->blocking) {
th->blocking += 1;
@@ -2348,7 +2344,7 @@ rb_fiber_transfer(VALUE fiber_value, int argc, const VALUE *argv)
VALUE
rb_fiber_blocking_p(VALUE fiber)
{
- return (fiber_ptr(fiber)->blocking == 0) ? Qfalse : Qtrue;
+ return RBOOL(fiber_ptr(fiber)->blocking != 0);
}
/*
@@ -2388,26 +2384,24 @@ rb_fiber_close(rb_fiber_t *fiber)
}
static void
-rb_fiber_terminate(rb_fiber_t *fiber, int need_interrupt, VALUE err)
+rb_fiber_terminate(rb_fiber_t *fiber, int need_interrupt, VALUE error)
{
VALUE value = fiber->cont.value;
- rb_fiber_t *next_fiber;
VM_ASSERT(FIBER_RESUMED_P(fiber));
rb_fiber_close(fiber);
- coroutine_destroy(&fiber->context);
-
fiber->cont.machine.stack = NULL;
fiber->cont.machine.stack_size = 0;
- next_fiber = return_fiber(true);
+ rb_fiber_t *next_fiber = return_fiber(true);
+
if (need_interrupt) RUBY_VM_SET_INTERRUPT(&next_fiber->cont.saved_ec);
- if (RTEST(err))
- fiber_switch(next_fiber, -1, &err, RB_NO_KEYWORDS, Qfalse, false);
+
+ if (RTEST(error))
+ fiber_switch(next_fiber, -1, &error, RB_NO_KEYWORDS, Qfalse, false);
else
fiber_switch(next_fiber, 1, &value, RB_NO_KEYWORDS, Qfalse, false);
- VM_UNREACHABLE(rb_fiber_terminate);
}
VALUE
@@ -2436,7 +2430,9 @@ rb_fiber_resume_kw(VALUE fiber_value, int argc, const VALUE *argv, int kw_splat)
rb_raise(rb_eFiberError, "attempt to resume a transferring fiber");
}
- return fiber_switch(fiber, argc, argv, kw_splat, fiber_value, false);
+ VALUE result = fiber_switch(fiber, argc, argv, kw_splat, fiber_value, false);
+
+ return result;
}
VALUE
@@ -2500,8 +2496,6 @@ rb_fiber_m_resume(int argc, VALUE *argv, VALUE fiber)
return rb_fiber_resume_kw(fiber, argc, argv, rb_keyword_given_p());
}
-VALUE rb_fiber_transfer_kw(VALUE fiber_value, int argc, const VALUE *argv, int kw_splat);
-
/*
* call-seq:
* fiber.raise -> obj
diff --git a/coroutine/Stack.h b/coroutine/Stack.h
deleted file mode 100644
index b3f57dc..0000000
--- a/coroutine/Stack.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#ifndef COROUTINE_STACK_H
-#define COROUTINE_STACK_H 1
-
-/*
- * This file is part of the "Coroutine" project and released under the MIT License.
- *
- * Created by Samuel Williams on 10/11/2020.
- * Copyright, 2020, by Samuel Williams.
-*/
-
-#include COROUTINE_H
-
-#ifdef COROUTINE_PRIVATE_STACK
-#define COROUTINE_STACK_LOCAL(type, name) type *name = ruby_xmalloc(sizeof(type))
-#define COROUTINE_STACK_FREE(name) ruby_xfree(name)
-#else
-#define COROUTINE_STACK_LOCAL(type, name) type name##_local; type * name = &name##_local
-#define COROUTINE_STACK_FREE(name)
-#endif
-
-#endif /* COROUTINE_STACK_H */
diff --git a/coroutine/amd64/Context.h b/coroutine/amd64/Context.h
index 676975f..f626a47 100644
--- a/coroutine/amd64/Context.h
+++ b/coroutine/amd64/Context.h
@@ -22,6 +22,7 @@ enum {COROUTINE_REGISTERS = 6};
struct coroutine_context
{
void **stack_pointer;
+ void *argument;
};
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
diff --git a/coroutine/arm32/Context.h b/coroutine/arm32/Context.h
index a1c5e03..09410eb 100644
--- a/coroutine/arm32/Context.h
+++ b/coroutine/arm32/Context.h
@@ -23,6 +23,7 @@ enum {COROUTINE_REGISTERS = 8};
struct coroutine_context
{
void **stack_pointer;
+ void *argument;
};
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
diff --git a/coroutine/arm64/Context.h b/coroutine/arm64/Context.h
index 0ba7354..dbc6ac9 100644
--- a/coroutine/arm64/Context.h
+++ b/coroutine/arm64/Context.h
@@ -22,6 +22,7 @@ enum {COROUTINE_REGISTERS = 0xb0 / 8};
struct coroutine_context
{
void **stack_pointer;
+ void *argument;
};
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
diff --git a/coroutine/copy/Context.c b/coroutine/copy/Context.c
deleted file mode 100644
index aa8bb2f..0000000
--- a/coroutine/copy/Context.c
+++ /dev/null
@@ -1,162 +0,0 @@
-/*
- * This file is part of the "Coroutine" project and released under the MIT License.
- *
- * Created by Samuel Williams on 24/6/2019.
- * Copyright, 2019, by Samuel Williams.
-*/
-
-#include "Context.h"
-
-#include <stdint.h>
-
-// http://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html
-#ifndef __GNUC__
-#define __asm__ asm
-#endif
-
-#if defined(__sparc)
-__attribute__((noinline))
-// https://marc.info/?l=linux-sparc&m=131914569320660&w=2
-static void coroutine_flush_register_windows(void) {
- __asm__
-#ifdef __GNUC__
- __volatile__
-#endif
-#if defined(__sparcv9) || defined(__sparc_v9__) || defined(__arch64__)
-#ifdef __GNUC__
- ("flushw" : : : "%o7")
-#else
- ("flushw")
-#endif
-#else
- ("ta 0x03")
-#endif
- ;
-}
-#else
-static void coroutine_flush_register_windows(void) {}
-#endif
-
-__attribute__((noinline))
-void *coroutine_stack_pointer(void) {
- return (void*)(
- (char*)__builtin_frame_address(0)
- );
-}
-
-// Save the current stack to a private area. It is likely that when restoring the stack, this stack frame will be incomplete. But that is acceptable since the previous stack frame which called `setjmp` should be correctly restored.
-__attribute__((noinline))
-int coroutine_save_stack_1(struct coroutine_context * context) {
- assert(context->stack);
- assert(context->base);
-
- void *stack_pointer = coroutine_stack_pointer();
-
- // At this point, you may need to ensure on architectures that use register windows, that all registers are flushed to the stack, otherwise the copy of the stack will not contain the valid registers:
- coroutine_flush_register_windows();
-
- // Save stack to private area:
- if (stack_pointer < context->base) {
- size_t size = (char*)context->base - (char*)stack_pointer;
- assert(size <= context->size);
-
- memcpy(context->stack, stack_pointer, size);
- context->used = size;
- } else {
- size_t size = (char*)stack_pointer - (char*)context->base;
- assert(size <= context->size);
-
- memcpy(context->stack, context->base, size);
- context->used = size;
- }
-
- // Initialized:
- return 0;
-}
-
-// Copy the current stack to a private memory buffer.
-int coroutine_save_stack(struct coroutine_context * context) {
- if (_setjmp(context->state)) {
- // Restored.
- return 1;
- }
-
- // We need to invoke the memory copy from one stack frame deeper than the one that calls setjmp. That is because if you don't do this, the setjmp might be restored into an invalid stack frame (truncated, etc):
- return coroutine_save_stack_1(context);
-}
-
-__attribute__((noreturn, noinline))
-void coroutine_restore_stack_padded(struct coroutine_context *context, void * buffer) {
- void *stack_pointer = coroutine_stack_pointer();
-
- assert(context->base);
-
- // At this point, you may need to ensure on architectures that use register windows, that all registers are flushed to the stack, otherwise when we copy in the new stack, the registers would not be updated:
- coroutine_flush_register_windows();
-
- // Restore stack from private area:
- if (stack_pointer < context->base) {
- void * bottom = (char*)context->base - context->used;
- assert(bottom > stack_pointer);
-
- memcpy(bottom, context->stack, context->used);
- } else {
- void * top = (char*)context->base + context->used;
- assert(top < stack_pointer);
-
- memcpy(context->base, context->stack, context->used);
- }
-
- // Restore registers. The `buffer` is to force the compiler NOT to elide he buffer and `alloca`:
- _longjmp(context->state, (int)(1 | (intptr_t)buffer));
-}
-
-// In order to swap between coroutines, we need to swap the stack and registers.
-// `setjmp` and `longjmp` are able to swap registers, but what about swapping stacks? You can use `memcpy` to copy the current stack to a private area and `memcpy` to copy the private stack of the next coroutine to the main stack.
-// But if the stack yop are copying in to the main stack is bigger than the currently executing stack, the `memcpy` will clobber the current stack frame (including the context argument). So we use `alloca` to push the current stack frame *beyond* the stack we are about to copy in. This ensures the current stack frame in `coroutine_restore_stack_padded` remains valid for calling `longjmp`.
-__attribute__((noreturn))
-void coroutine_restore_stack(struct coroutine_context *context) {
- void *stack_pointer = coroutine_stack_pointer();
- void *buffer = NULL;
-
- // We must ensure that the next stack frame is BEYOND the stack we are restoring:
- if (stack_pointer < context->base) {
- intptr_t offset = (intptr_t)stack_pointer - ((intptr_t)context->base - context->used);
- if (offset > 0) buffer = alloca(offset);
- } else {
- intptr_t offset = ((intptr_t)context->base + context->used) - (intptr_t)stack_pointer;
- if (offset > 0) buffer = alloca(offset);
- }
-
- assert(context->used > 0);
-
- coroutine_restore_stack_padded(context, buffer);
-}
-
-struct coroutine_context *coroutine_transfer(struct coroutine_context *current, struct coroutine_context *target)
-{
- struct coroutine_context *previous = target->from;
-
- // In theory, either this condition holds true, or we should assign the base address to target:
- assert(current->base == target->base);
- // If you are trying to copy the coroutine to a different thread
- // target->base = current->base
-
- target->from = current;
-
- assert(current != target);
-
- // It's possible to come here, even thought the current fiber has been terminated. We are never going to return so we don't bother saving the stack.
-
- if (current->stack) {
- if (coroutine_save_stack(current) == 0) {
- coroutine_restore_stack(target);
- }
- } else {
- coroutine_restore_stack(target);
- }
-
- target->from = previous;
-
- return target;
-}
diff --git a/coroutine/copy/Context.h b/coroutine/copy/Context.h
deleted file mode 100644
index 2cb2bc1..0000000
--- a/coroutine/copy/Context.h
+++ /dev/null
@@ -1,98 +0,0 @@
-#ifndef COROUTINE_COPY_CONTEXT_H
-#define COROUTINE_COPY_CONTEXT_H 1
-
-/*
- * This file is part of the "Coroutine" project and released under the MIT License.
- *
- * Created by Samuel Williams on 27/6/2019.
- * Copyright, 2019, by Samuel Williams.
-*/
-
-#pragma once
-
-#include <assert.h>
-#include <stddef.h>
-#include <setjmp.h>
-#include <string.h>
-#include <stdlib.h>
-
-/* OpenBSD supports alloca, but does not include alloca.h */
-#ifndef __OpenBSD__
-#include <alloca.h>
-#endif
-
-#define COROUTINE __attribute__((noreturn)) void
-
-#ifdef HAVE_STDINT_H
-#include <stdint.h>
-#if INTPTR_MAX <= INT32_MAX
-#define COROUTINE_LIMITED_ADDRESS_SPACE
-#endif
-#endif
-
-// This stack copying implementation which uses a private stack for each coroutine, including the main one.
-#define COROUTINE_PRIVATE_STACK
-
-struct coroutine_context
-{
- // Private stack:
- void *stack;
- size_t size, used;
-
- // The top (or bottom) of the currently executing stack:
- void *base;
-
- jmp_buf state;
-
- struct coroutine_context *from;
-};
-
-typedef COROUTINE(*coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
-
-int coroutine_save_stack(struct coroutine_context * context);
-COROUTINE coroutine_restore_stack(struct coroutine_context *context);
-
-// @param stack The private stack area memory allocation (pointer to lowest address).
-// @param size The size of the private stack area.
-// @param base A stack pointer to the base of the main stack. On x86 hardware, this is the upper extent of the region that will be copied to the private stack.
-static inline void coroutine_initialize_main(struct coroutine_context *context, void *stack, size_t size, void *base) {
- assert(stack);
- assert(size >= 1024);
-
- context->stack = stack;
- context->size = size;
- context->used = 0;
-
- assert(base);
- context->base = base;
-
- context->from = NULL;
-}
-
-// @param start The start function to invoke.
-static inline void coroutine_initialize(
- struct coroutine_context *context,
- coroutine_start start,
- void *stack,
- size_t size,
- void *base
-) {
- assert(start);
-
- coroutine_initialize_main(context, stack, size, base);
-
- if (coroutine_save_stack(context)) {
- start(context->from, context);
- }
-}
-
-struct coroutine_context *coroutine_transfer(struct coroutine_context *current, register struct coroutine_context *target);
-
-static inline void coroutine_destroy(struct coroutine_context *context)
-{
- context->stack = NULL;
- context->size = 0;
- context->from = NULL;
-}
-
-#endif /* COROUTINE_COPY_CONTEXT_H */
diff --git a/coroutine/emscripten/Context.h b/coroutine/emscripten/Context.h
index aefbb92..361e241 100644
--- a/coroutine/emscripten/Context.h
+++ b/coroutine/emscripten/Context.h
@@ -26,6 +26,7 @@ struct coroutine_context
emscripten_fiber_t state;
coroutine_start entry_func;
struct coroutine_context * from;
+ void *argument;
};
COROUTINE coroutine_trampoline(void * _context);
diff --git a/coroutine/ppc64le/Context.h b/coroutine/ppc64le/Context.h
index 7a7d9fe..fbfaa2e 100644
--- a/coroutine/ppc64le/Context.h
+++ b/coroutine/ppc64le/Context.h
@@ -19,6 +19,7 @@ enum {
struct coroutine_context
{
void **stack_pointer;
+ void *argument;
};
typedef COROUTINE(* coroutine_start)(struct coroutine_context *from, struct coroutine_context *self);
diff --git a/coroutine/pthread/Context.c b/coroutine/pthread/Context.c
new file mode 100644
index 0000000..38774cd
--- /dev/null
+++ b/coroutine/pthread/Context.c
@@ -0,0 +1,272 @@
+/*
+ * This file is part of the "Coroutine" project and released under the MIT License.
+ *
+ * Created by Samuel Williams on 24/6/2021.
+ * Copyright, 2021, by Samuel Williams.
+*/
+
+#include "Context.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+
+static const int DEBUG = 0;
+
+static
+int check(const char * message, int result) {
+ if (result) {
+ switch (result) {
+ case EDEADLK:
+ if (DEBUG) fprintf(stderr, "deadlock detected result=%d errno=%d\n", result, errno);
+ break;
+ default:
+ if (DEBUG) fprintf(stderr, "error detected result=%d errno=%d\n", result, errno);
+ perror(message);
+ }
+ }
+
+ assert(result == 0);
+
+ return result;
+}
+
+void coroutine_initialize_main(struct coroutine_context * context) {
+ context->id = pthread_self();
+
+ check("coroutine_initialize_main:pthread_cond_init",
+ pthread_cond_init(&context->schedule, NULL)
+ );
+
+ context->shared = (struct coroutine_shared*)malloc(sizeof(struct coroutine_shared));
+ assert(context->shared);
+
+ context->shared->main = context;
+ context->shared->count = 1;
+
+ if (DEBUG) {
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_ERRORCHECK);
+
+ check("coroutine_initialize_main:pthread_mutex_init",
+ pthread_mutex_init(&context->shared->guard, &attr)
+ );
+ } else {
+ check("coroutine_initialize_main:pthread_mutex_init",
+ pthread_mutex_init(&context->shared->guard, NULL)
+ );
+ }
+}
+
+static
+void coroutine_release(struct coroutine_context *context) {
+ if (context->shared) {
+ size_t count = (context->shared->count -= 1);
+
+ if (count == 0) {
+ if (DEBUG) fprintf(stderr, "coroutine_release:pthread_mutex_destroy(%p)\n", &context->shared->guard);
+ pthread_mutex_destroy(&context->shared->guard);
+ free(context->shared);
+ }
+
+ context->shared = NULL;
+
+ if (DEBUG) fprintf(stderr, "coroutine_release:pthread_cond_destroy(%p)\n", &context->schedule);
+ pthread_cond_destroy(&context->schedule);
+ }
+}
+
+void coroutine_initialize(
+ struct coroutine_context *context,
+ coroutine_start start,
+ void *stack,
+ size_t size
+) {
+ assert(start && stack && size >= 1024);
+
+ // We will create the thread when we first transfer, but save the details now:
+ context->shared = NULL;
+ context->start = start;
+ context->stack = stack;
+ context->size = size;
+}
+
+static
+int is_locked(pthread_mutex_t * mutex) {
+ int result = pthread_mutex_trylock(mutex);
+
+ // If we could successfully lock the mutex:
+ if (result == 0) {
+ pthread_mutex_unlock(mutex);
+ // We could lock the mutex, so it wasn't locked:
+ return 0;
+ } else {
+ // Otherwise we couldn't lock it because it's already locked:
+ return 1;
+ }
+}
+
+static
+void coroutine_guard_unlock(void * _context)
+{
+ struct coroutine_context * context = _context;
+
+ if (DEBUG) fprintf(stderr, "coroutine_guard_unlock:pthread_mutex_unlock\n");
+
+ check("coroutine_guard_unlock:pthread_mutex_unlock",
+ pthread_mutex_unlock(&context->shared->guard)
+ );
+}
+
+static
+void coroutine_wait(struct coroutine_context *context)
+{
+ if (DEBUG) fprintf(stderr, "coroutine_wait:pthread_mutex_lock(guard=%p is_locked=%d)\n", &context->shared->guard, is_locked(&context->shared->guard));
+ check("coroutine_wait:pthread_mutex_lock",
+ pthread_mutex_lock(&context->shared->guard)
+ );
+
+ if (DEBUG) fprintf(stderr, "coroutine_wait:pthread_mutex_unlock(guard)\n");
+ pthread_mutex_unlock(&context->shared->guard);
+}
+
+static
+void coroutine_trampoline_cleanup(void *_context) {
+ struct coroutine_context * context = _context;
+ coroutine_release(context);
+}
+
+void * coroutine_trampoline(void * _context)
+{
+ struct coroutine_context * context = _context;
+ assert(context->shared);
+
+ pthread_cleanup_push(coroutine_trampoline_cleanup, context);
+
+ coroutine_wait(context);
+
+ context->start(context->from, context);
+
+ pthread_cleanup_pop(1);
+
+ return NULL;
+}
+
+static
+int coroutine_create_thread(struct coroutine_context *context)
+{
+ int result;
+
+ pthread_attr_t attr;
+ result = pthread_attr_init(&attr);
+ if (result != 0) {
+ return result;
+ }
+
+ result = pthread_attr_setstack(&attr, context->stack, (size_t)context->size);
+ if (result != 0) {
+ pthread_attr_destroy(&attr);
+ return result;
+ }
+
+ result = pthread_cond_init(&context->schedule, NULL);
+ if (result != 0) {
+ pthread_attr_destroy(&attr);
+ return result;
+ }
+
+ result = pthread_create(&context->id, &attr, coroutine_trampoline, context);
+ if (result != 0) {
+ pthread_attr_destroy(&attr);
+ if (DEBUG) fprintf(stderr, "coroutine_create_thread:pthread_cond_destroy(%p)\n", &context->schedule);
+ pthread_cond_destroy(&context->schedule);
+ return result;
+ }
+
+ context->shared->count += 1;
+
+ return result;
+}
+
+struct coroutine_context * coroutine_transfer(struct coroutine_context * current, struct coroutine_context * target)
+{
+ assert(current->shared);
+
+ struct coroutine_context * previous = target->from;
+ target->from = current;
+
+ if (DEBUG) fprintf(stderr, "coroutine_transfer:pthread_mutex_lock(guard=%p is_locked=%d)\n", &current->shared->guard, is_locked(&current->shared->guard));
+ pthread_mutex_lock(&current->shared->guard);
+ pthread_cleanup_push(coroutine_guard_unlock, current);
+
+ // First transfer:
+ if (target->shared == NULL) {
+ target->shared = current->shared;
+
+ if (DEBUG) fprintf(stderr, "coroutine_transfer:coroutine_create_thread...\n");
+ if (coroutine_create_thread(target)) {
+ if (DEBUG) fprintf(stderr, "coroutine_transfer:coroutine_create_thread failed\n");
+ target->shared = NULL;
+ target->from = previous;
+ return NULL;
+ }
+ } else {
+ if (DEBUG) fprintf(stderr, "coroutine_transfer:pthread_cond_signal(target)\n");
+ pthread_cond_signal(&target->schedule);
+ }
+
+ // A side effect of acting upon a cancellation request while in a condition wait is that the mutex is (in effect) re-acquired before calling the first cancellation cleanup handler. If cancelled, pthread_cond_wait immediately invokes cleanup handlers.
+ if (DEBUG) fprintf(stderr, "coroutine_transfer:pthread_cond_wait(schedule=%p, guard=%p, is_locked=%d)\n", &current->schedule, &current->shared->guard, is_locked(&current->shared->guard));
+ check("coroutine_transfer:pthread_cond_wait",
+ pthread_cond_wait(&current->schedule, &current->shared->guard)
+ );
+
+ if (DEBUG) fprintf(stderr, "coroutine_transfer:pthread_cleanup_pop\n");
+ pthread_cleanup_pop(1);
+
+#ifdef __FreeBSD__
+ // Apparently required for FreeBSD:
+ pthread_testcancel();
+#endif
+
+ target->from = previous;
+
+ return target;
+}
+
+static
+void coroutine_join(struct coroutine_context * context) {
+ if (DEBUG) fprintf(stderr, "coroutine_join:pthread_cancel\n");
+ int result = pthread_cancel(context->id);
+ if (result == -1 && errno == ESRCH) {
+ // The thread may be dead due to fork, so it cannot be joined and this doesn't represent a real error:
+ return;
+ }
+
+ check("coroutine_join:pthread_cancel", result);
+
+ if (DEBUG) fprintf(stderr, "coroutine_join:pthread_join\n");
+ check("coroutine_join:pthread_join",
+ pthread_join(context->id, NULL)
+ );
+
+ if (DEBUG) fprintf(stderr, "coroutine_join:pthread_join done\n");
+}
+
+void coroutine_destroy(struct coroutine_context * context)
+{
+ if (DEBUG) fprintf(stderr, "coroutine_destroy\n");
+
+ assert(context);
+
+ // We are already destroyed or never created:
+ if (context->shared == NULL) return;
+
+ if (context == context->shared->main) {
+ context->shared->main = NULL;
+ coroutine_release(context);
+ } else {
+ coroutine_join(context);
+ assert(context->shared == NULL);
+ }
+}
diff --git a/coroutine/pthread/Context.h b/coroutine/pthread/Context.h
new file mode 100644
index 0000000..6d551ee
--- /dev/null
+++ b/coroutine/pthread/Context.h
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the "Coroutine" project and released under the MIT License.
+ *
+ * Created by Samuel Williams on 24/6/2021.
+ * Copyright, 2021, by Samuel Williams.
+*/
+
+#pragma once
+
+#include <assert.h>
+#include <stddef.h>
+#include <pthread.h>
+
+#define COROUTINE void
+
+#define COROUTINE_PTHREAD_CONTEXT
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#if INTPTR_MAX <= INT32_MAX
+#define COROUTINE_LIMITED_ADDRESS_SPACE
+#endif
+#endif
+
+struct coroutine_context;
+
+struct coroutine_shared
+{
+ pthread_mutex_t guard;
+ struct coroutine_context * main;
+
+ size_t count;
+};