summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--NEWS.md4
-rw-r--r--addr2line.c3
-rw-r--r--common.mk236
-rw-r--r--configure.ac7
-rw-r--r--doc/string/new.rdoc48
-rw-r--r--ext/digest/defs.h22
-rw-r--r--ext/digest/digest_conf.rb18
-rw-r--r--ext/digest/md5/md5cc.h8
-rw-r--r--ext/digest/md5/md5init.c1
-rw-r--r--ext/digest/sha1/sha1.c8
-rw-r--r--ext/json/generator/extconf.rb4
-rw-r--r--ext/json/generator/generator.c30
-rw-r--r--ext/json/generator/simd.h6
-rw-r--r--ext/psych/lib/psych/class_loader.rb1
-rw-r--r--ext/psych/lib/psych/versions.rb2
-rw-r--r--ext/psych/lib/psych/visitors/to_ruby.rb46
-rw-r--r--ext/psych/lib/psych/visitors/yaml_tree.rb40
-rw-r--r--ext/psych/psych_to_ruby.c10
-rw-r--r--ext/strscan/strscan.c7
-rw-r--r--gc.c12
-rw-r--r--jit.c423
-rw-r--r--lib/rubygems/gemcutter_utilities.rb5
-rw-r--r--string.c7
-rw-r--r--symbol.c2
-rw-r--r--template/Makefile.in1
-rw-r--r--test/objspace/test_objspace.rb5
-rw-r--r--test/psych/test_data.rb69
-rw-r--r--test/psych/test_object_references.rb5
-rw-r--r--test/psych/test_safe_load.rb32
-rw-r--r--test/psych/test_serialize_subclasses.rb18
-rw-r--r--test/psych/test_yaml.rb47
-rw-r--r--test/psych/visitors/test_yaml_tree.rb21
-rw-r--r--test/ruby/test_iseq.rb40
-rw-r--r--test/rubygems/test_gem_commands_owner_command.rb12
-rw-r--r--test/rubygems/test_gem_commands_push_command.rb16
-rw-r--r--test/rubygems/test_gem_commands_yank_command.rb12
-rw-r--r--test/rubygems/test_gem_gemcutter_utilities.rb12
-rw-r--r--test/strscan/test_stringscanner.rb6
-rw-r--r--tool/ruby_vm/views/insns_info.inc.erb3
-rwxr-xr-xtool/sync_default_gems.rb4
-rw-r--r--vm_method.c1
-rw-r--r--wasm/setjmp.h2
-rw-r--r--yjit.c403
-rw-r--r--yjit/bindgen/src/main.rs1
-rw-r--r--yjit/src/cruby_bindings.inc.rs133
-rw-r--r--zjit.c408
-rw-r--r--zjit/bindgen/src/main.rs1
-rw-r--r--zjit/src/cruby_bindings.inc.rs96
-rw-r--r--zjit/src/hir.rs84
49 files changed, 1322 insertions, 1060 deletions
diff --git a/NEWS.md b/NEWS.md
index 08ec7ace86..c6a1d9522a 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -66,9 +66,9 @@ The following default gems are updated.
* json 2.11.3
* optparse 0.7.0.dev.2
* prism 1.4.0
-* psych 5.2.3
+* psych 5.2.4
* stringio 3.1.8.dev
-* strscan 3.1.4.dev
+* strscan 3.1.5.dev
* uri 1.0.3
The following bundled gems are added.
diff --git a/addr2line.c b/addr2line.c
index dc0892e308..745364cc0f 100644
--- a/addr2line.c
+++ b/addr2line.c
@@ -2175,9 +2175,8 @@ fill_lines(int num_traces, void **traces, int check_debuglink,
}
}
- if (offset == -1) {
+ if (offset == 0) {
/* main executable */
- offset = 0;
if (dynsym_shdr && dynstr_shdr) {
char *strtab = file + dynstr_shdr->sh_offset;
ElfW(Sym) *symtab = (ElfW(Sym) *)(file + dynsym_shdr->sh_offset);
diff --git a/common.mk b/common.mk
index c1fa9ae438..7337f8ad62 100644
--- a/common.mk
+++ b/common.mk
@@ -189,6 +189,7 @@ COMMONOBJS = array.$(OBJEXT) \
$(YJIT_LIBOBJ) \
$(ZJIT_OBJ) \
$(ZJIT_LIBOBJ) \
+ $(JIT_OBJ) \
$(COROUTINE_OBJ) \
$(DTRACE_OBJ) \
$(BUILTIN_ENCOBJS) \
@@ -9156,6 +9157,241 @@ iseq.$(OBJEXT): {$(VPATH)}vm_debug.h
iseq.$(OBJEXT): {$(VPATH)}vm_opts.h
iseq.$(OBJEXT): {$(VPATH)}vm_sync.h
iseq.$(OBJEXT): {$(VPATH)}yjit.h
+jit.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
+jit.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
+jit.$(OBJEXT): $(CCAN_DIR)/list/list.h
+jit.$(OBJEXT): $(CCAN_DIR)/str/str.h
+jit.$(OBJEXT): $(hdrdir)/ruby/ruby.h
+jit.$(OBJEXT): $(top_srcdir)/internal/array.h
+jit.$(OBJEXT): $(top_srcdir)/internal/basic_operators.h
+jit.$(OBJEXT): $(top_srcdir)/internal/class.h
+jit.$(OBJEXT): $(top_srcdir)/internal/compilers.h
+jit.$(OBJEXT): $(top_srcdir)/internal/gc.h
+jit.$(OBJEXT): $(top_srcdir)/internal/imemo.h
+jit.$(OBJEXT): $(top_srcdir)/internal/sanitizers.h
+jit.$(OBJEXT): $(top_srcdir)/internal/serial.h
+jit.$(OBJEXT): $(top_srcdir)/internal/set_table.h
+jit.$(OBJEXT): $(top_srcdir)/internal/static_assert.h
+jit.$(OBJEXT): $(top_srcdir)/internal/variable.h
+jit.$(OBJEXT): $(top_srcdir)/internal/vm.h
+jit.$(OBJEXT): $(top_srcdir)/internal/warnings.h
+jit.$(OBJEXT): $(top_srcdir)/prism/defines.h
+jit.$(OBJEXT): $(top_srcdir)/prism/encoding.h
+jit.$(OBJEXT): $(top_srcdir)/prism/node.h
+jit.$(OBJEXT): $(top_srcdir)/prism/options.h
+jit.$(OBJEXT): $(top_srcdir)/prism/pack.h
+jit.$(OBJEXT): $(top_srcdir)/prism/parser.h
+jit.$(OBJEXT): $(top_srcdir)/prism/prettyprint.h
+jit.$(OBJEXT): $(top_srcdir)/prism/prism.h
+jit.$(OBJEXT): $(top_srcdir)/prism/regexp.h
+jit.$(OBJEXT): $(top_srcdir)/prism/static_literals.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_buffer.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_char.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_constant_pool.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_integer.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_list.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_memchr.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_newline_list.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_string.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strncasecmp.h
+jit.$(OBJEXT): $(top_srcdir)/prism/util/pm_strpbrk.h
+jit.$(OBJEXT): {$(VPATH)}assert.h
+jit.$(OBJEXT): {$(VPATH)}atomic.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/assume.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/attributes.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/bool.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/gcc_version_since.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/inttypes.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/limits.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/long_long.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/stdalign.h
+jit.$(OBJEXT): {$(VPATH)}backward/2/stdarg.h
+jit.$(OBJEXT): {$(VPATH)}builtin.h
+jit.$(OBJEXT): {$(VPATH)}config.h
+jit.$(OBJEXT): {$(VPATH)}constant.h
+jit.$(OBJEXT): {$(VPATH)}debug_counter.h
+jit.$(OBJEXT): {$(VPATH)}defines.h
+jit.$(OBJEXT): {$(VPATH)}encoding.h
+jit.$(OBJEXT): {$(VPATH)}id.h
+jit.$(OBJEXT): {$(VPATH)}id_table.h
+jit.$(OBJEXT): {$(VPATH)}insns.def
+jit.$(OBJEXT): {$(VPATH)}insns.inc
+jit.$(OBJEXT): {$(VPATH)}insns_info.inc
+jit.$(OBJEXT): {$(VPATH)}intern.h
+jit.$(OBJEXT): {$(VPATH)}internal.h
+jit.$(OBJEXT): {$(VPATH)}internal/abi.h
+jit.$(OBJEXT): {$(VPATH)}internal/anyargs.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/char.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/double.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/fixnum.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/gid_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/int.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/intptr_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/long_long.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/mode_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/off_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/pid_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/short.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/size_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/st_data_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/arithmetic/uid_t.h
+jit.$(OBJEXT): {$(VPATH)}internal/assume.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/alloc_size.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/artificial.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/cold.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/const.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/constexpr.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/deprecated.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/diagnose_if.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/enum_extensibility.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/error.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/flag_enum.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/forceinline.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/format.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/maybe_unused.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/noalias.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/nodiscard.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/noexcept.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/noinline.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/nonnull.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/noreturn.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/packed_struct.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/pure.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/restrict.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/returns_nonnull.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/warning.h
+jit.$(OBJEXT): {$(VPATH)}internal/attr/weakref.h
+jit.$(OBJEXT): {$(VPATH)}internal/cast.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/apple.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/clang.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/gcc.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/intel.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/msvc.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_is/sunpro.h
+jit.$(OBJEXT): {$(VPATH)}internal/compiler_since.h
+jit.$(OBJEXT): {$(VPATH)}internal/config.h
+jit.$(OBJEXT): {$(VPATH)}internal/constant_p.h
+jit.$(OBJEXT): {$(VPATH)}internal/core.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rarray.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rbasic.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rbignum.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rclass.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rdata.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rfile.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rhash.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/robject.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rregexp.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rstring.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rstruct.h
+jit.$(OBJEXT): {$(VPATH)}internal/core/rtypeddata.h
+jit.$(OBJEXT): {$(VPATH)}internal/ctype.h
+jit.$(OBJEXT): {$(VPATH)}internal/dllexport.h
+jit.$(OBJEXT): {$(VPATH)}internal/dosish.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/coderange.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/ctype.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/encoding.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/pathname.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/re.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/sprintf.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/string.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/symbol.h
+jit.$(OBJEXT): {$(VPATH)}internal/encoding/transcode.h
+jit.$(OBJEXT): {$(VPATH)}internal/error.h
+jit.$(OBJEXT): {$(VPATH)}internal/eval.h
+jit.$(OBJEXT): {$(VPATH)}internal/event.h
+jit.$(OBJEXT): {$(VPATH)}internal/fl_type.h
+jit.$(OBJEXT): {$(VPATH)}internal/gc.h
+jit.$(OBJEXT): {$(VPATH)}internal/glob.h
+jit.$(OBJEXT): {$(VPATH)}internal/globals.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/attribute.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/builtin.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/c_attribute.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/cpp_attribute.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/declspec_attribute.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/extension.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/feature.h
+jit.$(OBJEXT): {$(VPATH)}internal/has/warning.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/array.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/bignum.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/class.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/compar.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/complex.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/cont.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/dir.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/enum.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/enumerator.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/error.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/eval.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/file.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/hash.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/io.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/load.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/marshal.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/numeric.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/object.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/parse.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/proc.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/process.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/random.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/range.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/rational.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/re.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/ruby.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/select.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/select/largesize.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/signal.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/sprintf.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/string.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/struct.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/thread.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/time.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/variable.h
+jit.$(OBJEXT): {$(VPATH)}internal/intern/vm.h
+jit.$(OBJEXT): {$(VPATH)}internal/interpreter.h
+jit.$(OBJEXT): {$(VPATH)}internal/iterator.h
+jit.$(OBJEXT): {$(VPATH)}internal/memory.h
+jit.$(OBJEXT): {$(VPATH)}internal/method.h
+jit.$(OBJEXT): {$(VPATH)}internal/module.h
+jit.$(OBJEXT): {$(VPATH)}internal/newobj.h
+jit.$(OBJEXT): {$(VPATH)}internal/scan_args.h
+jit.$(OBJEXT): {$(VPATH)}internal/special_consts.h
+jit.$(OBJEXT): {$(VPATH)}internal/static_assert.h
+jit.$(OBJEXT): {$(VPATH)}internal/stdalign.h
+jit.$(OBJEXT): {$(VPATH)}internal/stdbool.h
+jit.$(OBJEXT): {$(VPATH)}internal/stdckdint.h
+jit.$(OBJEXT): {$(VPATH)}internal/symbol.h
+jit.$(OBJEXT): {$(VPATH)}internal/value.h
+jit.$(OBJEXT): {$(VPATH)}internal/value_type.h
+jit.$(OBJEXT): {$(VPATH)}internal/variable.h
+jit.$(OBJEXT): {$(VPATH)}internal/warning_push.h
+jit.$(OBJEXT): {$(VPATH)}internal/xmalloc.h
+jit.$(OBJEXT): {$(VPATH)}iseq.h
+jit.$(OBJEXT): {$(VPATH)}jit.c
+jit.$(OBJEXT): {$(VPATH)}method.h
+jit.$(OBJEXT): {$(VPATH)}missing.h
+jit.$(OBJEXT): {$(VPATH)}node.h
+jit.$(OBJEXT): {$(VPATH)}onigmo.h
+jit.$(OBJEXT): {$(VPATH)}oniguruma.h
+jit.$(OBJEXT): {$(VPATH)}prism/ast.h
+jit.$(OBJEXT): {$(VPATH)}prism/diagnostic.h
+jit.$(OBJEXT): {$(VPATH)}prism/version.h
+jit.$(OBJEXT): {$(VPATH)}prism_compile.h
+jit.$(OBJEXT): {$(VPATH)}ruby_assert.h
+jit.$(OBJEXT): {$(VPATH)}ruby_atomic.h
+jit.$(OBJEXT): {$(VPATH)}rubyparser.h
+jit.$(OBJEXT): {$(VPATH)}shape.h
+jit.$(OBJEXT): {$(VPATH)}st.h
+jit.$(OBJEXT): {$(VPATH)}subst.h
+jit.$(OBJEXT): {$(VPATH)}thread_$(THREAD_MODEL).h
+jit.$(OBJEXT): {$(VPATH)}thread_native.h
+jit.$(OBJEXT): {$(VPATH)}vm_callinfo.h
+jit.$(OBJEXT): {$(VPATH)}vm_core.h
+jit.$(OBJEXT): {$(VPATH)}vm_debug.h
+jit.$(OBJEXT): {$(VPATH)}vm_opts.h
+jit.$(OBJEXT): {$(VPATH)}vm_sync.h
load.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
load.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
load.$(OBJEXT): $(CCAN_DIR)/list/list.h
diff --git a/configure.ac b/configure.ac
index c76db94d84..4bcd614f44 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3967,6 +3967,7 @@ AS_CASE(["${YJIT_SUPPORT}"],
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
])
YJIT_OBJ='yjit.$(OBJEXT)'
+ JIT_OBJ='jit.$(OBJEXT)'
AS_IF([test x"$YJIT_SUPPORT" != "xyes" ], [
AC_DEFINE_UNQUOTED(YJIT_SUPPORT, [$YJIT_SUPPORT])
])
@@ -4008,6 +4009,7 @@ AS_CASE(["${ZJIT_SUPPORT}"],
LDFLAGS="$LDFLAGS -lpthread -lc++abi"
])
ZJIT_OBJ='zjit.$(OBJEXT)'
+ JIT_OBJ='jit.$(OBJEXT)'
AS_IF([test x"$ZJIT_SUPPORT" != "xyes" ], [
AC_DEFINE_UNQUOTED(ZJIT_SUPPORT, [$ZJIT_SUPPORT])
])
@@ -4025,8 +4027,9 @@ AC_SUBST(ZJIT_CARGO_BUILD_ARGS)dnl for selecting Rust build profiles
AC_SUBST(YJIT_LIBS)dnl for optionally building the Rust parts of YJIT
AC_SUBST(YJIT_OBJ)dnl for optionally building the C parts of YJIT
AC_SUBST(ZJIT_SUPPORT)dnl what flavor of ZJIT the Ruby build includes
-AC_SUBST(ZJIT_LIBS)dnl for optionally building the Rust parts of YJIT
-AC_SUBST(ZJIT_OBJ)dnl for optionally building the C parts of YJIT
+AC_SUBST(ZJIT_LIBS)dnl for optionally building the Rust parts of ZJIT
+AC_SUBST(ZJIT_OBJ)dnl for optionally building the C parts of ZJIT
+AC_SUBST(JIT_OBJ)dnl for optionally building C glue code for Rust FFI
}
[begin]_group "build section" && {
diff --git a/doc/string/new.rdoc b/doc/string/new.rdoc
index 1d44291f76..e2752d6e1f 100644
--- a/doc/string/new.rdoc
+++ b/doc/string/new.rdoc
@@ -1,34 +1,38 @@
-Returns a new \String that is a copy of +string+.
+Returns a new \String object containing the given +string+.
-With no arguments, returns the empty string with the Encoding <tt>ASCII-8BIT</tt>:
+The +options+ are optional keyword options (see below).
- s = String.new
- s # => ""
- s.encoding # => #<Encoding:ASCII-8BIT>
+With no argument given and keyword +encoding+ also not given,
+returns an empty string with the Encoding <tt>ASCII-8BIT</tt>:
-With optional argument +string+ and no keyword arguments,
-returns a copy of +string+ with the same encoding:
+ s = String.new # => ""
+ s.encoding # => #<Encoding:ASCII-8BIT>
- String.new('foo') # => "foo"
- String.new('тест') # => "тест"
- String.new('こんにちは') # => "こんにちは"
+With argument +string+ given and keyword option +encoding+ not given,
+returns a new string with the same encoding as +string+:
+
+ s0 = 'foo'.encode(Encoding::UTF_16)
+ s1 = String.new(s0)
+ s1.encoding # => #<Encoding:UTF-16 (dummy)>
(Unlike \String.new,
a {string literal}[rdoc-ref:syntax/literals.rdoc@String+Literals] like <tt>''</tt> or a
{here document literal}[rdoc-ref:syntax/literals.rdoc@Here+Document+Literals]
always has {script encoding}[rdoc-ref:encodings.rdoc@Script+Encoding].)
-With optional keyword argument +encoding+, returns a copy of +string+
-with the specified encoding;
+With keyword option +encoding+ given,
+returns a string with the specified encoding;
the +encoding+ may be an Encoding object, an encoding name,
or an encoding name alias:
+ String.new(encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
+ String.new('', encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: Encoding::US_ASCII).encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: 'US-ASCII').encoding # => #<Encoding:US-ASCII>
String.new('foo', encoding: 'ASCII').encoding # => #<Encoding:US-ASCII>
The given encoding need not be valid for the string's content,
-and that validity is not checked:
+and its validity is not checked:
s = String.new('こんにちは', encoding: 'ascii')
s.valid_encoding? # => false
@@ -37,19 +41,11 @@ But the given +encoding+ itself is checked:
String.new('foo', encoding: 'bar') # Raises ArgumentError.
-With optional keyword argument +capacity+, returns a copy of +string+
-(or an empty string, if +string+ is not given);
-the given +capacity+ is advisory only,
+With keyword option +capacity+ given,
+the given value is advisory only,
and may or may not set the size of the internal buffer,
which may in turn affect performance:
- String.new(capacity: 1)
- String.new('foo', capacity: 4096)
-
-Note that Ruby strings are null-terminated internally, so the internal
-buffer size will be one or more bytes larger than the requested capacity
-depending on the encoding.
-
-The +string+, +encoding+, and +capacity+ arguments may all be used together:
-
- String.new('hello', encoding: 'UTF-8', capacity: 25)
+ String.new('foo', capacity: 1) # Buffer size is at least 4 (includes terminal null byte).
+ String.new('foo', capacity: 4096) # Buffer size is at least 4;
+ # may be equal to, greater than, or less than 4096.
diff --git a/ext/digest/defs.h b/ext/digest/defs.h
index 77a134f364..9b11f4eca9 100644
--- a/ext/digest/defs.h
+++ b/ext/digest/defs.h
@@ -16,4 +16,26 @@
# define __END_DECLS
#endif
+#define RB_DIGEST_DIAGNOSTIC(compiler, op, flag) _Pragma(STRINGIZE(compiler diagnostic op flag))
+#ifdef RBIMPL_WARNING_IGNORED
+# define RB_DIGEST_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag)
+# define RB_DIGEST_WARNING_PUSH() RBIMPL_WARNING_PUSH()
+# define RB_DIGEST_WARNING_POP() RBIMPL_WARNING_POP()
+#elif defined(__clang__)
+# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(clang, ignored, #flag)
+# define RB_DIGEST_WARNING_PUSH() _Pragma("clang diagnostic push")
+# define RB_DIGEST_WARNING_POP() _Pragma("clang diagnostic pop")
+#else /* __GNUC__ */
+# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(GCC, ignored, #flag)
+# define RB_DIGEST_WARNING_PUSH() _Pragma("GCC diagnostic push")
+# define RB_DIGEST_WARNING_POP() _Pragma("GCC diagnostic pop")
+#endif
+#ifdef RBIMPL_HAS_WARNING
+# define RB_DIGEST_HAS_WARNING(_) RBIMPL_HAS_WARNING(_)
+#elif defined(__has_warning)
+# define RB_DIGEST_HAS_WARNING(_) __has_warning(_)
+#else
+# define RB_DIGEST_HAS_WARNING(_) 0
+#endif
+
#endif /* DEFS_H */
diff --git a/ext/digest/digest_conf.rb b/ext/digest/digest_conf.rb
index 36a7d75289..099d20fcbe 100644
--- a/ext/digest/digest_conf.rb
+++ b/ext/digest/digest_conf.rb
@@ -2,14 +2,16 @@
def digest_conf(name)
unless with_config("bundled-#{name}")
- cc = with_config("common-digest")
- if cc != false or /\b#{name}\b/ =~ cc
- if File.exist?("#$srcdir/#{name}cc.h") and
- have_header("CommonCrypto/CommonDigest.h")
- $defs << "-D#{name.upcase}_USE_COMMONDIGEST"
- $headers << "#{name}cc.h"
- return :commondigest
- end
+ case cc = with_config("common-digest", true)
+ when true, false
+ else
+ cc = cc.split(/[\s,]++/).any? {|pat| File.fnmatch?(pat, name)}
+ end
+ if cc and File.exist?("#$srcdir/#{name}cc.h") and
+ have_header("CommonCrypto/CommonDigest.h")
+ $defs << "-D#{name.upcase}_USE_COMMONDIGEST"
+ $headers << "#{name}cc.h"
+ return :commondigest
end
end
$objs << "#{name}.#{$OBJEXT}"
diff --git a/ext/digest/md5/md5cc.h b/ext/digest/md5/md5cc.h
index 657f573f85..a002c17604 100644
--- a/ext/digest/md5/md5cc.h
+++ b/ext/digest/md5/md5cc.h
@@ -2,14 +2,6 @@
#include <CommonCrypto/CommonDigest.h>
#ifdef __GNUC__
-# define RB_DIGEST_DIAGNOSTIC(compiler, op, flag) _Pragma(STRINGIZE(compiler diagnostic op flag))
-# ifdef RBIMPL_WARNING_IGNORED
-# define RB_DIGEST_WARNING_IGNORED(flag) RBIMPL_WARNING_IGNORED(flag)
-# elif defined(__clang__)
-# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(clang, ignored, #flag)
-# else /* __GNUC__ */
-# define RB_DIGEST_WARNING_IGNORED(flag) RB_DIGEST_DIAGNOSTIC(GCC, ignored, #flag)
-# endif
RB_DIGEST_WARNING_IGNORED(-Wdeprecated-declarations)
/* Suppress deprecation warnings of MD5 from Xcode 11.1 */
/* Although we know MD5 is deprecated too, provide just for backward
diff --git a/ext/digest/md5/md5init.c b/ext/digest/md5/md5init.c
index b81fd94864..c919060587 100644
--- a/ext/digest/md5/md5init.c
+++ b/ext/digest/md5/md5init.c
@@ -3,6 +3,7 @@
#include <ruby/ruby.h>
#include "../digest.h"
+#include "../defs.h"
#if defined(MD5_USE_COMMONDIGEST)
#include "md5cc.h"
#else
diff --git a/ext/digest/sha1/sha1.c b/ext/digest/sha1/sha1.c
index 5311227549..244fed7a3e 100644
--- a/ext/digest/sha1/sha1.c
+++ b/ext/digest/sha1/sha1.c
@@ -232,8 +232,14 @@ void SHA1_Update(SHA1_CTX *context, const uint8_t *data, size_t len)
if ((j + len) > 63) {
(void)memcpy(&context->buffer[j], data, (i = 64-j));
SHA1_Transform(context->state, context->buffer);
- for ( ; i + 63 < len; i += 64)
+ for ( ; i + 63 < len; i += 64) {
+ RB_DIGEST_WARNING_PUSH();
+#if defined(__GNUC__) && !defined(__clang__)
+ RB_DIGEST_WARNING_IGNORED(-Wstringop-overread);
+#endif
SHA1_Transform(context->state, &data[i]);
+ RB_DIGEST_WARNING_POP();
+ }
j = 0;
} else {
i = 0;
diff --git a/ext/json/generator/extconf.rb b/ext/json/generator/extconf.rb
index e44890e2ed..60372ee558 100644
--- a/ext/json/generator/extconf.rb
+++ b/ext/json/generator/extconf.rb
@@ -18,7 +18,7 @@ else
return 0;
}
SRC
- $defs.push("-DENABLE_SIMD")
+ $defs.push("-DJSON_ENABLE_SIMD")
end
end
@@ -29,7 +29,7 @@ else
return 0;
}
SRC
- $defs.push("-DENABLE_SIMD")
+ $defs.push("-DJSON_ENABLE_SIMD")
end
have_header('cpuid.h')
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c
index 536c2aa1b7..06ab8010d9 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -112,7 +112,7 @@ typedef struct _search_state {
const char *cursor;
FBuffer *buffer;
-#ifdef ENABLE_SIMD
+#ifdef HAVE_SIMD
const char *chunk_base;
const char *chunk_end;
bool has_matches;
@@ -124,7 +124,7 @@ typedef struct _search_state {
#else
#error "Unknown SIMD Implementation."
#endif /* HAVE_SIMD_NEON */
-#endif /* ENABLE_SIMD */
+#endif /* HAVE_SIMD */
} search_state;
#if (defined(__GNUC__ ) || defined(__clang__))
@@ -189,15 +189,11 @@ static inline FORCE_INLINE void escape_UTF8_char_basic(search_state *search)
case '\r': fbuffer_append(search->buffer, "\\r", 2); break;
case '\t': fbuffer_append(search->buffer, "\\t", 2); break;
default: {
- if (ch < ' ') {
- const char *hexdig = "0123456789abcdef";
- char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
- scratch[4] = hexdig[(ch >> 4) & 0xf];
- scratch[5] = hexdig[ch & 0xf];
- fbuffer_append(search->buffer, scratch, 6);
- } else {
- fbuffer_append_char(search->buffer, ch);
- }
+ const char *hexdig = "0123456789abcdef";
+ char scratch[6] = { '\\', 'u', '0', '0', 0, 0 };
+ scratch[4] = hexdig[(ch >> 4) & 0xf];
+ scratch[5] = hexdig[ch & 0xf];
+ fbuffer_append(search->buffer, scratch, 6);
break;
}
}
@@ -265,7 +261,7 @@ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
search->cursor = (search->ptr += ch_len);
}
-#ifdef ENABLE_SIMD
+#ifdef HAVE_SIMD
static inline FORCE_INLINE char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
{
@@ -537,7 +533,7 @@ static inline TARGET_SSE2 FORCE_INLINE unsigned char search_escape_basic_sse2(se
#endif /* HAVE_SIMD_SSE2 */
-#endif /* ENABLE_SIMD */
+#endif /* HAVE_SIMD */
static const unsigned char script_safe_escape_table[256] = {
// ASCII Control Characters
@@ -1302,11 +1298,11 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat
search.cursor = search.ptr;
search.end = search.ptr + len;
-#ifdef ENABLE_SIMD
+#ifdef HAVE_SIMD
search.matches_mask = 0;
search.has_matches = false;
search.chunk_base = NULL;
-#endif /* ENABLE_SIMD */
+#endif /* HAVE_SIMD */
switch(rb_enc_str_coderange(obj)) {
case ENC_CODERANGE_7BIT:
@@ -2174,7 +2170,7 @@ void Init_generator(void)
switch(find_simd_implementation()) {
-#ifdef ENABLE_SIMD
+#ifdef HAVE_SIMD
#ifdef HAVE_SIMD_NEON
case SIMD_NEON:
search_escape_basic_impl = search_escape_basic_neon;
@@ -2185,7 +2181,7 @@ void Init_generator(void)
search_escape_basic_impl = search_escape_basic_sse2;
break;
#endif /* HAVE_SIMD_SSE2 */
-#endif /* ENABLE_SIMD */
+#endif /* HAVE_SIMD */
default:
search_escape_basic_impl = search_escape_basic;
break;
diff --git a/ext/json/generator/simd.h b/ext/json/generator/simd.h
index 2fbc93169d..b12890cb09 100644
--- a/ext/json/generator/simd.h
+++ b/ext/json/generator/simd.h
@@ -4,7 +4,7 @@ typedef enum {
SIMD_SSE2
} SIMD_Implementation;
-#ifdef ENABLE_SIMD
+#ifdef JSON_ENABLE_SIMD
#ifdef __clang__
#if __has_builtin(__builtin_ctzll)
@@ -56,6 +56,7 @@ static SIMD_Implementation find_simd_implementation(void) {
return SIMD_NEON;
}
+#define HAVE_SIMD 1
#define HAVE_SIMD_NEON 1
uint8x16x4_t load_uint8x16_4(const unsigned char *table) {
@@ -74,6 +75,7 @@ uint8x16x4_t load_uint8x16_4(const unsigned char *table) {
#ifdef HAVE_X86INTRIN_H
#include <x86intrin.h>
+#define HAVE_SIMD 1
#define HAVE_SIMD_SSE2 1
#ifdef HAVE_CPUID_H
@@ -101,7 +103,7 @@ static SIMD_Implementation find_simd_implementation(void) {
#endif /* HAVE_X86INTRIN_H */
#endif /* X86_64 Support */
-#endif /* ENABLE_SIMD */
+#endif /* JSON_ENABLE_SIMD */
#ifndef FIND_SIMD_IMPLEMENTATION_DEFINED
static SIMD_Implementation find_simd_implementation(void) {
diff --git a/ext/psych/lib/psych/class_loader.rb b/ext/psych/lib/psych/class_loader.rb
index 50efc35ee2..c8f509720a 100644
--- a/ext/psych/lib/psych/class_loader.rb
+++ b/ext/psych/lib/psych/class_loader.rb
@@ -6,6 +6,7 @@ module Psych
class ClassLoader # :nodoc:
BIG_DECIMAL = 'BigDecimal'
COMPLEX = 'Complex'
+ DATA = 'Data' unless RUBY_VERSION < "3.2"
DATE = 'Date'
DATE_TIME = 'DateTime'
EXCEPTION = 'Exception'
diff --git a/ext/psych/lib/psych/versions.rb b/ext/psych/lib/psych/versions.rb
index d91563c861..0adcdae5f4 100644
--- a/ext/psych/lib/psych/versions.rb
+++ b/ext/psych/lib/psych/versions.rb
@@ -2,7 +2,7 @@
module Psych
# The version of Psych you are using
- VERSION = '5.2.3'
+ VERSION = '5.2.4'
if RUBY_ENGINE == 'jruby'
DEFAULT_SNAKEYAML_VERSION = '2.9'.freeze
diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb
index f0b4a94e45..580a74e9fb 100644
--- a/ext/psych/lib/psych/visitors/to_ruby.rb
+++ b/ext/psych/lib/psych/visitors/to_ruby.rb
@@ -96,11 +96,11 @@ module Psych
Float(@ss.tokenize(o.value))
when "!ruby/regexp"
klass = class_loader.regexp
- o.value =~ /^\/(.*)\/([mixn]*)$/m
- source = $1
+ matches = /^\/(?<string>.*)\/(?<options>[mixn]*)$/m.match(o.value)
+ source = matches[:string].gsub('\/', '/')
options = 0
lang = nil
- $2&.each_char do |option|
+ matches[:options].each_char do |option|
case option
when 'x' then options |= Regexp::EXTENDED
when 'i' then options |= Regexp::IGNORECASE
@@ -197,6 +197,32 @@ module Psych
s
end
+ when /^!ruby\/data(-with-ivars)?(?::(.*))?$/
+ data = register(o, resolve_class($2).allocate) if $2
+ members = {}
+
+ if $1 # data-with-ivars
+ ivars = {}
+ o.children.each_slice(2) do |type, vars|
+ case accept(type)
+ when 'members'
+ revive_data_members(members, vars)
+ data ||= allocate_anon_data(o, members)
+ when 'ivars'
+ revive_hash(ivars, vars)
+ end
+ end
+ ivars.each do |ivar, v|
+ data.instance_variable_set ivar, v
+ end
+ else
+ revive_data_members(members, o)
+ end
+ data ||= allocate_anon_data(o, members)
+ init_struct(data, **members)
+ data.freeze
+ data
+
when /^!ruby\/object:?(.*)?$/
name = $1 || 'Object'
@@ -340,6 +366,20 @@ module Psych
list
end
+ def allocate_anon_data node, members
+ klass = class_loader.data.define(*members.keys)
+ register(node, klass.allocate)
+ end
+
+ def revive_data_members hash, o
+ o.children.each_slice(2) do |k,v|
+ name = accept(k)
+ value = accept(v)
+ hash[class_loader.symbolize(name)] = value
+ end
+ hash
+ end
+
def revive_hash hash, o, tagged= false
o.children.each_slice(2) { |k,v|
key = accept(k)
diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb
index a9476df96e..d7958a8431 100644
--- a/ext/psych/lib/psych/visitors/yaml_tree.rb
+++ b/ext/psych/lib/psych/visitors/yaml_tree.rb
@@ -73,7 +73,7 @@ module Psych
method = respond_to?(method) ? method : h[klass.superclass]
- raise(TypeError, "Can't dump #{target.class}") unless method
+ raise(TypeError, "can't dump #{klass.name}") unless method
h[klass] = method
end.compare_by_identity
@@ -162,6 +162,44 @@ module Psych
alias :visit_Delegator :visit_Object
+ def visit_Data o
+ ivars = o.instance_variables
+ if ivars.empty?
+ tag = ['!ruby/data', o.class.name].compact.join(':')
+ register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK)
+ o.members.each do |member|
+ @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
+ accept o.send member
+ end
+ @emitter.end_mapping
+
+ else
+ tag = ['!ruby/data-with-ivars', o.class.name].compact.join(':')
+ node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK)
+ register(o, node)
+
+ # Dump the members
+ accept 'members'
+ @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
+ o.members.each do |member|
+ @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY
+ accept o.send member
+ end
+ @emitter.end_mapping
+
+ # Dump the ivars
+ accept 'ivars'
+ @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK
+ ivars.each do |ivar|
+ accept ivar.to_s
+ accept o.instance_variable_get ivar
+ end
+ @emitter.end_mapping
+
+ @emitter.end_mapping
+ end
+ end
+
def visit_Struct o
tag = ['!ruby/struct', o.class.name].compact.join(':')
diff --git a/ext/psych/psych_to_ruby.c b/ext/psych/psych_to_ruby.c
index ffe0c69c7f..d473a5f840 100644
--- a/ext/psych/psych_to_ruby.c
+++ b/ext/psych/psych_to_ruby.c
@@ -24,6 +24,15 @@ static VALUE path2class(VALUE self, VALUE path)
return rb_path_to_class(path);
}
+static VALUE init_struct(VALUE self, VALUE data, VALUE attrs)
+{
+ VALUE args = rb_ary_new2(1);
+ rb_ary_push(args, attrs);
+ rb_struct_initialize(data, args);
+
+ return data;
+}
+
void Init_psych_to_ruby(void)
{
VALUE psych = rb_define_module("Psych");
@@ -33,6 +42,7 @@ void Init_psych_to_ruby(void)
VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject);
cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor);
+ rb_define_private_method(cPsychVisitorsToRuby, "init_struct", init_struct, 2);
rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2);
rb_define_private_method(class_loader, "path2class", path2class, 1);
}
diff --git a/ext/strscan/strscan.c b/ext/strscan/strscan.c
index 5a6446adb3..e094e2f55a 100644
--- a/ext/strscan/strscan.c
+++ b/ext/strscan/strscan.c
@@ -22,7 +22,7 @@ extern size_t onig_region_memsize(const struct re_registers *regs);
#include <stdbool.h>
-#define STRSCAN_VERSION "3.1.4.dev"
+#define STRSCAN_VERSION "3.1.5.dev"
/* =======================================================================
Data Type Definitions
@@ -2211,7 +2211,10 @@ named_captures_iter(const OnigUChar *name,
VALUE value = RUBY_Qnil;
int i;
for (i = 0; i < back_num; i++) {
- value = strscan_aref(data->self, INT2NUM(back_refs[i]));
+ VALUE v = strscan_aref(data->self, INT2NUM(back_refs[i]));
+ if (!RB_NIL_P(v)) {
+ value = v;
+ }
}
rb_hash_aset(data->captures, key, value);
return 0;
diff --git a/gc.c b/gc.c
index 6e4c7ff74b..3f5bc5cea5 100644
--- a/gc.c
+++ b/gc.c
@@ -1216,14 +1216,14 @@ rb_data_free(void *objspace, VALUE obj)
void
rb_gc_obj_free_vm_weak_references(VALUE obj)
{
- if (FL_TEST(obj, FL_EXIVAR)) {
+ if (FL_TEST_RAW(obj, FL_EXIVAR)) {
rb_free_generic_ivar((VALUE)obj);
FL_UNSET(obj, FL_EXIVAR);
}
switch (BUILTIN_TYPE(obj)) {
case T_STRING:
- if (FL_TEST(obj, RSTRING_FSTR)) {
+ if (FL_TEST_RAW(obj, RSTRING_FSTR)) {
rb_gc_free_fstring(obj);
}
break;
@@ -1458,7 +1458,7 @@ rb_gc_obj_free(void *objspace, VALUE obj)
BUILTIN_TYPE(obj), (void*)obj, RBASIC(obj)->flags);
}
- if (FL_TEST(obj, FL_FINALIZE)) {
+ if (FL_TEST_RAW(obj, FL_FINALIZE)) {
rb_gc_impl_make_zombie(objspace, obj, 0, 0);
return FALSE;
}
@@ -2665,7 +2665,7 @@ rb_gc_mark_roots(void *objspace, const char **categoryp)
void
rb_gc_mark_children(void *objspace, VALUE obj)
{
- if (FL_TEST(obj, FL_EXIVAR)) {
+ if (FL_TEST_RAW(obj, FL_EXIVAR)) {
rb_mark_generic_ivar(obj);
}
@@ -2700,7 +2700,7 @@ rb_gc_mark_children(void *objspace, VALUE obj)
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
- if (FL_TEST(obj, FL_SINGLETON)) {
+ if (FL_TEST_RAW(obj, FL_SINGLETON)) {
gc_mark_internal(RCLASS_ATTACHED_OBJECT(obj));
}
// Continue to the shared T_CLASS/T_MODULE
@@ -3635,7 +3635,7 @@ rb_gc_update_object_references(void *objspace, VALUE obj)
{
switch (BUILTIN_TYPE(obj)) {
case T_CLASS:
- if (FL_TEST(obj, FL_SINGLETON)) {
+ if (FL_TEST_RAW(obj, FL_SINGLETON)) {
UPDATE_IF_MOVED(objspace, RCLASS_ATTACHED_OBJECT(obj));
}
// Continue to the shared T_CLASS/T_MODULE
diff --git a/jit.c b/jit.c
new file mode 100644
index 0000000000..d2147a9d7f
--- /dev/null
+++ b/jit.c
@@ -0,0 +1,423 @@
+// Glue code shared between YJIT and ZJIT for use from Rust.
+// For FFI safety and bindgen compatibility reasons, certain types of C
+// functions require wrapping before they can be called from Rust. Those show
+// up here.
+//
+// Code specific to YJIT and ZJIT should go to yjit.c and zjit.c respectively.
+
+#include "internal.h"
+#include "vm_core.h"
+#include "vm_callinfo.h"
+#include "builtin.h"
+#include "insns.inc"
+#include "insns_info.inc"
+#include "iseq.h"
+#include "internal/gc.h"
+
+unsigned int
+rb_iseq_encoded_size(const rb_iseq_t *iseq)
+{
+ return iseq->body->iseq_size;
+}
+
+// Get the PC for a given index in an iseq
+VALUE *
+rb_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx)
+{
+ RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
+ RUBY_ASSERT_ALWAYS(insn_idx < iseq->body->iseq_size);
+ VALUE *encoded = iseq->body->iseq_encoded;
+ VALUE *pc = &encoded[insn_idx];
+ return pc;
+}
+
+// Get the opcode given a program counter. Can return trace opcode variants.
+int
+rb_iseq_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
+{
+ // YJIT should only use iseqs after AST to bytecode compilation
+ RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED));
+
+ const VALUE at_pc = *pc;
+ return rb_vm_insn_addr2opcode((const void *)at_pc);
+}
+
+unsigned long
+rb_RSTRING_LEN(VALUE str)
+{
+ return RSTRING_LEN(str);
+}
+
+char *
+rb_RSTRING_PTR(VALUE str)
+{
+ return RSTRING_PTR(str);
+}
+
+const char *
+rb_insn_name(VALUE insn)
+{
+ return insn_name(insn);
+}
+
+unsigned int
+rb_vm_ci_argc(const struct rb_callinfo *ci)
+{
+ return vm_ci_argc(ci);
+}
+
+ID
+rb_vm_ci_mid(const struct rb_callinfo *ci)
+{
+ return vm_ci_mid(ci);
+}
+
+unsigned int
+rb_vm_ci_flag(const struct rb_callinfo *ci)
+{
+ return vm_ci_flag(ci);
+}
+
+const struct rb_callinfo_kwarg *
+rb_vm_ci_kwarg(const struct rb_callinfo *ci)
+{
+ return vm_ci_kwarg(ci);
+}
+
+int
+rb_get_cikw_keyword_len(const struct rb_callinfo_kwarg *cikw)
+{
+ return cikw->keyword_len;
+}
+
+VALUE
+rb_get_cikw_keywords_idx(const struct rb_callinfo_kwarg *cikw, int idx)
+{
+ return cikw->keywords[idx];
+}
+
+rb_method_visibility_t
+rb_METHOD_ENTRY_VISI(const rb_callable_method_entry_t *me)
+{
+ return METHOD_ENTRY_VISI(me);
+}
+
+rb_method_type_t
+rb_get_cme_def_type(const rb_callable_method_entry_t *cme)
+{
+ if (UNDEFINED_METHOD_ENTRY_P(cme)) {
+ return VM_METHOD_TYPE_UNDEF;
+ }
+ else {
+ return cme->def->type;
+ }
+}
+
+ID
+rb_get_cme_def_body_attr_id(const rb_callable_method_entry_t *cme)
+{
+ return cme->def->body.attr.id;
+}
+
+enum method_optimized_type
+rb_get_cme_def_body_optimized_type(const rb_callable_method_entry_t *cme)
+{
+ return cme->def->body.optimized.type;
+}
+
+unsigned int
+rb_get_cme_def_body_optimized_index(const rb_callable_method_entry_t *cme)
+{
+ return cme->def->body.optimized.index;
+}
+
+rb_method_cfunc_t *
+rb_get_cme_def_body_cfunc(const rb_callable_method_entry_t *cme)
+{
+ return UNALIGNED_MEMBER_PTR(cme->def, body.cfunc);
+}
+
+uintptr_t
+rb_get_def_method_serial(const rb_method_definition_t *def)
+{
+ return def->method_serial;
+}
+
+ID
+rb_get_def_original_id(const rb_method_definition_t *def)
+{
+ return def->original_id;
+}
+
+int
+rb_get_mct_argc(const rb_method_cfunc_t *mct)
+{
+ return mct->argc;
+}
+
+void *
+rb_get_mct_func(const rb_method_cfunc_t *mct)
+{
+ return (void*)(uintptr_t)mct->func; // this field is defined as type VALUE (*func)(ANYARGS)
+}
+
+const rb_iseq_t *
+rb_get_def_iseq_ptr(rb_method_definition_t *def)
+{
+ return def_iseq_ptr(def);
+}
+
+const rb_iseq_t *
+rb_get_iseq_body_local_iseq(const rb_iseq_t *iseq)
+{
+ return iseq->body->local_iseq;
+}
+
+unsigned int
+rb_get_iseq_body_local_table_size(const rb_iseq_t *iseq)
+{
+ return iseq->body->local_table_size;
+}
+
+VALUE *
+rb_get_iseq_body_iseq_encoded(const rb_iseq_t *iseq)
+{
+ return iseq->body->iseq_encoded;
+}
+
+unsigned
+rb_get_iseq_body_stack_max(const rb_iseq_t *iseq)
+{
+ return iseq->body->stack_max;
+}
+
+enum rb_iseq_type
+rb_get_iseq_body_type(const rb_iseq_t *iseq)
+{
+ return iseq->body->type;
+}
+
+bool
+rb_get_iseq_flags_has_lead(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_lead;
+}
+
+bool
+rb_get_iseq_flags_has_opt(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_opt;
+}
+
+bool
+rb_get_iseq_flags_has_kw(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_kw;
+}
+
+bool
+rb_get_iseq_flags_has_post(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_post;
+}
+
+bool
+rb_get_iseq_flags_has_kwrest(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_kwrest;
+}
+
+bool
+rb_get_iseq_flags_anon_kwrest(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.anon_kwrest;
+}
+
+bool
+rb_get_iseq_flags_has_rest(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_rest;
+}
+
+bool
+rb_get_iseq_flags_ruby2_keywords(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.ruby2_keywords;
+}
+
+bool
+rb_get_iseq_flags_has_block(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.has_block;
+}
+
+bool
+rb_get_iseq_flags_ambiguous_param0(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.ambiguous_param0;
+}
+
+bool
+rb_get_iseq_flags_accepts_no_kwarg(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.accepts_no_kwarg;
+}
+
+bool
+rb_get_iseq_flags_forwardable(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.flags.forwardable;
+}
+
+// This is defined only as a named struct inside rb_iseq_constant_body.
+// By giving it a separate typedef, we make it nameable by rust-bindgen.
+// Bindgen's temp/anon name isn't guaranteed stable.
+typedef struct rb_iseq_param_keyword rb_iseq_param_keyword_struct;
+
+const rb_iseq_param_keyword_struct *
+rb_get_iseq_body_param_keyword(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.keyword;
+}
+
+unsigned
+rb_get_iseq_body_param_size(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.size;
+}
+
+int
+rb_get_iseq_body_param_lead_num(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.lead_num;
+}
+
+int
+rb_get_iseq_body_param_opt_num(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.opt_num;
+}
+
+const VALUE *
+rb_get_iseq_body_param_opt_table(const rb_iseq_t *iseq)
+{
+ return iseq->body->param.opt_table;
+}
+
+struct rb_control_frame_struct *
+rb_get_ec_cfp(const rb_execution_context_t *ec)
+{
+ return ec->cfp;
+}
+
+const rb_iseq_t *
+rb_get_cfp_iseq(struct rb_control_frame_struct *cfp)
+{
+ return cfp->iseq;
+}
+
+VALUE *
+rb_get_cfp_pc(struct rb_control_frame_struct *cfp)
+{
+ return (VALUE*)cfp->pc;
+}
+
+VALUE *
+rb_get_cfp_sp(struct rb_control_frame_struct *cfp)
+{
+ return cfp->sp;
+}
+
+VALUE
+rb_get_cfp_self(struct rb_control_frame_struct *cfp)
+{
+ return cfp->self;
+}
+
+VALUE *
+rb_get_cfp_ep(struct rb_control_frame_struct *cfp)
+{
+ return (VALUE*)cfp->ep;
+}
+
+const VALUE *
+rb_get_cfp_ep_level(struct rb_control_frame_struct *cfp, uint32_t lv)
+{
+ uint32_t i;
+ const VALUE *ep = (VALUE*)cfp->ep;
+ for (i = 0; i < lv; i++) {
+ ep = VM_ENV_PREV_EP(ep);
+ }
+ return ep;
+}
+
+VALUE
+rb_yarv_class_of(VALUE obj)
+{
+ return rb_class_of(obj);
+}
+
+// The FL_TEST() macro
+VALUE
+rb_FL_TEST(VALUE obj, VALUE flags)
+{
+ return RB_FL_TEST(obj, flags);
+}
+
+// The FL_TEST_RAW() macro, normally an internal implementation detail
+VALUE
+rb_FL_TEST_RAW(VALUE obj, VALUE flags)
+{
+ return FL_TEST_RAW(obj, flags);
+}
+
+// The RB_TYPE_P macro
+bool
+rb_RB_TYPE_P(VALUE obj, enum ruby_value_type t)
+{
+ return RB_TYPE_P(obj, t);
+}
+
+long
+rb_RSTRUCT_LEN(VALUE st)
+{
+ return RSTRUCT_LEN(st);
+}
+
+const struct rb_callinfo *
+rb_get_call_data_ci(const struct rb_call_data *cd)
+{
+ return cd->ci;
+}
+
+bool
+rb_BASIC_OP_UNREDEFINED_P(enum ruby_basic_operators bop, uint32_t klass)
+{
+ return BASIC_OP_UNREDEFINED_P(bop, klass);
+}
+
+VALUE
+rb_RCLASS_ORIGIN(VALUE c)
+{
+ return RCLASS_ORIGIN(c);
+}
+
+// For debug builds
+void
+rb_assert_iseq_handle(VALUE handle)
+{
+ RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_iseq));
+}
+
+int
+rb_IMEMO_TYPE_P(VALUE imemo, enum imemo_type imemo_type)
+{
+ return IMEMO_TYPE_P(imemo, imemo_type);
+}
+
+void
+rb_assert_cme_handle(VALUE handle)
+{
+ RUBY_ASSERT_ALWAYS(!rb_objspace_garbage_object_p(handle));
+ RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_ment));
+}
diff --git a/lib/rubygems/gemcutter_utilities.rb b/lib/rubygems/gemcutter_utilities.rb
index d3176d4564..8d9a9b2d35 100644
--- a/lib/rubygems/gemcutter_utilities.rb
+++ b/lib/rubygems/gemcutter_utilities.rb
@@ -263,7 +263,10 @@ module Gem::GemcutterUtilities
port = server.addr[1].to_s
url_with_port = "#{webauthn_url}?port=#{port}"
- say "You have enabled multi-factor authentication. Please visit #{url_with_port} to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option."
+ say "You have enabled multi-factor authentication. Please visit the following URL to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin command with the `--otp [your_code]` option."
+ say ""
+ say url_with_port
+ say ""
threads = [WebauthnListener.listener_thread(host, server), WebauthnPoller.poll_thread(options, host, webauthn_url, credentials)]
otp_thread = wait_for_otp_thread(*threads)
diff --git a/string.c b/string.c
index 3b40dafb53..2d5e20984b 100644
--- a/string.c
+++ b/string.c
@@ -2347,9 +2347,14 @@ rb_str_with_debug_created_info(VALUE str, VALUE path, int line)
}
/*
+ * The documentation block below uses an include (instead of inline text)
+ * because the included text has non-ASCII characters (which are not allowed in a C file).
+ */
+
+/*
*
* call-seq:
- * String.new(string = '', **opts) -> new_string
+ * String.new(string = ''.encode(Encoding::ASCII_8BIT) , **options) -> new_string
*
* :include: doc/string/new.rdoc
*
diff --git a/symbol.c b/symbol.c
index 8ba0b818a8..12dea88158 100644
--- a/symbol.c
+++ b/symbol.c
@@ -172,7 +172,7 @@ rb_id_attrset(ID id)
/* make new symbol and ID */
if (!(str = lookup_id_str(id))) {
- RBIMPL_ATTR_NONSTRING() static const char id_types[][8] = {
+ static const char id_types[][8] = {
"local",
"instance",
"invalid",
diff --git a/template/Makefile.in b/template/Makefile.in
index 7e88f94c7a..743971abcb 100644
--- a/template/Makefile.in
+++ b/template/Makefile.in
@@ -102,6 +102,7 @@ USE_RUBYGEMS = @USE_RUBYGEMS@
USE_RUBYGEMS_ = $(USE_RUBYGEMS:yes=)
CPPFLAGS = @CPPFLAGS@ $(USE_RUBYGEMS_:no=-DDISABLE_RUBYGEMS=1)
TOP_BUILD_DIR=@abs_top_builddir@
+JIT_OBJ=@JIT_OBJ@
YJIT_SUPPORT=@YJIT_SUPPORT@
YJIT_LIBS=@YJIT_LIBS@
YJIT_OBJ=@YJIT_OBJ@
diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb
index 39fa72e7dd..326cf22e1f 100644
--- a/test/objspace/test_objspace.rb
+++ b/test/objspace/test_objspace.rb
@@ -203,8 +203,9 @@ class TestObjSpace < Test::Unit::TestCase
assert_equal(line1, ObjectSpace.allocation_sourceline(o1))
assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o1))
assert_equal(c1, ObjectSpace.allocation_generation(o1))
- assert_equal(self.class.name, ObjectSpace.allocation_class_path(o1))
- assert_equal(__method__, ObjectSpace.allocation_method_id(o1))
+ # These assertions fail under coverage measurement: https://bugs.ruby-lang.org/issues/21298
+ #assert_equal(self.class.name, ObjectSpace.allocation_class_path(o1))
+ #assert_equal(__method__, ObjectSpace.allocation_method_id(o1))
assert_equal(__FILE__, ObjectSpace.allocation_sourcefile(o2))
assert_equal(line2, ObjectSpace.allocation_sourceline(o2))
diff --git a/test/psych/test_data.rb b/test/psych/test_data.rb
new file mode 100644
index 0000000000..a67a037b9e
--- /dev/null
+++ b/test/psych/test_data.rb
@@ -0,0 +1,69 @@
+# frozen_string_literal: true
+require_relative 'helper'
+
+class PsychDataWithIvar < Data.define(:foo)
+ attr_reader :bar
+ def initialize(**)
+ @bar = 'hello'
+ super
+ end
+end unless RUBY_VERSION < "3.2"
+
+module Psych
+ class TestData < TestCase
+ class SelfReferentialData < Data.define(:foo)
+ attr_accessor :ref
+ def initialize(foo:)
+ @ref = self
+ super
+ end
+ end unless RUBY_VERSION < "3.2"
+
+ def setup
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ end
+
+ # TODO: move to another test?
+ def test_dump_data
+ assert_equal <<~eoyml, Psych.dump(PsychDataWithIvar["bar"])
+ --- !ruby/data-with-ivars:PsychDataWithIvar
+ members:
+ foo: bar
+ ivars:
+ "@bar": hello
+ eoyml
+ end
+
+ def test_self_referential_data
+ circular = SelfReferentialData.new("foo")
+
+ loaded = Psych.unsafe_load(Psych.dump(circular))
+ assert_instance_of(SelfReferentialData, loaded.ref)
+
+ assert_equal(circular, loaded)
+ assert_same(loaded, loaded.ref)
+ end
+
+ def test_roundtrip
+ thing = PsychDataWithIvar.new("bar")
+ data = Psych.unsafe_load(Psych.dump(thing))
+
+ assert_equal "hello", data.bar
+ assert_equal "bar", data.foo
+ end
+
+ def test_load
+ obj = Psych.unsafe_load(<<~eoyml)
+ --- !ruby/data-with-ivars:PsychDataWithIvar
+ members:
+ foo: bar
+ ivars:
+ "@bar": hello
+ eoyml
+
+ assert_equal "hello", obj.bar
+ assert_equal "bar", obj.foo
+ end
+ end
+end
+
diff --git a/test/psych/test_object_references.rb b/test/psych/test_object_references.rb
index 86bb9034b9..0498d54eec 100644
--- a/test/psych/test_object_references.rb
+++ b/test/psych/test_object_references.rb
@@ -31,6 +31,11 @@ module Psych
assert_reference_trip Struct.new(:foo).new(1)
end
+ def test_data_has_references
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ assert_reference_trip Data.define(:foo).new(1)
+ end
+
def assert_reference_trip obj
yml = Psych.dump([obj, obj])
assert_match(/\*-?\d+/, yml)
diff --git a/test/psych/test_safe_load.rb b/test/psych/test_safe_load.rb
index a9ed737528..e6ca1e142b 100644
--- a/test/psych/test_safe_load.rb
+++ b/test/psych/test_safe_load.rb
@@ -114,6 +114,38 @@ module Psych
end
end
+ D = Data.define(:d) unless RUBY_VERSION < "3.2"
+
+ def test_data_depends_on_sym
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ assert_safe_cycle(D.new(nil), permitted_classes: [D, Symbol])
+ assert_raise(Psych::DisallowedClass) do
+ cycle D.new(nil), permitted_classes: [D]
+ end
+ end
+
+ def test_anon_data
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ assert Psych.safe_load(<<-eoyml, permitted_classes: [Data, Symbol])
+--- !ruby/data
+ foo: bar
+ eoyml
+
+ assert_raise(Psych::DisallowedClass) do
+ Psych.safe_load(<<-eoyml, permitted_classes: [Data])
+--- !ruby/data
+ foo: bar
+ eoyml
+ end
+
+ assert_raise(Psych::DisallowedClass) do
+ Psych.safe_load(<<-eoyml, permitted_classes: [Symbol])
+--- !ruby/data
+ foo: bar
+ eoyml
+ end
+ end
+
def test_safe_load_default_fallback
assert_nil Psych.safe_load("")
end
diff --git a/test/psych/test_serialize_subclasses.rb b/test/psych/test_serialize_subclasses.rb
index 344c79b3ef..640c331337 100644
--- a/test/psych/test_serialize_subclasses.rb
+++ b/test/psych/test_serialize_subclasses.rb
@@ -35,5 +35,23 @@ module Psych
so = StructSubclass.new('foo', [1,2,3])
assert_equal so, Psych.unsafe_load(Psych.dump(so))
end
+
+ class DataSubclass < Data.define(:foo)
+ def initialize(foo:)
+ @bar = "hello #{foo}"
+ super(foo: foo)
+ end
+
+ def == other
+ super(other) && @bar == other.instance_eval{ @bar }
+ end
+ end unless RUBY_VERSION < "3.2"
+
+ def test_data_subclass
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ so = DataSubclass.new('foo')
+ assert_equal so, Psych.unsafe_load(Psych.dump(so))
+ end
+
end
end
diff --git a/test/psych/test_yaml.rb b/test/psych/test_yaml.rb
index 897a7c8935..134c346c90 100644
--- a/test/psych/test_yaml.rb
+++ b/test/psych/test_yaml.rb
@@ -6,6 +6,7 @@ require_relative 'helper'
# [ruby-core:01946]
module Psych_Tests
StructTest = Struct::new( :c )
+ DataTest = Data.define( :c ) unless RUBY_VERSION < "3.2"
end
class Psych_Unit_Tests < Psych::TestCase
@@ -35,6 +36,10 @@ class Psych_Unit_Tests < Psych::TestCase
assert_cycle(Regexp.new("foo\nbar"))
end
+ def test_regexp_with_slash
+ assert_cycle(Regexp.new('/'))
+ end
+
# [ruby-core:34969]
def test_regexp_with_n
assert_cycle(Regexp.new('',Regexp::NOENCODING))
@@ -1037,7 +1042,6 @@ EOY
end
def test_ruby_struct
- Struct.send(:remove_const, :MyBookStruct) if Struct.const_defined?(:MyBookStruct)
# Ruby structures
book_struct = Struct::new( "MyBookStruct", :author, :title, :year, :isbn )
assert_to_yaml(
@@ -1069,6 +1073,47 @@ EOY
c: 123
EOY
+ ensure
+ Struct.__send__(:remove_const, :MyBookStruct) if book_struct
+ end
+
+ def test_ruby_data
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ # Ruby Data value objects
+ book_class = Data.define(:author, :title, :year, :isbn)
+ Object.const_set(:MyBookData, book_class)
+ assert_to_yaml(
+ [ book_class.new( "Yukihiro Matsumoto", "Ruby in a Nutshell", 2002, "0-596-00214-9" ),
+ book_class.new( [ 'Dave Thomas', 'Andy Hunt' ], "The Pickaxe", 2002,
+ book_class.new( "This should be the ISBN", "but I have more data here", 2002, "None" )
+ )
+ ], <<EOY
+- !ruby/data:MyBookData
+ author: Yukihiro Matsumoto
+ title: Ruby in a Nutshell
+ year: 2002
+ isbn: 0-596-00214-9
+- !ruby/data:MyBookData
+ author:
+ - Dave Thomas
+ - Andy Hunt
+ title: The Pickaxe
+ year: 2002
+ isbn: !ruby/data:MyBookData
+ author: This should be the ISBN
+ title: but I have more data here
+ year: 2002
+ isbn: None
+EOY
+ )
+
+ assert_to_yaml( Psych_Tests::DataTest.new( 123 ), <<EOY )
+--- !ruby/data:Psych_Tests::DataTest
+c: 123
+EOY
+
+ ensure
+ Object.__send__(:remove_const, :MyBookData) if book_class
end
def test_ruby_rational
diff --git a/test/psych/visitors/test_yaml_tree.rb b/test/psych/visitors/test_yaml_tree.rb
index 01e685134a..bd3919f83d 100644
--- a/test/psych/visitors/test_yaml_tree.rb
+++ b/test/psych/visitors/test_yaml_tree.rb
@@ -73,6 +73,27 @@ module Psych
assert_equal s.method, obj.method
end
+ D = Data.define(:foo) unless RUBY_VERSION < "3.2"
+
+ def test_data
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ assert_cycle D.new('bar')
+ end
+
+ def test_data_anon
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ d = Data.define(:foo).new('bar')
+ obj = Psych.unsafe_load(Psych.dump(d))
+ assert_equal d.foo, obj.foo
+ end
+
+ def test_data_override_method
+ omit "Data requires ruby >= 3.2" if RUBY_VERSION < "3.2"
+ d = Data.define(:method).new('override')
+ obj = Psych.unsafe_load(Psych.dump(d))
+ assert_equal d.method, obj.method
+ end
+
def test_exception
ex = Exception.new 'foo'
loaded = Psych.unsafe_load(Psych.dump(ex))
diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb
index 032f78f6a8..86c1f51dde 100644
--- a/test/ruby/test_iseq.rb
+++ b/test/ruby/test_iseq.rb
@@ -92,7 +92,7 @@ class TestISeq < Test::Unit::TestCase
42
end
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_forwardable
@@ -102,7 +102,7 @@ class TestISeq < Test::Unit::TestCase
def foo(...); bar(...); end
}
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval.new.foo(40, 2))
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval.new.foo(40, 2))
end
def test_super_with_block
@@ -112,7 +112,7 @@ class TestISeq < Test::Unit::TestCase
end
42
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_super_with_block_hash_0
@@ -123,7 +123,7 @@ class TestISeq < Test::Unit::TestCase
end
42
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_super_with_block_and_kwrest
@@ -133,7 +133,7 @@ class TestISeq < Test::Unit::TestCase
end
42
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_lambda_with_ractor_roundtrip
@@ -143,7 +143,7 @@ class TestISeq < Test::Unit::TestCase
Ractor.make_shareable(y)
y.call
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_super_with_anonymous_block
@@ -153,7 +153,7 @@ class TestISeq < Test::Unit::TestCase
end
42
EOF
- assert_equal(42, ISeq.load_from_binary(iseq.to_binary).eval)
+ assert_equal(42, ISeq.load_from_binary(iseq_to_binary(iseq)).eval)
end
def test_ractor_unshareable_outer_variable
@@ -182,7 +182,7 @@ class TestISeq < Test::Unit::TestCase
# shareable_constant_value: literal
REGEX = /#{}/ # [Bug #20569]
RUBY
- assert_includes iseq.to_binary, "REGEX".b
+ assert_includes iseq_to_binary(iseq), "REGEX".b
end
def test_disasm_encoding
@@ -566,16 +566,20 @@ class TestISeq < Test::Unit::TestCase
}
end
+ def iseq_to_binary(iseq)
+ iseq.to_binary
+ rescue RuntimeError => e
+ omit e.message if /compile with coverage/ =~ e.message
+ raise
+ end
+
def assert_iseq_to_binary(code, mesg = nil)
iseq = RubyVM::InstructionSequence.compile(code)
bin = assert_nothing_raised(mesg) do
- iseq.to_binary
- rescue RuntimeError => e
- omit e.message if /compile with coverage/ =~ e.message
- raise
+ iseq_to_binary(iseq)
end
10.times do
- bin2 = iseq.to_binary
+ bin2 = iseq_to_binary(iseq)
assert_equal(bin, bin2, message(mesg) {diff hexdump(bin), hexdump(bin2)})
end
iseq2 = RubyVM::InstructionSequence.load_from_binary(bin)
@@ -593,7 +597,7 @@ class TestISeq < Test::Unit::TestCase
def test_to_binary_with_hidden_local_variables
assert_iseq_to_binary("for _foo in bar; end")
- bin = RubyVM::InstructionSequence.compile(<<-RUBY).to_binary
+ bin = iseq_to_binary(RubyVM::InstructionSequence.compile(<<-RUBY))
Object.new.instance_eval do
a = []
def self.bar; [1] end
@@ -668,7 +672,7 @@ class TestISeq < Test::Unit::TestCase
end
RUBY
- iseq_bin = iseq.to_binary
+ iseq_bin = iseq_to_binary(iseq)
iseq = ISeq.load_from_binary(iseq_bin)
lines = []
TracePoint.new(tracepoint_type){|tp|
@@ -764,7 +768,7 @@ class TestISeq < Test::Unit::TestCase
def test_iseq_builtin_load
Tempfile.create(["builtin", ".iseq"]) do |f|
f.binmode
- f.write(RubyVM::InstructionSequence.of(1.method(:abs)).to_binary)
+ f.write(iseq_to_binary(RubyVM::InstructionSequence.of(1.method(:abs))))
f.close
assert_separately(["-", f.path], "#{<<~"begin;"}\n#{<<~'end;'}")
begin;
@@ -857,7 +861,7 @@ class TestISeq < Test::Unit::TestCase
def test_loading_kwargs_memory_leak
assert_no_memory_leak([], "#{<<~"begin;"}", "#{<<~'end;'}", rss: true)
- a = RubyVM::InstructionSequence.compile("foo(bar: :baz)").to_binary
+ a = iseq_to_binary(RubyVM::InstructionSequence.compile("foo(bar: :baz)"))
begin;
1_000_000.times do
RubyVM::InstructionSequence.load_from_binary(a)
@@ -868,7 +872,7 @@ class TestISeq < Test::Unit::TestCase
def test_ibf_bignum
iseq = RubyVM::InstructionSequence.compile("0x0"+"_0123_4567_89ab_cdef"*5)
expected = iseq.eval
- result = RubyVM::InstructionSequence.load_from_binary(iseq.to_binary).eval
+ result = RubyVM::InstructionSequence.load_from_binary(iseq_to_binary(iseq)).eval
assert_equal expected, result, proc {sprintf("expected: %x, result: %x", expected, result)}
end
diff --git a/test/rubygems/test_gem_commands_owner_command.rb b/test/rubygems/test_gem_commands_owner_command.rb
index bc4f13ff2a..ac18699736 100644
--- a/test/rubygems/test_gem_commands_owner_command.rb
+++ b/test/rubygems/test_gem_commands_owner_command.rb
@@ -386,9 +386,10 @@ EOF
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
+ assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
assert_match response_success, @stub_ui.output
@@ -413,9 +414,10 @@ EOF
end
assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @stub_ui.output
+ assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @stub_ui.error
refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
refute_match response_success, @stub_ui.output
@@ -435,9 +437,10 @@ EOF
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
"command with the `--otp [your_code]` option.", @stub_ui.output
+ assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @stub_fetcher.last_request["OTP"]
assert_match response_success, @stub_ui.output
@@ -463,9 +466,10 @@ EOF
end
assert_match @stub_fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@stub_fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
"command with the `--otp [your_code]` option.", @stub_ui.output
+ assert_match @stub_fetcher.webauthn_url_with_port(server.port), @stub_ui.output
assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
"or been used already.", @stub_ui.error
refute_match "You are verified with a security device. You may close the browser window.", @stub_ui.output
diff --git a/test/rubygems/test_gem_commands_push_command.rb b/test/rubygems/test_gem_commands_push_command.rb
index 2d0190b49f..bedc8e0d58 100644
--- a/test/rubygems/test_gem_commands_push_command.rb
+++ b/test/rubygems/test_gem_commands_push_command.rb
@@ -477,9 +477,10 @@ class TestGemCommandsPushCommand < Gem::TestCase
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
assert_match response_success, @ui.output
@@ -505,9 +506,10 @@ class TestGemCommandsPushCommand < Gem::TestCase
assert_equal 1, error.exit_code
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error
refute_match "You are verified with a security device. You may close the browser window.", @ui.output
refute_match response_success, @ui.output
@@ -527,9 +529,10 @@ class TestGemCommandsPushCommand < Gem::TestCase
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
assert_match response_success, @ui.output
@@ -553,9 +556,10 @@ class TestGemCommandsPushCommand < Gem::TestCase
assert_equal 1, error.exit_code
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
- "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, you can re-run the gem signin " \
- "command with the `--otp [your_code]` option.", @ui.output
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
+ "to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
+ "you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
"or been used already.", @ui.error
refute_match "You are verified with a security device. You may close the browser window.", @ui.output
diff --git a/test/rubygems/test_gem_commands_yank_command.rb b/test/rubygems/test_gem_commands_yank_command.rb
index eb78e3a542..213f098374 100644
--- a/test/rubygems/test_gem_commands_yank_command.rb
+++ b/test/rubygems/test_gem_commands_yank_command.rb
@@ -131,9 +131,10 @@ class TestGemCommandsYankCommand < Gem::TestCase
end
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
assert_match "Successfully yanked", @ui.output
@@ -163,9 +164,10 @@ class TestGemCommandsYankCommand < Gem::TestCase
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @ui.error
refute_match "You are verified with a security device. You may close the browser window.", @ui.output
refute_match "Successfully yanked", @ui.output
@@ -189,9 +191,10 @@ class TestGemCommandsYankCommand < Gem::TestCase
end
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "You are verified with a security device. You may close the browser window.", @ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
assert_match "Successfully yanked", @ui.output
@@ -219,9 +222,10 @@ class TestGemCommandsYankCommand < Gem::TestCase
assert_match @fetcher.last_request["Authorization"], Gem.configuration.rubygems_api_key
assert_match %r{Yanking gem from http://example}, @ui.output
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @ui.output
assert_match "ERROR: Security device verification failed: The token in the link you used has either expired " \
"or been used already.", @ui.error
refute_match "You are verified with a security device. You may close the browser window.", @ui.output
diff --git a/test/rubygems/test_gem_gemcutter_utilities.rb b/test/rubygems/test_gem_gemcutter_utilities.rb
index a3236e6276..9204dc5f20 100644
--- a/test/rubygems/test_gem_gemcutter_utilities.rb
+++ b/test/rubygems/test_gem_gemcutter_utilities.rb
@@ -233,9 +233,10 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
end
@@ -255,9 +256,10 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
assert_equal 1, error.exit_code
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output
assert_match "ERROR: Security device verification failed: Something went wrong", @sign_in_ui.error
refute_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
refute_match "Signed in with API key:", @sign_in_ui.output
@@ -273,9 +275,10 @@ class TestGemGemcutterUtilities < Gem::TestCase
util_sign_in
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output
assert_match "You are verified with a security device. You may close the browser window.", @sign_in_ui.output
assert_equal "Uvh6T57tkWuUnWYo", @fetcher.last_request["OTP"]
end
@@ -292,9 +295,10 @@ class TestGemGemcutterUtilities < Gem::TestCase
end
end
- assert_match "You have enabled multi-factor authentication. Please visit #{@fetcher.webauthn_url_with_port(server.port)} " \
+ assert_match "You have enabled multi-factor authentication. Please visit the following URL " \
"to authenticate via security device. If you can't verify using WebAuthn but have OTP enabled, " \
"you can re-run the gem signin command with the `--otp [your_code]` option.", @sign_in_ui.output
+ assert_match @fetcher.webauthn_url_with_port(server.port), @sign_in_ui.output
assert_match "ERROR: Security device verification failed: " \
"The token in the link you used has either expired or been used already.", @sign_in_ui.error
end
diff --git a/test/strscan/test_stringscanner.rb b/test/strscan/test_stringscanner.rb
index 0a28d92368..e895a8382b 100644
--- a/test/strscan/test_stringscanner.rb
+++ b/test/strscan/test_stringscanner.rb
@@ -967,6 +967,12 @@ module StringScannerTests
assert_equal({}, scan.named_captures)
end
+ def test_named_captures_same_name_union
+ scan = StringScanner.new("123")
+ assert_equal(1, scan.match?(/(?<number>0)|(?<number>1)|(?<number>2)/))
+ assert_equal({"number" => "1"}, scan.named_captures)
+ end
+
def test_scan_integer
s = create_string_scanner('abc')
assert_equal(3, s.match?(/(?<a>abc)/)) # set named_captures
diff --git a/tool/ruby_vm/views/insns_info.inc.erb b/tool/ruby_vm/views/insns_info.inc.erb
index 6ba12a856e..0a6f71fee3 100644
--- a/tool/ruby_vm/views/insns_info.inc.erb
+++ b/tool/ruby_vm/views/insns_info.inc.erb
@@ -11,6 +11,8 @@
this_file: 'contains instruction information for yarv instruction sequence.',
edit: __FILE__,
} %>
+#ifndef INSNS_INFO_INC
+#define INSNS_INFO_INC 1
<%= render 'insn_type_chars' %>
<%= render 'insn_name_info' %>
<%= render 'insn_len_info' %>
@@ -20,3 +22,4 @@
<%= render 'zjit_helpers' %>
<%= render 'attributes' %>
<%= render 'comptime_insn_stack_increase' %>
+#endif
diff --git a/tool/sync_default_gems.rb b/tool/sync_default_gems.rb
index 903baf49dd..5b0bca72b7 100755
--- a/tool/sync_default_gems.rb
+++ b/tool/sync_default_gems.rb
@@ -46,7 +46,6 @@ module SyncDefaultGems
resolv: "ruby/resolv",
rubygems: 'rubygems/rubygems',
securerandom: "ruby/securerandom",
- set: "ruby/set",
shellwords: "ruby/shellwords",
singleton: "ruby/singleton",
stringio: 'ruby/stringio',
@@ -295,9 +294,6 @@ module SyncDefaultGems
cp_r("#{upstream}/test/digest", "test")
cp_r("#{upstream}/digest.gemspec", "ext/digest")
`git checkout ext/digest/depend ext/digest/*/depend`
- when "set"
- sync_lib gem, upstream
- cp_r(Dir.glob("#{upstream}/test/*"), "test/set")
when "optparse"
sync_lib gem, upstream
rm_rf(%w[doc/optparse])
diff --git a/vm_method.c b/vm_method.c
index 22adc469f7..7288fdd2ec 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -1371,7 +1371,6 @@ prepare_callable_method_entry(VALUE defined_class, ID id, const rb_method_entry_
if (me->defined_class == 0) {
RB_DEBUG_COUNTER_INC(mc_cme_complement);
VM_ASSERT_TYPE2(defined_class, T_ICLASS, T_MODULE);
- VM_ASSERT(me->defined_class == 0, "me->defined_class: %s", rb_obj_info(me->defined_class));
mtbl = RCLASS_CALLABLE_M_TBL(defined_class);
diff --git a/wasm/setjmp.h b/wasm/setjmp.h
index e65bfc0ca0..82cfff1d00 100644
--- a/wasm/setjmp.h
+++ b/wasm/setjmp.h
@@ -5,7 +5,7 @@
#include <stdbool.h>
#ifndef WASM_SETJMP_STACK_BUFFER_SIZE
-# define WASM_SETJMP_STACK_BUFFER_SIZE 6144
+# define WASM_SETJMP_STACK_BUFFER_SIZE 8192
#endif
struct __rb_wasm_asyncify_jmp_buf {
diff --git a/yjit.c b/yjit.c
index 04231a0491..e11a30a6f8 100644
--- a/yjit.c
+++ b/yjit.c
@@ -396,12 +396,6 @@ rb_full_cfunc_return(rb_execution_context_t *ec, VALUE return_value)
ec->cfp->sp++;
}
-unsigned int
-rb_iseq_encoded_size(const rb_iseq_t *iseq)
-{
- return iseq->body->iseq_size;
-}
-
// TODO(alan): consider using an opaque pointer for the payload rather than a void pointer
void *
rb_iseq_get_yjit_payload(const rb_iseq_t *iseq)
@@ -437,40 +431,6 @@ rb_iseq_reset_jit_func(const rb_iseq_t *iseq)
iseq->body->jit_exception_calls = 0;
}
-// Get the PC for a given index in an iseq
-VALUE *
-rb_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx)
-{
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
- RUBY_ASSERT_ALWAYS(insn_idx < iseq->body->iseq_size);
- VALUE *encoded = iseq->body->iseq_encoded;
- VALUE *pc = &encoded[insn_idx];
- return pc;
-}
-
-// Get the opcode given a program counter. Can return trace opcode variants.
-int
-rb_iseq_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
-{
- // YJIT should only use iseqs after AST to bytecode compilation
- RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED));
-
- const VALUE at_pc = *pc;
- return rb_vm_insn_addr2opcode((const void *)at_pc);
-}
-
-unsigned long
-rb_RSTRING_LEN(VALUE str)
-{
- return RSTRING_LEN(str);
-}
-
-char *
-rb_RSTRING_PTR(VALUE str)
-{
- return RSTRING_PTR(str);
-}
-
rb_proc_t *
rb_yjit_get_proc_ptr(VALUE procv)
{
@@ -484,121 +444,8 @@ rb_yjit_get_proc_ptr(VALUE procv)
// Bindgen's temp/anon name isn't guaranteed stable.
typedef struct rb_iseq_param_keyword rb_seq_param_keyword_struct;
-const char *
-rb_insn_name(VALUE insn)
-{
- return insn_name(insn);
-}
-
-unsigned int
-rb_vm_ci_argc(const struct rb_callinfo *ci)
-{
- return vm_ci_argc(ci);
-}
-
-ID
-rb_vm_ci_mid(const struct rb_callinfo *ci)
-{
- return vm_ci_mid(ci);
-}
-
-unsigned int
-rb_vm_ci_flag(const struct rb_callinfo *ci)
-{
- return vm_ci_flag(ci);
-}
-
-const struct rb_callinfo_kwarg *
-rb_vm_ci_kwarg(const struct rb_callinfo *ci)
-{
- return vm_ci_kwarg(ci);
-}
-
-int
-rb_get_cikw_keyword_len(const struct rb_callinfo_kwarg *cikw)
-{
- return cikw->keyword_len;
-}
-
-VALUE
-rb_get_cikw_keywords_idx(const struct rb_callinfo_kwarg *cikw, int idx)
-{
- return cikw->keywords[idx];
-}
-
-rb_method_visibility_t
-rb_METHOD_ENTRY_VISI(const rb_callable_method_entry_t *me)
-{
- return METHOD_ENTRY_VISI(me);
-}
-
-rb_method_type_t
-rb_get_cme_def_type(const rb_callable_method_entry_t *cme)
-{
- if (UNDEFINED_METHOD_ENTRY_P(cme)) {
- return VM_METHOD_TYPE_UNDEF;
- }
- else {
- return cme->def->type;
- }
-}
-
-ID
-rb_get_cme_def_body_attr_id(const rb_callable_method_entry_t *cme)
-{
- return cme->def->body.attr.id;
-}
-
ID rb_get_symbol_id(VALUE namep);
-enum method_optimized_type
-rb_get_cme_def_body_optimized_type(const rb_callable_method_entry_t *cme)
-{
- return cme->def->body.optimized.type;
-}
-
-unsigned int
-rb_get_cme_def_body_optimized_index(const rb_callable_method_entry_t *cme)
-{
- return cme->def->body.optimized.index;
-}
-
-rb_method_cfunc_t *
-rb_get_cme_def_body_cfunc(const rb_callable_method_entry_t *cme)
-{
- return UNALIGNED_MEMBER_PTR(cme->def, body.cfunc);
-}
-
-uintptr_t
-rb_get_def_method_serial(const rb_method_definition_t *def)
-{
- return def->method_serial;
-}
-
-ID
-rb_get_def_original_id(const rb_method_definition_t *def)
-{
- return def->original_id;
-}
-
-int
-rb_get_mct_argc(const rb_method_cfunc_t *mct)
-{
- return mct->argc;
-}
-
-void *
-rb_get_mct_func(const rb_method_cfunc_t *mct)
-{
- return (void*)(uintptr_t)mct->func; // this field is defined as type VALUE (*func)(ANYARGS)
-}
-
-const rb_iseq_t *
-rb_get_def_iseq_ptr(rb_method_definition_t *def)
-{
- return def_iseq_ptr(def);
-}
-
VALUE
rb_get_def_bmethod_proc(rb_method_definition_t *def)
{
@@ -607,143 +454,11 @@ rb_get_def_bmethod_proc(rb_method_definition_t *def)
}
const rb_iseq_t *
-rb_get_iseq_body_local_iseq(const rb_iseq_t *iseq)
-{
- return iseq->body->local_iseq;
-}
-
-const rb_iseq_t *
rb_get_iseq_body_parent_iseq(const rb_iseq_t *iseq)
{
return iseq->body->parent_iseq;
}
-unsigned int
-rb_get_iseq_body_local_table_size(const rb_iseq_t *iseq)
-{
- return iseq->body->local_table_size;
-}
-
-VALUE *
-rb_get_iseq_body_iseq_encoded(const rb_iseq_t *iseq)
-{
- return iseq->body->iseq_encoded;
-}
-
-unsigned
-rb_get_iseq_body_stack_max(const rb_iseq_t *iseq)
-{
- return iseq->body->stack_max;
-}
-
-enum rb_iseq_type
-rb_get_iseq_body_type(const rb_iseq_t *iseq)
-{
- return iseq->body->type;
-}
-
-bool
-rb_get_iseq_flags_has_lead(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_lead;
-}
-
-bool
-rb_get_iseq_flags_has_opt(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_opt;
-}
-
-bool
-rb_get_iseq_flags_has_kw(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_kw;
-}
-
-bool
-rb_get_iseq_flags_has_post(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_post;
-}
-
-bool
-rb_get_iseq_flags_has_kwrest(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_kwrest;
-}
-
-bool
-rb_get_iseq_flags_anon_kwrest(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.anon_kwrest;
-}
-
-bool
-rb_get_iseq_flags_has_rest(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_rest;
-}
-
-bool
-rb_get_iseq_flags_ruby2_keywords(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.ruby2_keywords;
-}
-
-bool
-rb_get_iseq_flags_has_block(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_block;
-}
-
-bool
-rb_get_iseq_flags_ambiguous_param0(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.ambiguous_param0;
-}
-
-bool
-rb_get_iseq_flags_accepts_no_kwarg(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.accepts_no_kwarg;
-}
-
-bool
-rb_get_iseq_flags_forwardable(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.forwardable;
-}
-
-const rb_seq_param_keyword_struct *
-rb_get_iseq_body_param_keyword(const rb_iseq_t *iseq)
-{
- return iseq->body->param.keyword;
-}
-
-unsigned
-rb_get_iseq_body_param_size(const rb_iseq_t *iseq)
-{
- return iseq->body->param.size;
-}
-
-int
-rb_get_iseq_body_param_lead_num(const rb_iseq_t *iseq)
-{
- return iseq->body->param.lead_num;
-}
-
-int
-rb_get_iseq_body_param_opt_num(const rb_iseq_t *iseq)
-{
- return iseq->body->param.opt_num;
-}
-
-const VALUE *
-rb_get_iseq_body_param_opt_table(const rb_iseq_t *iseq)
-{
- return iseq->body->param.opt_table;
-}
-
VALUE
rb_optimized_call(VALUE *recv, rb_execution_context_t *ec, int argc, VALUE *argv, int kw_splat, VALUE block_handler)
{
@@ -789,30 +504,6 @@ rb_yjit_str_simple_append(VALUE str1, VALUE str2)
return rb_str_cat(str1, RSTRING_PTR(str2), RSTRING_LEN(str2));
}
-struct rb_control_frame_struct *
-rb_get_ec_cfp(const rb_execution_context_t *ec)
-{
- return ec->cfp;
-}
-
-const rb_iseq_t *
-rb_get_cfp_iseq(struct rb_control_frame_struct *cfp)
-{
- return cfp->iseq;
-}
-
-VALUE *
-rb_get_cfp_pc(struct rb_control_frame_struct *cfp)
-{
- return (VALUE*)cfp->pc;
-}
-
-VALUE *
-rb_get_cfp_sp(struct rb_control_frame_struct *cfp)
-{
- return cfp->sp;
-}
-
void
rb_set_cfp_pc(struct rb_control_frame_struct *cfp, const VALUE *pc)
{
@@ -825,37 +516,8 @@ rb_set_cfp_sp(struct rb_control_frame_struct *cfp, VALUE *sp)
cfp->sp = sp;
}
-VALUE
-rb_get_cfp_self(struct rb_control_frame_struct *cfp)
-{
- return cfp->self;
-}
-
-VALUE *
-rb_get_cfp_ep(struct rb_control_frame_struct *cfp)
-{
- return (VALUE*)cfp->ep;
-}
-
-const VALUE *
-rb_get_cfp_ep_level(struct rb_control_frame_struct *cfp, uint32_t lv)
-{
- uint32_t i;
- const VALUE *ep = (VALUE*)cfp->ep;
- for (i = 0; i < lv; i++) {
- ep = VM_ENV_PREV_EP(ep);
- }
- return ep;
-}
-
extern VALUE *rb_vm_base_ptr(struct rb_control_frame_struct *cfp);
-VALUE
-rb_yarv_class_of(VALUE obj)
-{
- return rb_class_of(obj);
-}
-
// YJIT needs this function to never allocate and never raise
VALUE
rb_yarv_str_eql_internal(VALUE str1, VALUE str2)
@@ -989,33 +651,6 @@ rb_yjit_iseq_inspect(const rb_iseq_t *iseq)
return buf;
}
-// The FL_TEST() macro
-VALUE
-rb_FL_TEST(VALUE obj, VALUE flags)
-{
- return RB_FL_TEST(obj, flags);
-}
-
-// The FL_TEST_RAW() macro, normally an internal implementation detail
-VALUE
-rb_FL_TEST_RAW(VALUE obj, VALUE flags)
-{
- return FL_TEST_RAW(obj, flags);
-}
-
-// The RB_TYPE_P macro
-bool
-rb_RB_TYPE_P(VALUE obj, enum ruby_value_type t)
-{
- return RB_TYPE_P(obj, t);
-}
-
-long
-rb_RSTRUCT_LEN(VALUE st)
-{
- return RSTRUCT_LEN(st);
-}
-
// There are RSTRUCT_SETs in ruby/internal/core/rstruct.h and internal/struct.h
// with different types (int vs long) for k. Here we use the one from ruby/internal/core/rstruct.h,
// which takes an int.
@@ -1025,24 +660,6 @@ rb_RSTRUCT_SET(VALUE st, int k, VALUE v)
RSTRUCT_SET(st, k, v);
}
-const struct rb_callinfo *
-rb_get_call_data_ci(const struct rb_call_data *cd)
-{
- return cd->ci;
-}
-
-bool
-rb_BASIC_OP_UNREDEFINED_P(enum ruby_basic_operators bop, uint32_t klass)
-{
- return BASIC_OP_UNREDEFINED_P(bop, klass);
-}
-
-VALUE
-rb_RCLASS_ORIGIN(VALUE c)
-{
- return RCLASS_ORIGIN(c);
-}
-
// Return the string encoding index
int
rb_ENCODING_GET(VALUE obj)
@@ -1056,32 +673,12 @@ rb_yjit_multi_ractor_p(void)
return rb_multi_ractor_p();
}
-// For debug builds
-void
-rb_assert_iseq_handle(VALUE handle)
-{
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_iseq));
-}
-
-int
-rb_IMEMO_TYPE_P(VALUE imemo, enum imemo_type imemo_type)
-{
- return IMEMO_TYPE_P(imemo, imemo_type);
-}
-
bool
rb_yjit_constcache_shareable(const struct iseq_inline_constant_cache_entry *ice)
{
return (ice->flags & IMEMO_CONST_CACHE_SHAREABLE) != 0;
}
-void
-rb_assert_cme_handle(VALUE handle)
-{
- RUBY_ASSERT_ALWAYS(!rb_objspace_garbage_object_p(handle));
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_ment));
-}
-
// Used for passing a callback and other data over rb_objspace_each_objects
struct iseq_callback_data {
rb_iseq_callback callback;
diff --git a/yjit/bindgen/src/main.rs b/yjit/bindgen/src/main.rs
index 9305a50cc9..9ee6fc7b8f 100644
--- a/yjit/bindgen/src/main.rs
+++ b/yjit/bindgen/src/main.rs
@@ -47,6 +47,7 @@ fn main() {
// Our C file for glue code
.header(src_root.join("yjit.c").to_str().unwrap())
+ .header(src_root.join("jit.c").to_str().unwrap())
// Don't want to copy over C comment
.generate_comments(false)
diff --git a/yjit/src/cruby_bindings.inc.rs b/yjit/src/cruby_bindings.inc.rs
index db4f75e39b..490a61226a 100644
--- a/yjit/src/cruby_bindings.inc.rs
+++ b/yjit/src/cruby_bindings.inc.rs
@@ -979,6 +979,7 @@ pub type robject_offsets = u32;
pub const RUBY_OFFSET_RSTRING_LEN: rstring_offsets = 16;
pub type rstring_offsets = u32;
pub type rb_seq_param_keyword_struct = rb_iseq_constant_body__bindgen_ty_1_rb_iseq_param_keyword;
+pub type rb_iseq_param_keyword_struct = rb_iseq_constant_body__bindgen_ty_1_rb_iseq_param_keyword;
extern "C" {
pub fn ruby_xfree(ptr: *mut ::std::os::raw::c_void);
pub fn rb_class_attached_object(klass: VALUE) -> VALUE;
@@ -1163,15 +1164,78 @@ extern "C" {
pub fn rb_yjit_reserve_addr_space(mem_size: u32) -> *mut u8;
pub fn rb_c_method_tracing_currently_enabled(ec: *const rb_execution_context_t) -> bool;
pub fn rb_full_cfunc_return(ec: *mut rb_execution_context_t, return_value: VALUE);
- pub fn rb_iseq_encoded_size(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
pub fn rb_iseq_get_yjit_payload(iseq: *const rb_iseq_t) -> *mut ::std::os::raw::c_void;
pub fn rb_iseq_set_yjit_payload(iseq: *const rb_iseq_t, payload: *mut ::std::os::raw::c_void);
pub fn rb_iseq_reset_jit_func(iseq: *const rb_iseq_t);
+ pub fn rb_yjit_get_proc_ptr(procv: VALUE) -> *mut rb_proc_t;
+ pub fn rb_get_symbol_id(namep: VALUE) -> ID;
+ pub fn rb_get_def_bmethod_proc(def: *mut rb_method_definition_t) -> VALUE;
+ pub fn rb_get_iseq_body_parent_iseq(iseq: *const rb_iseq_t) -> *const rb_iseq_t;
+ pub fn rb_optimized_call(
+ recv: *mut VALUE,
+ ec: *mut rb_execution_context_t,
+ argc: ::std::os::raw::c_int,
+ argv: *mut VALUE,
+ kw_splat: ::std::os::raw::c_int,
+ block_handler: VALUE,
+ ) -> VALUE;
+ pub fn rb_yjit_iseq_builtin_attrs(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
+ pub fn rb_yjit_builtin_function(iseq: *const rb_iseq_t) -> *const rb_builtin_function;
+ pub fn rb_yjit_str_simple_append(str1: VALUE, str2: VALUE) -> VALUE;
+ pub fn rb_set_cfp_pc(cfp: *mut rb_control_frame_struct, pc: *const VALUE);
+ pub fn rb_set_cfp_sp(cfp: *mut rb_control_frame_struct, sp: *mut VALUE);
+ pub fn rb_vm_base_ptr(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
+ pub fn rb_yarv_str_eql_internal(str1: VALUE, str2: VALUE) -> VALUE;
+ pub fn rb_str_neq_internal(str1: VALUE, str2: VALUE) -> VALUE;
+ pub fn rb_yarv_ary_entry_internal(ary: VALUE, offset: ::std::os::raw::c_long) -> VALUE;
+ pub fn rb_ary_unshift_m(argc: ::std::os::raw::c_int, argv: *mut VALUE, ary: VALUE) -> VALUE;
+ pub fn rb_yjit_rb_ary_subseq_length(ary: VALUE, beg: ::std::os::raw::c_long) -> VALUE;
+ pub fn rb_yjit_fix_div_fix(recv: VALUE, obj: VALUE) -> VALUE;
+ pub fn rb_yjit_fix_mod_fix(recv: VALUE, obj: VALUE) -> VALUE;
+ pub fn rb_yjit_ruby2_keywords_splat_p(obj: VALUE) -> usize;
+ pub fn rb_yjit_splat_varg_checks(
+ sp: *mut VALUE,
+ splat_array: VALUE,
+ cfp: *mut rb_control_frame_t,
+ ) -> VALUE;
+ pub fn rb_yjit_splat_varg_cfunc(stack_splat_array: *mut VALUE) -> ::std::os::raw::c_int;
+ pub fn rb_yjit_dump_iseq_loc(iseq: *const rb_iseq_t, insn_idx: u32);
+ pub fn rb_yjit_iseq_inspect(iseq: *const rb_iseq_t) -> *mut ::std::os::raw::c_char;
+ pub fn rb_RSTRUCT_SET(st: VALUE, k: ::std::os::raw::c_int, v: VALUE);
+ pub fn rb_ENCODING_GET(obj: VALUE) -> ::std::os::raw::c_int;
+ pub fn rb_yjit_multi_ractor_p() -> bool;
+ pub fn rb_yjit_constcache_shareable(ice: *const iseq_inline_constant_cache_entry) -> bool;
+ pub fn rb_yjit_for_each_iseq(callback: rb_iseq_callback, data: *mut ::std::os::raw::c_void);
+ pub fn rb_yjit_obj_written(
+ old: VALUE,
+ young: VALUE,
+ file: *const ::std::os::raw::c_char,
+ line: ::std::os::raw::c_int,
+ );
+ pub fn rb_yjit_vm_lock_then_barrier(
+ recursive_lock_level: *mut ::std::os::raw::c_uint,
+ file: *const ::std::os::raw::c_char,
+ line: ::std::os::raw::c_int,
+ );
+ pub fn rb_yjit_vm_unlock(
+ recursive_lock_level: *mut ::std::os::raw::c_uint,
+ file: *const ::std::os::raw::c_char,
+ line: ::std::os::raw::c_int,
+ );
+ pub fn rb_object_shape_count() -> VALUE;
+ pub fn rb_yjit_assert_holding_vm_lock();
+ pub fn rb_yjit_sendish_sp_pops(ci: *const rb_callinfo) -> usize;
+ pub fn rb_yjit_invokeblock_sp_pops(ci: *const rb_callinfo) -> usize;
+ pub fn rb_yjit_set_exception_return(
+ cfp: *mut rb_control_frame_t,
+ leave_exit: *mut ::std::os::raw::c_void,
+ leave_exception: *mut ::std::os::raw::c_void,
+ );
+ pub fn rb_iseq_encoded_size(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
pub fn rb_iseq_pc_at_idx(iseq: *const rb_iseq_t, insn_idx: u32) -> *mut VALUE;
pub fn rb_iseq_opcode_at_pc(iseq: *const rb_iseq_t, pc: *const VALUE) -> ::std::os::raw::c_int;
pub fn rb_RSTRING_LEN(str_: VALUE) -> ::std::os::raw::c_ulong;
pub fn rb_RSTRING_PTR(str_: VALUE) -> *mut ::std::os::raw::c_char;
- pub fn rb_yjit_get_proc_ptr(procv: VALUE) -> *mut rb_proc_t;
pub fn rb_insn_name(insn: VALUE) -> *const ::std::os::raw::c_char;
pub fn rb_vm_ci_argc(ci: *const rb_callinfo) -> ::std::os::raw::c_uint;
pub fn rb_vm_ci_mid(ci: *const rb_callinfo) -> ID;
@@ -1185,7 +1249,6 @@ extern "C" {
pub fn rb_METHOD_ENTRY_VISI(me: *const rb_callable_method_entry_t) -> rb_method_visibility_t;
pub fn rb_get_cme_def_type(cme: *const rb_callable_method_entry_t) -> rb_method_type_t;
pub fn rb_get_cme_def_body_attr_id(cme: *const rb_callable_method_entry_t) -> ID;
- pub fn rb_get_symbol_id(namep: VALUE) -> ID;
pub fn rb_get_cme_def_body_optimized_type(
cme: *const rb_callable_method_entry_t,
) -> method_optimized_type;
@@ -1200,9 +1263,7 @@ extern "C" {
pub fn rb_get_mct_argc(mct: *const rb_method_cfunc_t) -> ::std::os::raw::c_int;
pub fn rb_get_mct_func(mct: *const rb_method_cfunc_t) -> *mut ::std::os::raw::c_void;
pub fn rb_get_def_iseq_ptr(def: *mut rb_method_definition_t) -> *const rb_iseq_t;
- pub fn rb_get_def_bmethod_proc(def: *mut rb_method_definition_t) -> VALUE;
pub fn rb_get_iseq_body_local_iseq(iseq: *const rb_iseq_t) -> *const rb_iseq_t;
- pub fn rb_get_iseq_body_parent_iseq(iseq: *const rb_iseq_t) -> *const rb_iseq_t;
pub fn rb_get_iseq_body_local_table_size(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
pub fn rb_get_iseq_body_iseq_encoded(iseq: *const rb_iseq_t) -> *mut VALUE;
pub fn rb_get_iseq_body_stack_max(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
@@ -1221,87 +1282,27 @@ extern "C" {
pub fn rb_get_iseq_flags_forwardable(iseq: *const rb_iseq_t) -> bool;
pub fn rb_get_iseq_body_param_keyword(
iseq: *const rb_iseq_t,
- ) -> *const rb_seq_param_keyword_struct;
+ ) -> *const rb_iseq_param_keyword_struct;
pub fn rb_get_iseq_body_param_size(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
pub fn rb_get_iseq_body_param_lead_num(iseq: *const rb_iseq_t) -> ::std::os::raw::c_int;
pub fn rb_get_iseq_body_param_opt_num(iseq: *const rb_iseq_t) -> ::std::os::raw::c_int;
pub fn rb_get_iseq_body_param_opt_table(iseq: *const rb_iseq_t) -> *const VALUE;
- pub fn rb_optimized_call(
- recv: *mut VALUE,
- ec: *mut rb_execution_context_t,
- argc: ::std::os::raw::c_int,
- argv: *mut VALUE,
- kw_splat: ::std::os::raw::c_int,
- block_handler: VALUE,
- ) -> VALUE;
- pub fn rb_yjit_iseq_builtin_attrs(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
- pub fn rb_yjit_builtin_function(iseq: *const rb_iseq_t) -> *const rb_builtin_function;
- pub fn rb_yjit_str_simple_append(str1: VALUE, str2: VALUE) -> VALUE;
pub fn rb_get_ec_cfp(ec: *const rb_execution_context_t) -> *mut rb_control_frame_struct;
pub fn rb_get_cfp_iseq(cfp: *mut rb_control_frame_struct) -> *const rb_iseq_t;
pub fn rb_get_cfp_pc(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
pub fn rb_get_cfp_sp(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
- pub fn rb_set_cfp_pc(cfp: *mut rb_control_frame_struct, pc: *const VALUE);
- pub fn rb_set_cfp_sp(cfp: *mut rb_control_frame_struct, sp: *mut VALUE);
pub fn rb_get_cfp_self(cfp: *mut rb_control_frame_struct) -> VALUE;
pub fn rb_get_cfp_ep(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
pub fn rb_get_cfp_ep_level(cfp: *mut rb_control_frame_struct, lv: u32) -> *const VALUE;
- pub fn rb_vm_base_ptr(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
pub fn rb_yarv_class_of(obj: VALUE) -> VALUE;
- pub fn rb_yarv_str_eql_internal(str1: VALUE, str2: VALUE) -> VALUE;
- pub fn rb_str_neq_internal(str1: VALUE, str2: VALUE) -> VALUE;
- pub fn rb_yarv_ary_entry_internal(ary: VALUE, offset: ::std::os::raw::c_long) -> VALUE;
- pub fn rb_ary_unshift_m(argc: ::std::os::raw::c_int, argv: *mut VALUE, ary: VALUE) -> VALUE;
- pub fn rb_yjit_rb_ary_subseq_length(ary: VALUE, beg: ::std::os::raw::c_long) -> VALUE;
- pub fn rb_yjit_fix_div_fix(recv: VALUE, obj: VALUE) -> VALUE;
- pub fn rb_yjit_fix_mod_fix(recv: VALUE, obj: VALUE) -> VALUE;
- pub fn rb_yjit_ruby2_keywords_splat_p(obj: VALUE) -> usize;
- pub fn rb_yjit_splat_varg_checks(
- sp: *mut VALUE,
- splat_array: VALUE,
- cfp: *mut rb_control_frame_t,
- ) -> VALUE;
- pub fn rb_yjit_splat_varg_cfunc(stack_splat_array: *mut VALUE) -> ::std::os::raw::c_int;
- pub fn rb_yjit_dump_iseq_loc(iseq: *const rb_iseq_t, insn_idx: u32);
- pub fn rb_yjit_iseq_inspect(iseq: *const rb_iseq_t) -> *mut ::std::os::raw::c_char;
pub fn rb_FL_TEST(obj: VALUE, flags: VALUE) -> VALUE;
pub fn rb_FL_TEST_RAW(obj: VALUE, flags: VALUE) -> VALUE;
pub fn rb_RB_TYPE_P(obj: VALUE, t: ruby_value_type) -> bool;
pub fn rb_RSTRUCT_LEN(st: VALUE) -> ::std::os::raw::c_long;
- pub fn rb_RSTRUCT_SET(st: VALUE, k: ::std::os::raw::c_int, v: VALUE);
pub fn rb_get_call_data_ci(cd: *const rb_call_data) -> *const rb_callinfo;
pub fn rb_BASIC_OP_UNREDEFINED_P(bop: ruby_basic_operators, klass: u32) -> bool;
pub fn rb_RCLASS_ORIGIN(c: VALUE) -> VALUE;
- pub fn rb_ENCODING_GET(obj: VALUE) -> ::std::os::raw::c_int;
- pub fn rb_yjit_multi_ractor_p() -> bool;
pub fn rb_assert_iseq_handle(handle: VALUE);
pub fn rb_IMEMO_TYPE_P(imemo: VALUE, imemo_type: imemo_type) -> ::std::os::raw::c_int;
- pub fn rb_yjit_constcache_shareable(ice: *const iseq_inline_constant_cache_entry) -> bool;
pub fn rb_assert_cme_handle(handle: VALUE);
- pub fn rb_yjit_for_each_iseq(callback: rb_iseq_callback, data: *mut ::std::os::raw::c_void);
- pub fn rb_yjit_obj_written(
- old: VALUE,
- young: VALUE,
- file: *const ::std::os::raw::c_char,
- line: ::std::os::raw::c_int,
- );
- pub fn rb_yjit_vm_lock_then_barrier(
- recursive_lock_level: *mut ::std::os::raw::c_uint,
- file: *const ::std::os::raw::c_char,
- line: ::std::os::raw::c_int,
- );
- pub fn rb_yjit_vm_unlock(
- recursive_lock_level: *mut ::std::os::raw::c_uint,
- file: *const ::std::os::raw::c_char,
- line: ::std::os::raw::c_int,
- );
- pub fn rb_object_shape_count() -> VALUE;
- pub fn rb_yjit_assert_holding_vm_lock();
- pub fn rb_yjit_sendish_sp_pops(ci: *const rb_callinfo) -> usize;
- pub fn rb_yjit_invokeblock_sp_pops(ci: *const rb_callinfo) -> usize;
- pub fn rb_yjit_set_exception_return(
- cfp: *mut rb_control_frame_t,
- leave_exit: *mut ::std::os::raw::c_void,
- leave_exception: *mut ::std::os::raw::c_void,
- );
}
diff --git a/zjit.c b/zjit.c
index 32ccf521ad..620b9d6af3 100644
--- a/zjit.c
+++ b/zjit.c
@@ -156,18 +156,6 @@ rb_zjit_reserve_addr_space(uint32_t mem_size)
#endif
}
-unsigned long
-rb_RSTRING_LEN(VALUE str)
-{
- return RSTRING_LEN(str);
-}
-
-char *
-rb_RSTRING_PTR(VALUE str)
-{
- return RSTRING_PTR(str);
-}
-
void rb_zjit_profile_disable(const rb_iseq_t *iseq);
void
@@ -189,374 +177,20 @@ rb_zjit_compile_iseq(const rb_iseq_t *iseq, rb_execution_context_t *ec, bool jit
RB_VM_LOCK_LEAVE();
}
-unsigned int
-rb_iseq_encoded_size(const rb_iseq_t *iseq)
-{
- return iseq->body->iseq_size;
-}
-
-// Get the opcode given a program counter. Can return trace opcode variants.
-int
-rb_iseq_opcode_at_pc(const rb_iseq_t *iseq, const VALUE *pc)
-{
- // ZJIT should only use iseqs after AST to bytecode compilation
- RUBY_ASSERT_ALWAYS(FL_TEST_RAW((VALUE)iseq, ISEQ_TRANSLATED));
-
- const VALUE at_pc = *pc;
- return rb_vm_insn_addr2opcode((const void *)at_pc);
-}
-
-// Get the PC for a given index in an iseq
-VALUE *
-rb_iseq_pc_at_idx(const rb_iseq_t *iseq, uint32_t insn_idx)
-{
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(iseq, imemo_iseq));
- RUBY_ASSERT_ALWAYS(insn_idx < iseq->body->iseq_size);
- VALUE *encoded = iseq->body->iseq_encoded;
- VALUE *pc = &encoded[insn_idx];
- return pc;
-}
-
-const char *
-rb_insn_name(VALUE insn)
-{
- return insn_name(insn);
-}
-
-struct rb_control_frame_struct *
-rb_get_ec_cfp(const rb_execution_context_t *ec)
-{
- return ec->cfp;
-}
-
-const rb_iseq_t *
-rb_get_cfp_iseq(struct rb_control_frame_struct *cfp)
-{
- return cfp->iseq;
-}
-
-VALUE *
-rb_get_cfp_pc(struct rb_control_frame_struct *cfp)
-{
- return (VALUE*)cfp->pc;
-}
-
-VALUE *
-rb_get_cfp_sp(struct rb_control_frame_struct *cfp)
-{
- return cfp->sp;
-}
-
-VALUE
-rb_get_cfp_self(struct rb_control_frame_struct *cfp)
-{
- return cfp->self;
-}
-
-VALUE *
-rb_get_cfp_ep(struct rb_control_frame_struct *cfp)
-{
- return (VALUE*)cfp->ep;
-}
-
-const VALUE *
-rb_get_cfp_ep_level(struct rb_control_frame_struct *cfp, uint32_t lv)
-{
- uint32_t i;
- const VALUE *ep = (VALUE*)cfp->ep;
- for (i = 0; i < lv; i++) {
- ep = VM_ENV_PREV_EP(ep);
- }
- return ep;
-}
-
extern VALUE *rb_vm_base_ptr(struct rb_control_frame_struct *cfp);
-rb_method_type_t
-rb_get_cme_def_type(const rb_callable_method_entry_t *cme)
-{
- if (UNDEFINED_METHOD_ENTRY_P(cme)) {
- return VM_METHOD_TYPE_UNDEF;
- }
- else {
- return cme->def->type;
- }
-}
-
-ID
-rb_get_cme_def_body_attr_id(const rb_callable_method_entry_t *cme)
-{
- return cme->def->body.attr.id;
-}
-
-enum method_optimized_type
-rb_get_cme_def_body_optimized_type(const rb_callable_method_entry_t *cme)
-{
- return cme->def->body.optimized.type;
-}
-
-unsigned int
-rb_get_cme_def_body_optimized_index(const rb_callable_method_entry_t *cme)
-{
- return cme->def->body.optimized.index;
-}
-
-rb_method_cfunc_t *
-rb_get_cme_def_body_cfunc(const rb_callable_method_entry_t *cme)
-{
- return UNALIGNED_MEMBER_PTR(cme->def, body.cfunc);
-}
-
-uintptr_t
-rb_get_def_method_serial(const rb_method_definition_t *def)
-{
- return def->method_serial;
-}
-
-ID
-rb_get_def_original_id(const rb_method_definition_t *def)
-{
- return def->original_id;
-}
-
-int
-rb_get_mct_argc(const rb_method_cfunc_t *mct)
-{
- return mct->argc;
-}
-
-void *
-rb_get_mct_func(const rb_method_cfunc_t *mct)
-{
- return (void*)(uintptr_t)mct->func; // this field is defined as type VALUE (*func)(ANYARGS)
-}
-
-const rb_iseq_t *
-rb_get_def_iseq_ptr(rb_method_definition_t *def)
-{
- return def_iseq_ptr(def);
-}
-
-const rb_iseq_t *
-rb_get_iseq_body_local_iseq(const rb_iseq_t *iseq)
-{
- return iseq->body->local_iseq;
-}
-
-VALUE *
-rb_get_iseq_body_iseq_encoded(const rb_iseq_t *iseq)
-{
- return iseq->body->iseq_encoded;
-}
-
-unsigned
-rb_get_iseq_body_stack_max(const rb_iseq_t *iseq)
-{
- return iseq->body->stack_max;
-}
-
-enum rb_iseq_type
-rb_get_iseq_body_type(const rb_iseq_t *iseq)
-{
- return iseq->body->type;
-}
-
-bool
-rb_get_iseq_flags_has_lead(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_lead;
-}
-
-bool
-rb_get_iseq_flags_has_opt(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_opt;
-}
-
-bool
-rb_get_iseq_flags_has_kw(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_kw;
-}
-
-bool
-rb_get_iseq_flags_has_post(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_post;
-}
-
-bool
-rb_get_iseq_flags_has_kwrest(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_kwrest;
-}
-
-bool
-rb_get_iseq_flags_anon_kwrest(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.anon_kwrest;
-}
-
-bool
-rb_get_iseq_flags_has_rest(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_rest;
-}
-
-bool
-rb_get_iseq_flags_ruby2_keywords(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.ruby2_keywords;
-}
-
-bool
-rb_get_iseq_flags_has_block(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.has_block;
-}
-
-bool
-rb_get_iseq_flags_ambiguous_param0(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.ambiguous_param0;
-}
-
-bool
-rb_get_iseq_flags_accepts_no_kwarg(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.accepts_no_kwarg;
-}
-
-bool
-rb_get_iseq_flags_forwardable(const rb_iseq_t *iseq)
-{
- return iseq->body->param.flags.forwardable;
-}
-
-// This is defined only as a named struct inside rb_iseq_constant_body.
-// By giving it a separate typedef, we make it nameable by rust-bindgen.
-// Bindgen's temp/anon name isn't guaranteed stable.
-typedef struct rb_iseq_param_keyword rb_iseq_param_keyword_struct;
-
-const rb_iseq_param_keyword_struct *
-rb_get_iseq_body_param_keyword(const rb_iseq_t *iseq)
-{
- return iseq->body->param.keyword;
-}
-
-unsigned
-rb_get_iseq_body_param_size(const rb_iseq_t *iseq)
-{
- return iseq->body->param.size;
-}
-
-int
-rb_get_iseq_body_param_lead_num(const rb_iseq_t *iseq)
-{
- return iseq->body->param.lead_num;
-}
-
-int
-rb_get_iseq_body_param_opt_num(const rb_iseq_t *iseq)
-{
- return iseq->body->param.opt_num;
-}
-
-const VALUE *
-rb_get_iseq_body_param_opt_table(const rb_iseq_t *iseq)
-{
- return iseq->body->param.opt_table;
-}
-
-unsigned int
-rb_get_iseq_body_local_table_size(const rb_iseq_t *iseq)
-{
- return iseq->body->local_table_size;
-}
-
-int
-rb_get_cikw_keyword_len(const struct rb_callinfo_kwarg *cikw)
-{
- return cikw->keyword_len;
-}
-
-VALUE
-rb_get_cikw_keywords_idx(const struct rb_callinfo_kwarg *cikw, int idx)
-{
- return cikw->keywords[idx];
-}
-
-const struct rb_callinfo *
-rb_get_call_data_ci(const struct rb_call_data *cd)
-{
- return cd->ci;
-}
-
-// The FL_TEST() macro
-VALUE
-rb_FL_TEST(VALUE obj, VALUE flags)
-{
- return RB_FL_TEST(obj, flags);
-}
-
-// The FL_TEST_RAW() macro, normally an internal implementation detail
-VALUE
-rb_FL_TEST_RAW(VALUE obj, VALUE flags)
-{
- return FL_TEST_RAW(obj, flags);
-}
-
-// The RB_TYPE_P macro
-bool
-rb_RB_TYPE_P(VALUE obj, enum ruby_value_type t)
-{
- return RB_TYPE_P(obj, t);
-}
-
-long
-rb_RSTRUCT_LEN(VALUE st)
-{
- return RSTRUCT_LEN(st);
-}
-
-bool
-rb_BASIC_OP_UNREDEFINED_P(enum ruby_basic_operators bop, uint32_t klass)
-{
- return BASIC_OP_UNREDEFINED_P(bop, klass);
-}
-
bool
rb_zjit_multi_ractor_p(void)
{
return rb_multi_ractor_p();
}
-// For debug builds
-void
-rb_assert_iseq_handle(VALUE handle)
-{
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_iseq));
-}
-
bool
rb_zjit_constcache_shareable(const struct iseq_inline_constant_cache_entry *ice)
{
return (ice->flags & IMEMO_CONST_CACHE_SHAREABLE) != 0;
}
-void
-rb_assert_cme_handle(VALUE handle)
-{
- RUBY_ASSERT_ALWAYS(!rb_objspace_garbage_object_p(handle));
- RUBY_ASSERT_ALWAYS(IMEMO_TYPE_P(handle, imemo_ment));
-}
-
-int
-rb_IMEMO_TYPE_P(VALUE imemo, enum imemo_type imemo_type)
-{
- return IMEMO_TYPE_P(imemo, imemo_type);
-}
-
// Release the VM lock. The lock level must point to the same integer used to
// acquire the lock.
void
@@ -614,42 +248,6 @@ rb_zjit_icache_invalidate(void *start, void *end)
#endif
}
-unsigned int
-rb_vm_ci_argc(const struct rb_callinfo *ci)
-{
- return vm_ci_argc(ci);
-}
-
-ID
-rb_vm_ci_mid(const struct rb_callinfo *ci)
-{
- return vm_ci_mid(ci);
-}
-
-unsigned int
-rb_vm_ci_flag(const struct rb_callinfo *ci)
-{
- return vm_ci_flag(ci);
-}
-
-const struct rb_callinfo_kwarg *
-rb_vm_ci_kwarg(const struct rb_callinfo *ci)
-{
- return vm_ci_kwarg(ci);
-}
-
-rb_method_visibility_t
-rb_METHOD_ENTRY_VISI(const rb_callable_method_entry_t *me)
-{
- return METHOD_ENTRY_VISI(me);
-}
-
-VALUE
-rb_yarv_class_of(VALUE obj)
-{
- return rb_class_of(obj);
-}
-
// Acquire the VM lock and then signal all other Ruby threads (ractors) to
// contend for the VM lock, putting them to sleep. ZJIT uses this to evict
// threads running inside generated code so among other things, it can
@@ -661,12 +259,6 @@ rb_zjit_vm_lock_then_barrier(unsigned int *recursive_lock_level, const char *fil
rb_vm_barrier();
}
-VALUE
-rb_RCLASS_ORIGIN(VALUE c)
-{
- return RCLASS_ORIGIN(c);
-}
-
// Convert a given ISEQ's instructions to zjit_* instructions
void
rb_zjit_profile_enable(const rb_iseq_t *iseq)
diff --git a/zjit/bindgen/src/main.rs b/zjit/bindgen/src/main.rs
index 5372ead3e5..f47dff744c 100644
--- a/zjit/bindgen/src/main.rs
+++ b/zjit/bindgen/src/main.rs
@@ -51,6 +51,7 @@ fn main() {
// Our C file for glue code
.header(src_root.join(c_file).to_str().unwrap())
+ .header(src_root.join("jit.c").to_str().unwrap())
// Don't want to copy over C comment
.generate_comments(false)
diff --git a/zjit/src/cruby_bindings.inc.rs b/zjit/src/cruby_bindings.inc.rs
index 169789ef77..88532abb63 100644
--- a/zjit/src/cruby_bindings.inc.rs
+++ b/zjit/src/cruby_bindings.inc.rs
@@ -929,21 +929,46 @@ unsafe extern "C" {
pub fn rb_jit_cont_each_iseq(callback: rb_iseq_callback, data: *mut ::std::os::raw::c_void);
pub fn rb_zjit_get_page_size() -> u32;
pub fn rb_zjit_reserve_addr_space(mem_size: u32) -> *mut u8;
- pub fn rb_RSTRING_LEN(str_: VALUE) -> ::std::os::raw::c_ulong;
- pub fn rb_RSTRING_PTR(str_: VALUE) -> *mut ::std::os::raw::c_char;
pub fn rb_zjit_profile_disable(iseq: *const rb_iseq_t);
+ pub fn rb_vm_base_ptr(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
+ pub fn rb_zjit_multi_ractor_p() -> bool;
+ pub fn rb_zjit_constcache_shareable(ice: *const iseq_inline_constant_cache_entry) -> bool;
+ pub fn rb_zjit_vm_unlock(
+ recursive_lock_level: *mut ::std::os::raw::c_uint,
+ file: *const ::std::os::raw::c_char,
+ line: ::std::os::raw::c_int,
+ );
+ pub fn rb_zjit_mark_writable(mem_block: *mut ::std::os::raw::c_void, mem_size: u32) -> bool;
+ pub fn rb_zjit_mark_executable(mem_block: *mut ::std::os::raw::c_void, mem_size: u32);
+ pub fn rb_zjit_mark_unused(mem_block: *mut ::std::os::raw::c_void, mem_size: u32) -> bool;
+ pub fn rb_zjit_icache_invalidate(
+ start: *mut ::std::os::raw::c_void,
+ end: *mut ::std::os::raw::c_void,
+ );
+ pub fn rb_zjit_vm_lock_then_barrier(
+ recursive_lock_level: *mut ::std::os::raw::c_uint,
+ file: *const ::std::os::raw::c_char,
+ line: ::std::os::raw::c_int,
+ );
+ pub fn rb_iseq_get_zjit_payload(iseq: *const rb_iseq_t) -> *mut ::std::os::raw::c_void;
+ pub fn rb_iseq_set_zjit_payload(iseq: *const rb_iseq_t, payload: *mut ::std::os::raw::c_void);
+ pub fn rb_zjit_print_exception();
pub fn rb_iseq_encoded_size(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
- pub fn rb_iseq_opcode_at_pc(iseq: *const rb_iseq_t, pc: *const VALUE) -> ::std::os::raw::c_int;
pub fn rb_iseq_pc_at_idx(iseq: *const rb_iseq_t, insn_idx: u32) -> *mut VALUE;
+ pub fn rb_iseq_opcode_at_pc(iseq: *const rb_iseq_t, pc: *const VALUE) -> ::std::os::raw::c_int;
+ pub fn rb_RSTRING_LEN(str_: VALUE) -> ::std::os::raw::c_ulong;
+ pub fn rb_RSTRING_PTR(str_: VALUE) -> *mut ::std::os::raw::c_char;
pub fn rb_insn_name(insn: VALUE) -> *const ::std::os::raw::c_char;
- pub fn rb_get_ec_cfp(ec: *const rb_execution_context_t) -> *mut rb_control_frame_struct;
- pub fn rb_get_cfp_iseq(cfp: *mut rb_control_frame_struct) -> *const rb_iseq_t;
- pub fn rb_get_cfp_pc(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
- pub fn rb_get_cfp_sp(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
- pub fn rb_get_cfp_self(cfp: *mut rb_control_frame_struct) -> VALUE;
- pub fn rb_get_cfp_ep(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
- pub fn rb_get_cfp_ep_level(cfp: *mut rb_control_frame_struct, lv: u32) -> *const VALUE;
- pub fn rb_vm_base_ptr(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
+ pub fn rb_vm_ci_argc(ci: *const rb_callinfo) -> ::std::os::raw::c_uint;
+ pub fn rb_vm_ci_mid(ci: *const rb_callinfo) -> ID;
+ pub fn rb_vm_ci_flag(ci: *const rb_callinfo) -> ::std::os::raw::c_uint;
+ pub fn rb_vm_ci_kwarg(ci: *const rb_callinfo) -> *const rb_callinfo_kwarg;
+ pub fn rb_get_cikw_keyword_len(cikw: *const rb_callinfo_kwarg) -> ::std::os::raw::c_int;
+ pub fn rb_get_cikw_keywords_idx(
+ cikw: *const rb_callinfo_kwarg,
+ idx: ::std::os::raw::c_int,
+ ) -> VALUE;
+ pub fn rb_METHOD_ENTRY_VISI(me: *const rb_callable_method_entry_t) -> rb_method_visibility_t;
pub fn rb_get_cme_def_type(cme: *const rb_callable_method_entry_t) -> rb_method_type_t;
pub fn rb_get_cme_def_body_attr_id(cme: *const rb_callable_method_entry_t) -> ID;
pub fn rb_get_cme_def_body_optimized_type(
@@ -961,6 +986,7 @@ unsafe extern "C" {
pub fn rb_get_mct_func(mct: *const rb_method_cfunc_t) -> *mut ::std::os::raw::c_void;
pub fn rb_get_def_iseq_ptr(def: *mut rb_method_definition_t) -> *const rb_iseq_t;
pub fn rb_get_iseq_body_local_iseq(iseq: *const rb_iseq_t) -> *const rb_iseq_t;
+ pub fn rb_get_iseq_body_local_table_size(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
pub fn rb_get_iseq_body_iseq_encoded(iseq: *const rb_iseq_t) -> *mut VALUE;
pub fn rb_get_iseq_body_stack_max(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
pub fn rb_get_iseq_body_type(iseq: *const rb_iseq_t) -> rb_iseq_type;
@@ -983,48 +1009,22 @@ unsafe extern "C" {
pub fn rb_get_iseq_body_param_lead_num(iseq: *const rb_iseq_t) -> ::std::os::raw::c_int;
pub fn rb_get_iseq_body_param_opt_num(iseq: *const rb_iseq_t) -> ::std::os::raw::c_int;
pub fn rb_get_iseq_body_param_opt_table(iseq: *const rb_iseq_t) -> *const VALUE;
- pub fn rb_get_iseq_body_local_table_size(iseq: *const rb_iseq_t) -> ::std::os::raw::c_uint;
- pub fn rb_get_cikw_keyword_len(cikw: *const rb_callinfo_kwarg) -> ::std::os::raw::c_int;
- pub fn rb_get_cikw_keywords_idx(
- cikw: *const rb_callinfo_kwarg,
- idx: ::std::os::raw::c_int,
- ) -> VALUE;
- pub fn rb_get_call_data_ci(cd: *const rb_call_data) -> *const rb_callinfo;
+ pub fn rb_get_ec_cfp(ec: *const rb_execution_context_t) -> *mut rb_control_frame_struct;
+ pub fn rb_get_cfp_iseq(cfp: *mut rb_control_frame_struct) -> *const rb_iseq_t;
+ pub fn rb_get_cfp_pc(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
+ pub fn rb_get_cfp_sp(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
+ pub fn rb_get_cfp_self(cfp: *mut rb_control_frame_struct) -> VALUE;
+ pub fn rb_get_cfp_ep(cfp: *mut rb_control_frame_struct) -> *mut VALUE;
+ pub fn rb_get_cfp_ep_level(cfp: *mut rb_control_frame_struct, lv: u32) -> *const VALUE;
+ pub fn rb_yarv_class_of(obj: VALUE) -> VALUE;
pub fn rb_FL_TEST(obj: VALUE, flags: VALUE) -> VALUE;
pub fn rb_FL_TEST_RAW(obj: VALUE, flags: VALUE) -> VALUE;
pub fn rb_RB_TYPE_P(obj: VALUE, t: ruby_value_type) -> bool;
pub fn rb_RSTRUCT_LEN(st: VALUE) -> ::std::os::raw::c_long;
+ pub fn rb_get_call_data_ci(cd: *const rb_call_data) -> *const rb_callinfo;
pub fn rb_BASIC_OP_UNREDEFINED_P(bop: ruby_basic_operators, klass: u32) -> bool;
- pub fn rb_zjit_multi_ractor_p() -> bool;
+ pub fn rb_RCLASS_ORIGIN(c: VALUE) -> VALUE;
pub fn rb_assert_iseq_handle(handle: VALUE);
- pub fn rb_zjit_constcache_shareable(ice: *const iseq_inline_constant_cache_entry) -> bool;
- pub fn rb_assert_cme_handle(handle: VALUE);
pub fn rb_IMEMO_TYPE_P(imemo: VALUE, imemo_type: imemo_type) -> ::std::os::raw::c_int;
- pub fn rb_zjit_vm_unlock(
- recursive_lock_level: *mut ::std::os::raw::c_uint,
- file: *const ::std::os::raw::c_char,
- line: ::std::os::raw::c_int,
- );
- pub fn rb_zjit_mark_writable(mem_block: *mut ::std::os::raw::c_void, mem_size: u32) -> bool;
- pub fn rb_zjit_mark_executable(mem_block: *mut ::std::os::raw::c_void, mem_size: u32);
- pub fn rb_zjit_mark_unused(mem_block: *mut ::std::os::raw::c_void, mem_size: u32) -> bool;
- pub fn rb_zjit_icache_invalidate(
- start: *mut ::std::os::raw::c_void,
- end: *mut ::std::os::raw::c_void,
- );
- pub fn rb_vm_ci_argc(ci: *const rb_callinfo) -> ::std::os::raw::c_uint;
- pub fn rb_vm_ci_mid(ci: *const rb_callinfo) -> ID;
- pub fn rb_vm_ci_flag(ci: *const rb_callinfo) -> ::std::os::raw::c_uint;
- pub fn rb_vm_ci_kwarg(ci: *const rb_callinfo) -> *const rb_callinfo_kwarg;
- pub fn rb_METHOD_ENTRY_VISI(me: *const rb_callable_method_entry_t) -> rb_method_visibility_t;
- pub fn rb_yarv_class_of(obj: VALUE) -> VALUE;
- pub fn rb_zjit_vm_lock_then_barrier(
- recursive_lock_level: *mut ::std::os::raw::c_uint,
- file: *const ::std::os::raw::c_char,
- line: ::std::os::raw::c_int,
- );
- pub fn rb_RCLASS_ORIGIN(c: VALUE) -> VALUE;
- pub fn rb_iseq_get_zjit_payload(iseq: *const rb_iseq_t) -> *mut ::std::os::raw::c_void;
- pub fn rb_iseq_set_zjit_payload(iseq: *const rb_iseq_t, payload: *mut ::std::os::raw::c_void);
- pub fn rb_zjit_print_exception();
+ pub fn rb_assert_cme_handle(handle: VALUE);
}
diff --git a/zjit/src/hir.rs b/zjit/src/hir.rs
index d54617efe4..da56738231 100644
--- a/zjit/src/hir.rs
+++ b/zjit/src/hir.rs
@@ -141,6 +141,7 @@ impl<'a> std::fmt::Display for InvariantPrinter<'a> {
write!(f, "BOPRedefined(")?;
match klass {
INTEGER_REDEFINED_OP_FLAG => write!(f, "INTEGER_REDEFINED_OP_FLAG")?,
+ ARRAY_REDEFINED_OP_FLAG => write!(f, "ARRAY_REDEFINED_OP_FLAG")?,
_ => write!(f, "{klass}")?,
}
write!(f, ", ")?;
@@ -156,6 +157,7 @@ impl<'a> std::fmt::Display for InvariantPrinter<'a> {
BOP_LE => write!(f, "BOP_LE")?,
BOP_GT => write!(f, "BOP_GT")?,
BOP_GE => write!(f, "BOP_GE")?,
+ BOP_MAX => write!(f, "BOP_MAX")?,
_ => write!(f, "{bop}")?,
}
write!(f, ")")
@@ -310,6 +312,7 @@ pub enum Insn {
NewArray { elements: Vec<InsnId>, state: InsnId },
ArraySet { array: InsnId, idx: usize, val: InsnId },
ArrayDup { val: InsnId, state: InsnId },
+ ArrayMax { elements: Vec<InsnId>, state: InsnId },
// Check if the value is truthy and "return" a C boolean. In reality, we will likely fuse this
// with IfTrue/IfFalse in the backend to generate jcc.
@@ -441,6 +444,15 @@ impl<'a> std::fmt::Display for InsnPrinter<'a> {
}
Ok(())
}
+ Insn::ArrayMax { elements, .. } => {
+ write!(f, "ArrayMax")?;
+ let mut prefix = " ";
+ for element in elements {
+ write!(f, "{prefix}{element}")?;
+ prefix = ", ";
+ }
+ Ok(())
+ }
Insn::ArraySet { array, idx, val } => { write!(f, "ArraySet {array}, {idx}, {val}") }
Insn::ArrayDup { val, .. } => { write!(f, "ArrayDup {val}") }
Insn::StringCopy { val } => { write!(f, "StringCopy {val}") }
@@ -744,12 +756,19 @@ impl Function {
}
};
}
+ macro_rules! find_vec {
+ ( $x:expr ) => {
+ {
+ $x.iter().map(|arg| find!(*arg)).collect()
+ }
+ };
+ }
macro_rules! find_branch_edge {
( $edge:ident ) => {
{
BranchEdge {
target: $edge.target,
- args: $edge.args.iter().map(|x| find!(*x)).collect(),
+ args: find_vec!($edge.args),
}
}
};
@@ -757,7 +776,7 @@ impl Function {
let insn_id = self.union_find.borrow_mut().find(insn_id);
use Insn::*;
match &self.insns[insn_id.0] {
- result@(PutSelf | Const {..} | Param {..} | NewArray {..} | GetConstantPath {..}
+ result@(PutSelf | Const {..} | Param {..} | GetConstantPath {..}
| PatchPoint {..}) => result.clone(),
Snapshot { state: FrameState { iseq, insn_idx, pc, stack, locals } } =>
Snapshot {
@@ -816,6 +835,8 @@ impl Function {
ArrayDup { val , state } => ArrayDup { val: find!(*val), state: *state },
CCall { cfun, args, name, return_type } => CCall { cfun: *cfun, args: args.iter().map(|arg| find!(*arg)).collect(), name: *name, return_type: *return_type },
Defined { .. } => todo!("find(Defined)"),
+ NewArray { elements, state } => NewArray { elements: find_vec!(*elements), state: find!(*state) },
+ ArrayMax { elements, state } => ArrayMax { elements: find_vec!(*elements), state: find!(*state) },
}
}
@@ -882,6 +903,7 @@ impl Function {
Insn::PutSelf => types::BasicObject,
Insn::Defined { .. } => types::BasicObject,
Insn::GetConstantPath { .. } => types::BasicObject,
+ Insn::ArrayMax { .. } => types::BasicObject,
}
}
@@ -1309,9 +1331,13 @@ impl Function {
necessary[insn_id.0] = true;
match self.find(insn_id) {
Insn::PutSelf | Insn::Const { .. } | Insn::Param { .. }
- | Insn::NewArray { .. } | Insn::PatchPoint(..)
- | Insn::GetConstantPath { .. } =>
+ | Insn::PatchPoint(..) | Insn::GetConstantPath { .. } =>
{}
+ Insn::ArrayMax { elements, state }
+ | Insn::NewArray { elements, state } => {
+ worklist.extend(elements);
+ worklist.push_back(state);
+ }
Insn::StringCopy { val }
| Insn::StringIntern { val }
| Insn::Return { val }
@@ -1636,6 +1662,7 @@ pub enum CallType {
pub enum ParseError {
StackUnderflow(FrameState),
UnknownOpcode(String),
+ UnknownNewArraySend(String),
UnhandledCallType(CallType),
}
@@ -1755,6 +1782,26 @@ pub fn iseq_to_hir(iseq: *const rb_iseq_t) -> Result<Function, ParseError> {
elements.reverse();
state.stack_push(fun.push_insn(block, Insn::NewArray { elements, state: exit_id }));
}
+ YARVINSN_opt_newarray_send => {
+ let count = get_arg(pc, 0).as_usize();
+ let method = get_arg(pc, 1).as_u32();
+ let mut elements = vec![];
+ for _ in 0..count {
+ elements.push(state.stack_pop()?);
+ }
+ elements.reverse();
+ let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.clone() });
+ let (bop, insn) = match method {
+ VM_OPT_NEWARRAY_SEND_MAX => (BOP_MAX, Insn::ArrayMax { elements, state: exit_id }),
+ VM_OPT_NEWARRAY_SEND_MIN => return Err(ParseError::UnknownNewArraySend("min".into())),
+ VM_OPT_NEWARRAY_SEND_HASH => return Err(ParseError::UnknownNewArraySend("hash".into())),
+ VM_OPT_NEWARRAY_SEND_PACK => return Err(ParseError::UnknownNewArraySend("pack".into())),
+ VM_OPT_NEWARRAY_SEND_PACK_BUFFER => return Err(ParseError::UnknownNewArraySend("pack_buffer".into())),
+ _ => return Err(ParseError::UnknownNewArraySend(format!("{method}"))),
+ };
+ fun.push_insn(block, Insn::PatchPoint(Invariant::BOPRedefined { klass: ARRAY_REDEFINED_OP_FLAG, bop }));
+ state.stack_push(fun.push_insn(block, insn));
+ }
YARVINSN_duparray => {
let val = fun.push_insn(block, Insn::Const { val: Const::Value(get_arg(pc, 0)) });
let exit_id = fun.push_insn(block, Insn::Snapshot { state: exit_state.clone() });
@@ -2831,6 +2878,35 @@ mod tests {
Return v10
"#]]);
}
+
+ #[test]
+ fn test_opt_newarray_send_max_no_elements() {
+ eval("
+ def test = [].max
+ ");
+ // TODO(max): Rewrite to nil
+ assert_method_hir("test", expect![[r#"
+ fn test:
+ bb0():
+ PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_MAX)
+ v3:BasicObject = ArrayMax
+ Return v3
+ "#]]);
+ }
+
+ #[test]
+ fn test_opt_newarray_send_max() {
+ eval("
+ def test(a,b) = [a,b].max
+ ");
+ assert_method_hir("test", expect![[r#"
+ fn test:
+ bb0(v0:BasicObject, v1:BasicObject):
+ PatchPoint BOPRedefined(ARRAY_REDEFINED_OP_FLAG, BOP_MAX)
+ v5:BasicObject = ArrayMax v0, v1
+ Return v5
+ "#]]);
+ }
}
#[cfg(test)]