summaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
Diffstat (limited to 'include')
-rw-r--r--include/ruby/assert.h112
-rw-r--r--include/ruby/atomic.h503
-rw-r--r--include/ruby/backward.h6
-rw-r--r--include/ruby/backward/2/rmodule.h2
-rw-r--r--include/ruby/backward/cxxanyargs.hpp29
-rw-r--r--include/ruby/debug.h235
-rw-r--r--include/ruby/fiber/scheduler.h109
-rw-r--r--include/ruby/intern.h1
-rw-r--r--include/ruby/internal/abi.h4
-rw-r--r--include/ruby/internal/anyargs.h22
-rw-r--r--include/ruby/internal/arithmetic/int.h2
-rw-r--r--include/ruby/internal/arithmetic/intptr_t.h12
-rw-r--r--include/ruby/internal/arithmetic/long.h14
-rw-r--r--include/ruby/internal/arithmetic/long_long.h2
-rw-r--r--include/ruby/internal/arithmetic/st_data_t.h4
-rw-r--r--include/ruby/internal/attr/deprecated.h9
-rw-r--r--include/ruby/internal/attr/forceinline.h2
-rw-r--r--include/ruby/internal/attr/noexcept.h4
-rw-r--r--include/ruby/internal/attr/nonstring.h40
-rw-r--r--include/ruby/internal/attr/restrict.h2
-rw-r--r--include/ruby/internal/compiler_is/msvc.h13
-rw-r--r--include/ruby/internal/config.h2
-rw-r--r--include/ruby/internal/core/rarray.h4
-rw-r--r--include/ruby/internal/core/rbasic.h34
-rw-r--r--include/ruby/internal/core/rclass.h2
-rw-r--r--include/ruby/internal/core/rdata.h35
-rw-r--r--include/ruby/internal/core/robject.h40
-rw-r--r--include/ruby/internal/core/rstring.h57
-rw-r--r--include/ruby/internal/core/rstruct.h12
-rw-r--r--include/ruby/internal/core/rtypeddata.h257
-rw-r--r--include/ruby/internal/ctype.h4
-rw-r--r--include/ruby/internal/encoding/coderange.h2
-rw-r--r--include/ruby/internal/encoding/encoding.h3
-rw-r--r--include/ruby/internal/encoding/string.h8
-rw-r--r--include/ruby/internal/error.h33
-rw-r--r--include/ruby/internal/eval.h15
-rw-r--r--include/ruby/internal/fl_type.h260
-rw-r--r--include/ruby/internal/gc.h23
-rw-r--r--include/ruby/internal/globals.h4
-rw-r--r--include/ruby/internal/has/builtin.h4
-rw-r--r--include/ruby/internal/has/c_attribute.h12
-rw-r--r--include/ruby/internal/intern/array.h10
-rw-r--r--include/ruby/internal/intern/bignum.h4
-rw-r--r--include/ruby/internal/intern/class.h8
-rw-r--r--include/ruby/internal/intern/complex.h4
-rw-r--r--include/ruby/internal/intern/cont.h11
-rw-r--r--include/ruby/internal/intern/enumerator.h12
-rw-r--r--include/ruby/internal/intern/error.h18
-rw-r--r--include/ruby/internal/intern/file.h3
-rw-r--r--include/ruby/internal/intern/hash.h14
-rw-r--r--include/ruby/internal/intern/io.h2
-rw-r--r--include/ruby/internal/intern/load.h37
-rw-r--r--include/ruby/internal/intern/object.h6
-rw-r--r--include/ruby/internal/intern/proc.h12
-rw-r--r--include/ruby/internal/intern/process.h11
-rw-r--r--include/ruby/internal/intern/select.h4
-rw-r--r--include/ruby/internal/intern/select/win32.h4
-rw-r--r--include/ruby/internal/intern/set.h111
-rw-r--r--include/ruby/internal/intern/signal.h2
-rw-r--r--include/ruby/internal/intern/string.h25
-rw-r--r--include/ruby/internal/intern/struct.h8
-rw-r--r--include/ruby/internal/intern/thread.h8
-rw-r--r--include/ruby/internal/intern/vm.h10
-rw-r--r--include/ruby/internal/interpreter.h2
-rw-r--r--include/ruby/internal/iterator.h45
-rw-r--r--include/ruby/internal/memory.h147
-rw-r--r--include/ruby/internal/module.h16
-rw-r--r--include/ruby/internal/newobj.h87
-rw-r--r--include/ruby/internal/scan_args.h2
-rw-r--r--include/ruby/internal/special_consts.h8
-rw-r--r--include/ruby/internal/static_assert.h5
-rw-r--r--include/ruby/internal/stdbool.h16
-rw-r--r--include/ruby/internal/stdckdint.h68
-rw-r--r--include/ruby/internal/symbol.h75
-rw-r--r--include/ruby/internal/value_type.h13
-rw-r--r--include/ruby/internal/warning_push.h2
-rw-r--r--include/ruby/internal/xmalloc.h104
-rw-r--r--include/ruby/io.h311
-rw-r--r--include/ruby/io/buffer.h28
-rw-r--r--include/ruby/memory_view.h4
-rw-r--r--include/ruby/onigmo.h13
-rw-r--r--include/ruby/ractor.h16
-rw-r--r--include/ruby/random.h4
-rw-r--r--include/ruby/ruby.h139
-rw-r--r--include/ruby/st.h4
-rw-r--r--include/ruby/thread.h120
-rw-r--r--include/ruby/util.h4
-rw-r--r--include/ruby/version.h4
-rw-r--r--include/ruby/vm.h7
-rw-r--r--include/ruby/win32.h52
90 files changed, 2296 insertions, 1262 deletions
diff --git a/include/ruby/assert.h b/include/ruby/assert.h
index 0c052363bc..acc5e5bbfc 100644
--- a/include/ruby/assert.h
+++ b/include/ruby/assert.h
@@ -22,6 +22,7 @@
*/
#include "ruby/internal/assume.h"
#include "ruby/internal/attr/cold.h"
+#include "ruby/internal/attr/format.h"
#include "ruby/internal/attr/noreturn.h"
#include "ruby/internal/cast.h"
#include "ruby/internal/dllexport.h"
@@ -132,6 +133,11 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NORETURN()
RBIMPL_ATTR_COLD()
void rb_assert_failure(const char *file, int line, const char *name, const char *expr);
+
+RBIMPL_ATTR_NORETURN()
+RBIMPL_ATTR_COLD()
+RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 5, 6)
+void rb_assert_failure_detail(const char *file, int line, const char *name, const char *expr, const char *fmt, ...);
RBIMPL_SYMBOL_EXPORT_END()
#ifdef RUBY_FUNCTION_NAME_STRING
@@ -147,8 +153,28 @@ RBIMPL_SYMBOL_EXPORT_END()
*
* @param mesg The message to display.
*/
-#define RUBY_ASSERT_FAIL(mesg) \
+#if defined(HAVE___VA_OPT__)
+# if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments")
+/* __VA_OPT__ is to be used for the zero variadic macro arguments
+ * cases. */
+RBIMPL_WARNING_IGNORED(-Wgnu-zero-variadic-macro-arguments)
+# endif
+# define RBIMPL_VA_OPT_ARGS(...) __VA_OPT__(,) __VA_ARGS__
+
+# define RUBY_ASSERT_FAIL(mesg, ...) \
+ rb_assert_failure##__VA_OPT__(_detail)( \
+ __FILE__, __LINE__, RBIMPL_ASSERT_FUNC, mesg RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
+#elif !defined(__cplusplus)
+# define RBIMPL_VA_OPT_ARGS(...)
+
+# define RUBY_ASSERT_FAIL(mesg, ...) \
rb_assert_failure(__FILE__, __LINE__, RBIMPL_ASSERT_FUNC, mesg)
+#else
+# undef RBIMPL_VA_OPT_ARGS
+
+# define RUBY_ASSERT_FAIL(mesg) \
+ rb_assert_failure(__FILE__, __LINE__, RBIMPL_ASSERT_FUNC, mesg)
+#endif
/**
* Asserts that the expression is truthy. If not aborts with the message.
@@ -156,15 +182,25 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param expr What supposedly evaluates to true.
* @param mesg The message to display on failure.
*/
-#define RUBY_ASSERT_MESG(expr, mesg) \
+#if defined(RBIMPL_VA_OPT_ARGS)
+# define RUBY_ASSERT_MESG(expr, ...) \
+ (RB_LIKELY(expr) ? RBIMPL_ASSERT_NOTHING : RUBY_ASSERT_FAIL(__VA_ARGS__))
+#else
+# define RUBY_ASSERT_MESG(expr, mesg) \
(RB_LIKELY(expr) ? RBIMPL_ASSERT_NOTHING : RUBY_ASSERT_FAIL(mesg))
+#endif
/**
* A variant of #RUBY_ASSERT that does not interface with #RUBY_DEBUG.
*
* @copydetails #RUBY_ASSERT
*/
-#define RUBY_ASSERT_ALWAYS(expr) RUBY_ASSERT_MESG((expr), #expr)
+#if defined(RBIMPL_VA_OPT_ARGS)
+# define RUBY_ASSERT_ALWAYS(expr, ...) \
+ RUBY_ASSERT_MESG(expr, #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
+#else
+# define RUBY_ASSERT_ALWAYS(expr) RUBY_ASSERT_MESG((expr), #expr)
+#endif
/**
* Asserts that the given expression is truthy if and only if #RUBY_DEBUG is truthy.
@@ -172,9 +208,18 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param expr What supposedly evaluates to true.
*/
#if RUBY_DEBUG
-# define RUBY_ASSERT(expr) RUBY_ASSERT_MESG((expr), #expr)
+# if defined(RBIMPL_VA_OPT_ARGS)
+# define RUBY_ASSERT(expr, ...) \
+ RUBY_ASSERT_MESG((expr), #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
+# else
+# define RUBY_ASSERT(expr) RUBY_ASSERT_MESG((expr), #expr)
+# endif
#else
-# define RUBY_ASSERT(expr) RBIMPL_ASSERT_NOTHING
+# if defined(RBIMPL_VA_OPT_ARGS)
+# define RUBY_ASSERT(/* expr, */...) RBIMPL_ASSERT_NOTHING
+# else
+# define RUBY_ASSERT(expr) RBIMPL_ASSERT_NOTHING
+# endif
#endif
/**
@@ -187,9 +232,18 @@ RBIMPL_SYMBOL_EXPORT_END()
/* Currently `RUBY_DEBUG == ! defined(NDEBUG)` is always true. There is no
* difference any longer between this one and `RUBY_ASSERT`. */
#if defined(NDEBUG)
-# define RUBY_ASSERT_NDEBUG(expr) RBIMPL_ASSERT_NOTHING
+# if defined(RBIMPL_VA_OPT_ARGS)
+# define RUBY_ASSERT_NDEBUG(/* expr, */...) RBIMPL_ASSERT_NOTHING
+# else
+# define RUBY_ASSERT_NDEBUG(expr) RBIMPL_ASSERT_NOTHING
+# endif
#else
-# define RUBY_ASSERT_NDEBUG(expr) RUBY_ASSERT_MESG((expr), #expr)
+# if defined(RBIMPL_VA_OPT_ARGS)
+# define RUBY_ASSERT_NDEBUG(expr, ...) \
+ RUBY_ASSERT_MESG((expr), #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
+# else
+# define RUBY_ASSERT_NDEBUG(expr) RUBY_ASSERT_MESG((expr), #expr)
+# endif
#endif
/**
@@ -197,10 +251,20 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param mesg The message to display on failure.
*/
#if RUBY_DEBUG
-# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) RUBY_ASSERT_MESG((expr), (mesg))
+# if defined(RBIMPL_VA_OPT_ARGS)
+# define RUBY_ASSERT_MESG_WHEN(cond, /* expr, */...) \
+ RUBY_ASSERT_MESG(__VA_ARGS__)
+# else
+# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) RUBY_ASSERT_MESG((expr), (mesg))
+# endif
#else
-# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) \
+# if defined(RBIMPL_VA_OPT_ARGS)
+# define RUBY_ASSERT_MESG_WHEN(cond, expr, ...) \
+ ((cond) ? RUBY_ASSERT_MESG((expr), __VA_ARGS__) : RBIMPL_ASSERT_NOTHING)
+# else
+# define RUBY_ASSERT_MESG_WHEN(cond, expr, mesg) \
((cond) ? RUBY_ASSERT_MESG((expr), (mesg)) : RBIMPL_ASSERT_NOTHING)
+# endif
#endif
/**
@@ -210,7 +274,23 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param cond Extra condition that shall hold for assertion to take effect.
* @param expr What supposedly evaluates to true.
*/
-#define RUBY_ASSERT_WHEN(cond, expr) RUBY_ASSERT_MESG_WHEN((cond), (expr), #expr)
+#if defined(RBIMPL_VA_OPT_ARGS)
+# define RUBY_ASSERT_WHEN(cond, expr, ...) \
+ RUBY_ASSERT_MESG_WHEN(cond, expr, #expr RBIMPL_VA_OPT_ARGS(__VA_ARGS__))
+#else
+# define RUBY_ASSERT_WHEN(cond, expr) RUBY_ASSERT_MESG_WHEN((cond), (expr), #expr)
+#endif
+
+/**
+ * A variant of #RUBY_ASSERT that asserts when either #RUBY_DEBUG or built-in
+ * type of `obj` is `type`.
+ *
+ * @param obj Object to check its built-in typue.
+ * @param type Built-in type constant, T_ARRAY, T_STRING, etc.
+ */
+#define RUBY_ASSERT_BUILTIN_TYPE(obj, type) \
+ RUBY_ASSERT(RB_TYPE_P(obj, type), \
+ "Actual type is %s", rb_builtin_type_name(BUILTIN_TYPE(obj)))
/**
* This is either #RUBY_ASSERT or #RBIMPL_ASSUME, depending on #RUBY_DEBUG.
@@ -218,17 +298,19 @@ RBIMPL_SYMBOL_EXPORT_END()
* @copydetails #RUBY_ASSERT
*/
#if RUBY_DEBUG
-# define RBIMPL_ASSERT_OR_ASSUME(expr) RUBY_ASSERT_ALWAYS(expr)
+# define RBIMPL_ASSERT_OR_ASSUME RUBY_ASSERT_ALWAYS
+#elif ! defined(RBIMPL_VA_OPT_ARGS)
+# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSUME(expr)
#elif RBIMPL_COMPILER_BEFORE(Clang, 7, 0, 0)
# /* See commit 67d259c5dccd31fe49d417fec169977712ffdf10 */
-# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSERT_NOTHING
+# define RBIMPL_ASSERT_OR_ASSUME(...) RBIMPL_ASSERT_NOTHING
#elif defined(RUBY_ASSERT_NOASSUME)
# /* See commit d300a734414ef6de7e8eb563b7cc4389c455ed08 */
-# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSERT_NOTHING
+# define RBIMPL_ASSERT_OR_ASSUME(...) RBIMPL_ASSERT_NOTHING
#elif ! defined(RBIMPL_HAVE___ASSUME)
-# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSERT_NOTHING
+# define RBIMPL_ASSERT_OR_ASSUME(...) RBIMPL_ASSERT_NOTHING
#else
-# define RBIMPL_ASSERT_OR_ASSUME(expr) RBIMPL_ASSUME(expr)
+# define RBIMPL_ASSERT_OR_ASSUME(expr, ...) RBIMPL_ASSUME(expr)
#endif
#endif /* RUBY_ASSERT_H */
diff --git a/include/ruby/atomic.h b/include/ruby/atomic.h
index 3eb80fbf7d..fcc48f532c 100644
--- a/include/ruby/atomic.h
+++ b/include/ruby/atomic.h
@@ -34,7 +34,7 @@
# include <sys/types.h> /* ssize_t */
#endif
-#if RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+#if RBIMPL_COMPILER_IS(MSVC)
# pragma intrinsic(_InterlockedOr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
# include <atomic.h>
@@ -72,13 +72,40 @@ typedef unsigned int rb_atomic_t;
#elif defined(HAVE_GCC_SYNC_BUILTINS)
typedef unsigned int rb_atomic_t;
#elif defined(_WIN32)
+# include <winsock2.h> // to prevent macro redefinitions
+# include <windows.h> // for `LONG` and `Interlocked` functions
typedef LONG rb_atomic_t;
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
typedef unsigned int rb_atomic_t;
+#elif defined(HAVE_STDATOMIC_H)
+# include <stdatomic.h>
+typedef unsigned int rb_atomic_t;
#else
# error No atomic operation found
#endif
+/* Memory ordering constants */
+#if defined(HAVE_GCC_ATOMIC_BUILTINS)
+# define RBIMPL_ATOMIC_RELAXED __ATOMIC_RELAXED
+# define RBIMPL_ATOMIC_ACQUIRE __ATOMIC_ACQUIRE
+# define RBIMPL_ATOMIC_RELEASE __ATOMIC_RELEASE
+# define RBIMPL_ATOMIC_ACQ_REL __ATOMIC_ACQ_REL
+# define RBIMPL_ATOMIC_SEQ_CST __ATOMIC_SEQ_CST
+#elif defined(HAVE_STDATOMIC_H)
+# define RBIMPL_ATOMIC_RELAXED memory_order_relaxed
+# define RBIMPL_ATOMIC_ACQUIRE memory_order_acquire
+# define RBIMPL_ATOMIC_RELEASE memory_order_release
+# define RBIMPL_ATOMIC_ACQ_REL memory_order_acq_rel
+# define RBIMPL_ATOMIC_SEQ_CST memory_order_seq_cst
+#else
+/* Dummy values for unsupported platforms */
+# define RBIMPL_ATOMIC_RELAXED 0
+# define RBIMPL_ATOMIC_ACQUIRE 1
+# define RBIMPL_ATOMIC_RELEASE 2
+# define RBIMPL_ATOMIC_ACQ_REL 3
+# define RBIMPL_ATOMIC_SEQ_CST 4
+#endif
+
/**
* Atomically replaces the value pointed by `var` with the result of addition
* of `val` to the old value of `var`.
@@ -88,7 +115,7 @@ typedef unsigned int rb_atomic_t;
* @return What was stored in `var` before the addition.
* @post `var` holds `var + val`.
*/
-#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val))
+#define RUBY_ATOMIC_FETCH_ADD(var, val) rbimpl_atomic_fetch_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically replaces the value pointed by `var` with the result of
@@ -99,7 +126,7 @@ typedef unsigned int rb_atomic_t;
* @return What was stored in `var` before the subtraction.
* @post `var` holds `var - val`.
*/
-#define RUBY_ATOMIC_FETCH_SUB(var, val) rbimpl_atomic_fetch_sub(&(var), (val))
+#define RUBY_ATOMIC_FETCH_SUB(var, val) rbimpl_atomic_fetch_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically replaces the value pointed by `var` with the result of
@@ -111,7 +138,7 @@ typedef unsigned int rb_atomic_t;
* @post `var` holds `var | val`.
* @note For portability, this macro can return void.
*/
-#define RUBY_ATOMIC_OR(var, val) rbimpl_atomic_or(&(var), (val))
+#define RUBY_ATOMIC_OR(var, val) rbimpl_atomic_or(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically replaces the value pointed by `var` with `val`. This is just an
@@ -122,7 +149,7 @@ typedef unsigned int rb_atomic_t;
* @return What was stored in `var` before the assignment.
* @post `var` holds `val`.
*/
-#define RUBY_ATOMIC_EXCHANGE(var, val) rbimpl_atomic_exchange(&(var), (val))
+#define RUBY_ATOMIC_EXCHANGE(var, val) rbimpl_atomic_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomic compare-and-swap. This stores `val` to `var` if and only if the
@@ -136,7 +163,16 @@ typedef unsigned int rb_atomic_t;
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_CAS(var, oldval, newval) \
- rbimpl_atomic_cas(&(var), (oldval), (newval))
+ rbimpl_atomic_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)
+
+/**
+ * Atomic load. This loads `var` with an atomic intrinsic and returns
+ * its value.
+ *
+ * @param var A variable of ::rb_atomic_t
+ * @return What was stored in `var`j
+ */
+#define RUBY_ATOMIC_LOAD(var) rbimpl_atomic_load(&(var), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except for the return type.
@@ -146,7 +182,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `val`.
*/
-#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_set(&(var), (val))
+#define RUBY_ATOMIC_SET(var, val) rbimpl_atomic_store(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_FETCH_ADD, except for the return type.
@@ -156,7 +192,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var + val`.
*/
-#define RUBY_ATOMIC_ADD(var, val) rbimpl_atomic_add(&(var), (val))
+#define RUBY_ATOMIC_ADD(var, val) rbimpl_atomic_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_FETCH_SUB, except for the return type.
@@ -166,7 +202,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var - val`.
*/
-#define RUBY_ATOMIC_SUB(var, val) rbimpl_atomic_sub(&(var), (val))
+#define RUBY_ATOMIC_SUB(var, val) rbimpl_atomic_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically increments the value pointed by `var`.
@@ -175,7 +211,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var + 1`.
*/
-#define RUBY_ATOMIC_INC(var) rbimpl_atomic_inc(&(var))
+#define RUBY_ATOMIC_INC(var) rbimpl_atomic_inc(&(var), RBIMPL_ATOMIC_SEQ_CST)
/**
* Atomically decrements the value pointed by `var`.
@@ -184,7 +220,19 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var - 1`.
*/
-#define RUBY_ATOMIC_DEC(var) rbimpl_atomic_dec(&(var))
+#define RUBY_ATOMIC_DEC(var) rbimpl_atomic_dec(&(var), RBIMPL_ATOMIC_SEQ_CST)
+
+/**
+ * Identical to #RUBY_ATOMIC_FETCH_ADD, except it expects its arguments to be `size_t`.
+ * There are cases where ::rb_atomic_t is 32bit while `size_t` is 64bit. This
+ * should be used for size related operations to support such platforms.
+ *
+ * @param var A variable of `size_t`.
+ * @param val Value to add.
+ * @return What was stored in `var` before the addition.
+ * @post `var` holds `var + val`.
+ */
+#define RUBY_ATOMIC_SIZE_FETCH_ADD(var, val) rbimpl_atomic_size_fetch_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_INC, except it expects its argument is `size_t`.
@@ -195,7 +243,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var + 1`.
*/
-#define RUBY_ATOMIC_SIZE_INC(var) rbimpl_atomic_size_inc(&(var))
+#define RUBY_ATOMIC_SIZE_INC(var) rbimpl_atomic_size_inc(&(var), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_DEC, except it expects its argument is `size_t`.
@@ -206,7 +254,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var - 1`.
*/
-#define RUBY_ATOMIC_SIZE_DEC(var) rbimpl_atomic_size_dec(&(var))
+#define RUBY_ATOMIC_SIZE_DEC(var) rbimpl_atomic_size_dec(&(var), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
@@ -220,7 +268,7 @@ typedef unsigned int rb_atomic_t;
* @post `var` holds `val`.
*/
#define RUBY_ATOMIC_SIZE_EXCHANGE(var, val) \
- rbimpl_atomic_size_exchange(&(var), (val))
+ rbimpl_atomic_size_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `size_t`.
@@ -234,7 +282,7 @@ typedef unsigned int rb_atomic_t;
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_SIZE_CAS(var, oldval, newval) \
- rbimpl_atomic_size_cas(&(var), (oldval), (newval))
+ rbimpl_atomic_size_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_ADD, except it expects its arguments are `size_t`.
@@ -246,7 +294,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var + val`.
*/
-#define RUBY_ATOMIC_SIZE_ADD(var, val) rbimpl_atomic_size_add(&(var), (val))
+#define RUBY_ATOMIC_SIZE_ADD(var, val) rbimpl_atomic_size_add(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_SUB, except it expects its arguments are `size_t`.
@@ -258,7 +306,7 @@ typedef unsigned int rb_atomic_t;
* @return void
* @post `var` holds `var - val`.
*/
-#define RUBY_ATOMIC_SIZE_SUB(var, val) rbimpl_atomic_size_sub(&(var), (val))
+#define RUBY_ATOMIC_SIZE_SUB(var, val) rbimpl_atomic_size_sub(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
@@ -277,7 +325,31 @@ typedef unsigned int rb_atomic_t;
* some pointers, most notably function pointers.
*/
#define RUBY_ATOMIC_PTR_EXCHANGE(var, val) \
- RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val))
+ RBIMPL_CAST(rbimpl_atomic_ptr_exchange((void **)&(var), (void *)val, RBIMPL_ATOMIC_SEQ_CST))
+
+/**
+ * Identical to #RUBY_ATOMIC_LOAD, except it expects its arguments are `void*`.
+ * There are cases where ::rb_atomic_t is 32bit while `void*` is 64bit. This
+ * should be used for size related operations to support such platforms.
+ *
+ * @param var A variable of `void*`
+ * @return The value of `var` (without tearing)
+ */
+#define RUBY_ATOMIC_PTR_LOAD(var) \
+ RBIMPL_CAST(rbimpl_atomic_ptr_load((void **)&var, RBIMPL_ATOMIC_SEQ_CST))
+
+/**
+* Identical to #RUBY_ATOMIC_SET, except it expects its arguments are
+* `void*`. There are cases where ::rb_atomic_t is 32bit while ::VALUE is
+* 64bit. This should be used for pointer related operations to support such
+* platforms.
+*
+* @param var A variable of `void*`.
+* @param val Value to set.
+* @post `var` holds `val`.
+*/
+#define RUBY_ATOMIC_PTR_SET(var, val) \
+ rbimpl_atomic_ptr_store((volatile void **)&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are `void*`.
@@ -291,7 +363,20 @@ typedef unsigned int rb_atomic_t;
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_PTR_CAS(var, oldval, newval) \
- RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (oldval), (newval)))
+ RBIMPL_CAST(rbimpl_atomic_ptr_cas((void **)&(var), (void *)(oldval), (void *)(newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST))
+
+/**
+ * Identical to #RUBY_ATOMIC_SET, except it expects its arguments are
+ * ::VALUE. There are cases where ::rb_atomic_t is 32bit while ::VALUE is
+ * 64bit. This should be used for pointer related operations to support such
+ * platforms.
+ *
+ * @param var A variable of ::VALUE.
+ * @param val Value to set.
+ * @post `var` holds `val`.
+ */
+#define RUBY_ATOMIC_VALUE_SET(var, val) \
+ rbimpl_atomic_value_store(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_EXCHANGE, except it expects its arguments are
@@ -305,7 +390,7 @@ typedef unsigned int rb_atomic_t;
* @post `var` holds `val`.
*/
#define RUBY_ATOMIC_VALUE_EXCHANGE(var, val) \
- rbimpl_atomic_value_exchange(&(var), (val))
+ rbimpl_atomic_value_exchange(&(var), (val), RBIMPL_ATOMIC_SEQ_CST)
/**
* Identical to #RUBY_ATOMIC_CAS, except it expects its arguments are ::VALUE.
@@ -319,19 +404,20 @@ typedef unsigned int rb_atomic_t;
* @retval otherwise Something else is at `var`; not updated.
*/
#define RUBY_ATOMIC_VALUE_CAS(var, oldval, newval) \
- rbimpl_atomic_value_cas(&(var), (oldval), (newval))
+ rbimpl_atomic_value_cas(&(var), (oldval), (newval), RBIMPL_ATOMIC_SEQ_CST, RBIMPL_ATOMIC_SEQ_CST)
/** @cond INTERNAL_MACRO */
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
-rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_fetch_add(ptr, val, __ATOMIC_SEQ_CST);
+ return __atomic_fetch_add(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_fetch_and_add(ptr, val);
@@ -348,6 +434,47 @@ rbimpl_atomic_fetch_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
return atomic_add_int_nv(ptr, val) - val;
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_fetch_add_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
+#else
+# error Unsupported platform.
+#endif
+}
+
+/** @cond INTERNAL_MACRO */
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
+static inline size_t
+rbimpl_atomic_size_fetch_add(volatile size_t *ptr, size_t val, int memory_order)
+{
+ (void)memory_order;
+#if 0
+
+#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+ return __atomic_fetch_add(ptr, val, memory_order);
+
+#elif defined(HAVE_GCC_SYNC_BUILTINS)
+ return __sync_fetch_and_add(ptr, val);
+
+#elif defined(_WIN32)
+ return InterlockedExchangeAdd64(ptr, val);
+
+#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
+ /* Ditto for `atomic_add_int_nv`. */
+ RBIMPL_ASSERT_OR_ASSUME(val <= LONG_MAX);
+ atomic_add_long(ptr, val);
+
+#elif defined(__sun) && defined(HAVE_ATOMIC_H)
+ RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
+
+ volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
+ rbimpl_atomic_fetch_add(tmp, val, memory_order);
+
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_fetch_add_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -357,8 +484,9 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
@@ -367,7 +495,7 @@ rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
* return value is not used, then compiles it into single `LOCK ADD`
* instruction.
*/
- __atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_add_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_add_and_fetch(ptr, val);
@@ -385,6 +513,9 @@ rbimpl_atomic_add(volatile rb_atomic_t *ptr, rb_atomic_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
atomic_add_int(ptr, val);
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_fetch_add_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -394,17 +525,18 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_size_add(volatile size_t *ptr, size_t val)
+rbimpl_atomic_size_add(volatile size_t *ptr, size_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_add_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_add_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_add_and_fetch(ptr, val);
-#elif defined(_WIN32) && defined(_M_AMD64)
+#elif defined(_WIN64)
/* Ditto for `InterlockeExchangedAdd`. */
InterlockedExchangeAdd64(ptr, val);
@@ -413,12 +545,17 @@ rbimpl_atomic_size_add(volatile size_t *ptr, size_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= LONG_MAX);
atomic_add_long(ptr, val);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
- rbimpl_atomic_add(tmp, val);
+ rbimpl_atomic_add(tmp, val, memory_order);
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_fetch_add_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
+
+#else
+# error Unsupported platform.
#endif
}
@@ -426,12 +563,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_inc(volatile rb_atomic_t *ptr)
+rbimpl_atomic_inc(volatile rb_atomic_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
- rbimpl_atomic_add(ptr, 1);
+ rbimpl_atomic_add(ptr, 1, memory_order);
#elif defined(_WIN32)
InterlockedIncrement(ptr);
@@ -439,9 +577,11 @@ rbimpl_atomic_inc(volatile rb_atomic_t *ptr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_inc_uint(ptr);
-#else
- rbimpl_atomic_add(ptr, 1);
+#elif defined(HAVE_STDATOMIC_H)
+ rbimpl_atomic_add(ptr, 1, memory_order);
+#else
+# error Unsupported platform.
#endif
}
@@ -449,22 +589,30 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_size_inc(volatile size_t *ptr)
+rbimpl_atomic_size_inc(volatile size_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
- rbimpl_atomic_size_add(ptr, 1);
+ rbimpl_atomic_size_add(ptr, 1, memory_order);
-#elif defined(_WIN32) && defined(_M_AMD64)
+#elif defined(_WIN64)
InterlockedIncrement64(ptr);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
atomic_inc_ulong(ptr);
-#else
- rbimpl_atomic_size_add(ptr, 1);
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
+ RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
+
+ rbimpl_atomic_size_add(ptr, 1, memory_order);
+#elif defined(HAVE_STDATOMIC_H)
+ rbimpl_atomic_size_add(ptr, 1, memory_order);
+
+#else
+# error Unsupported platform.
#endif
}
@@ -472,12 +620,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
-rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_fetch_sub(ptr, val, __ATOMIC_SEQ_CST);
+ return __atomic_fetch_sub(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_fetch_and_sub(ptr, val);
@@ -492,6 +641,9 @@ rbimpl_atomic_fetch_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
return atomic_add_int_nv(ptr, neg * val) + val;
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_fetch_sub_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -501,12 +653,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_sub_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_sub_and_fetch(ptr, val);
@@ -519,6 +672,9 @@ rbimpl_atomic_sub(volatile rb_atomic_t *ptr, rb_atomic_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= INT_MAX);
atomic_add_int(ptr, neg * val);
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_fetch_sub_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -528,17 +684,18 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val)
+rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_sub_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_sub_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_sub_and_fetch(ptr, val);
-#elif defined(_WIN32) && defined(_M_AMD64)
+#elif defined(_WIN64)
const ssize_t neg = -1;
InterlockedExchangeAdd64(ptr, neg * val);
@@ -547,12 +704,17 @@ rbimpl_atomic_size_sub(volatile size_t *ptr, size_t val)
RBIMPL_ASSERT_OR_ASSUME(val <= LONG_MAX);
atomic_add_long(ptr, neg * val);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_rb_atomic_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
- rbimpl_atomic_sub(tmp, val);
+ rbimpl_atomic_sub(tmp, val, memory_order);
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_fetch_sub_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
+
+#else
+# error Unsupported platform.
#endif
}
@@ -560,12 +722,13 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_dec(volatile rb_atomic_t *ptr)
+rbimpl_atomic_dec(volatile rb_atomic_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
- rbimpl_atomic_sub(ptr, 1);
+ rbimpl_atomic_sub(ptr, 1, memory_order);
#elif defined(_WIN32)
InterlockedDecrement(ptr);
@@ -573,9 +736,11 @@ rbimpl_atomic_dec(volatile rb_atomic_t *ptr)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_dec_uint(ptr);
-#else
- rbimpl_atomic_sub(ptr, 1);
+#elif defined(HAVE_STDATOMIC_H)
+ rbimpl_atomic_sub(ptr, 1, memory_order);
+#else
+# error Unsupported platform.
#endif
}
@@ -583,22 +748,30 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_size_dec(volatile size_t *ptr)
+rbimpl_atomic_size_dec(volatile size_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS) || defined(HAVE_GCC_SYNC_BUILTINS)
- rbimpl_atomic_size_sub(ptr, 1);
+ rbimpl_atomic_size_sub(ptr, 1, memory_order);
-#elif defined(_WIN32) && defined(_M_AMD64)
+#elif defined(_WIN64)
InterlockedDecrement64(ptr);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
atomic_dec_ulong(ptr);
-#else
- rbimpl_atomic_size_sub(ptr, 1);
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
+ RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
+
+ rbimpl_atomic_size_sub(ptr, 1, memory_order);
+#elif defined(HAVE_STDATOMIC_H)
+ rbimpl_atomic_size_sub(ptr, 1, memory_order);
+
+#else
+# error Unsupported platform.
#endif
}
@@ -606,59 +779,42 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_or(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_or_fetch(ptr, val, __ATOMIC_SEQ_CST);
+ __atomic_or_fetch(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
__sync_or_and_fetch(ptr, val);
-#elif RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
_InterlockedOr(ptr, val);
-#elif defined(_WIN32) && defined(__GNUC__)
- /* This was for old MinGW. Maybe not needed any longer? */
- __asm__(
- "lock\n\t"
- "orl\t%1, %0"
- : "=m"(ptr)
- : "Ir"(val));
-
-#elif defined(_WIN32) && defined(_M_IX86)
- __asm mov eax, ptr;
- __asm mov ecx, val;
- __asm lock or [eax], ecx;
-
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
atomic_or_uint(ptr, val);
+#elif !defined(_WIN32) && defined(HAVE_STDATOMIC_H)
+ atomic_fetch_or_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
}
-/* Nobody uses this but for theoretical backwards compatibility... */
-#if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
-static inline rb_atomic_t
-rb_w32_atomic_or(volatile rb_atomic_t *var, rb_atomic_t val)
-{
- return rbimpl_atomic_or(var, val);
-}
-#endif
-
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
-rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST);
+ return __atomic_exchange_n(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_lock_test_and_set(ptr, val);
@@ -669,6 +825,9 @@ rbimpl_atomic_exchange(volatile rb_atomic_t *ptr, rb_atomic_t val)
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
return atomic_swap_uint(ptr, val);
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_exchange_explicit((_Atomic volatile rb_atomic_t *)ptr, val, memory_order);
+
#else
# error Unsupported platform.
#endif
@@ -678,29 +837,53 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline size_t
-rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val)
+rbimpl_atomic_size_exchange(volatile size_t *ptr, size_t val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- return __atomic_exchange_n(ptr, val, __ATOMIC_SEQ_CST);
+ return __atomic_exchange_n(ptr, val, memory_order);
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_lock_test_and_set(ptr, val);
-#elif defined(_WIN32) && defined(_M_AMD64)
+#elif defined(_WIN64)
return InterlockedExchange64(ptr, val);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
return atomic_swap_ulong(ptr, val);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *const tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
- const rb_atomic_t ret = rbimpl_atomic_exchange(tmp, val);
+ const rb_atomic_t ret = rbimpl_atomic_exchange(tmp, val, memory_order);
return RBIMPL_CAST((size_t)ret);
+#elif defined(HAVE_STDATOMIC_H)
+ return atomic_exchange_explicit((_Atomic volatile size_t *)ptr, val, memory_order);
+
+#else
+# error Unsupported platform.
+#endif
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
+static inline void
+rbimpl_atomic_size_store(volatile size_t *ptr, size_t val, int memory_order)
+{
+ (void)memory_order;
+#if 0
+
+#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+ __atomic_store_n(ptr, val, memory_order);
+
+#else
+ rbimpl_atomic_size_exchange(ptr, val, memory_order);
+
#endif
}
@@ -708,8 +891,9 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void *
-rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val)
+rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(InterlockedExchangePointer)
@@ -726,7 +910,7 @@ rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val)
const size_t sval = RBIMPL_CAST((size_t)val);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
- const size_t sret = rbimpl_atomic_size_exchange(sptr, sval);
+ const size_t sret = rbimpl_atomic_size_exchange(sptr, sval, memory_order);
return RBIMPL_CAST((void *)sret);
#endif
@@ -735,14 +919,27 @@ rbimpl_atomic_ptr_exchange(void *volatile *ptr, const void *val)
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
+static inline void
+rbimpl_atomic_ptr_store(volatile void **ptr, void *val, int memory_order)
+{
+ RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
+
+ const size_t sval = RBIMPL_CAST((size_t)val);
+ volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
+ rbimpl_atomic_size_store(sptr, sval, memory_order);
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
static inline VALUE
-rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val)
+rbimpl_atomic_value_exchange(volatile VALUE *ptr, VALUE val, int memory_order)
{
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
const size_t sval = RBIMPL_CAST((size_t)val);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
- const size_t sret = rbimpl_atomic_size_exchange(sptr, sval);
+ const size_t sret = rbimpl_atomic_size_exchange(sptr, sval, memory_order);
return RBIMPL_CAST((VALUE)sret);
}
@@ -750,16 +947,46 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void
-rbimpl_atomic_set(volatile rb_atomic_t *ptr, rb_atomic_t val)
+rbimpl_atomic_value_store(volatile VALUE *ptr, VALUE val, int memory_order)
+{
+ RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
+
+ const size_t sval = RBIMPL_CAST((size_t)val);
+ volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
+ rbimpl_atomic_size_store(sptr, sval, memory_order);
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
+static inline rb_atomic_t
+rbimpl_atomic_load(volatile rb_atomic_t *ptr, int memory_order)
{
+ (void)memory_order;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
- __atomic_store_n(ptr, val, __ATOMIC_SEQ_CST);
+ return __atomic_load_n(ptr, memory_order);
+#else
+ return rbimpl_atomic_fetch_add(ptr, 0, memory_order);
+#endif
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
+static inline void
+rbimpl_atomic_store(volatile rb_atomic_t *ptr, rb_atomic_t val, int memory_order)
+{
+ (void)memory_order;
+#if 0
+
+#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+ __atomic_store_n(ptr, val, memory_order);
#else
/* Maybe std::atomic<rb_atomic_t>::store can be faster? */
- rbimpl_atomic_exchange(ptr, val);
+ rbimpl_atomic_exchange(ptr, val, memory_order);
#endif
}
@@ -768,73 +995,73 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline rb_atomic_t
-rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t newval)
+rbimpl_atomic_cas(volatile rb_atomic_t *ptr, rb_atomic_t oldval, rb_atomic_t newval, int success_memorder, int failure_memorder)
{
+ (void)success_memorder;
+ (void)failure_memorder;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_compare_exchange_n(
- ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ ptr, &oldval, newval, 0, success_memorder, failure_memorder);
return oldval;
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_val_compare_and_swap(ptr, oldval, newval);
-#elif RBIMPL_COMPILER_SINCE(MSVC, 13, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
return InterlockedCompareExchange(ptr, newval, oldval);
-#elif defined(_WIN32)
- PVOID *pptr = RBIMPL_CAST((PVOID *)ptr);
- PVOID pold = RBIMPL_CAST((PVOID)oldval);
- PVOID pnew = RBIMPL_CAST((PVOID)newval);
- PVOID pret = InterlockedCompareExchange(pptr, pnew, pold);
- return RBIMPL_CAST((rb_atomic_t)pret);
-
#elif defined(__sun) && defined(HAVE_ATOMIC_H)
return atomic_cas_uint(ptr, oldval, newval);
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_compare_exchange_strong_explicit(
+ (_Atomic volatile rb_atomic_t *)ptr, &oldval, newval, success_memorder, failure_memorder);
+ return oldval;
+
#else
# error Unsupported platform.
#endif
}
-/* Nobody uses this but for theoretical backwards compatibility... */
-#if RBIMPL_COMPILER_BEFORE(MSVC, 13, 0, 0)
-static inline rb_atomic_t
-rb_w32_atomic_cas(volatile rb_atomic_t *var, rb_atomic_t oldval, rb_atomic_t newval)
-{
- return rbimpl_atomic_cas(var, oldval, newval);
-}
-#endif
-
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline size_t
-rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval)
+rbimpl_atomic_size_cas(volatile size_t *ptr, size_t oldval, size_t newval, int success_memorder, int failure_memorder)
{
+ (void)success_memorder;
+ (void)failure_memorder;
#if 0
#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
__atomic_compare_exchange_n(
- ptr, &oldval, newval, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ ptr, &oldval, newval, 0, success_memorder, failure_memorder);
return oldval;
#elif defined(HAVE_GCC_SYNC_BUILTINS)
return __sync_val_compare_and_swap(ptr, oldval, newval);
-#elif defined(_WIN32) && defined(_M_AMD64)
+#elif defined(_WIN64)
return InterlockedCompareExchange64(ptr, newval, oldval);
#elif defined(__sun) && defined(HAVE_ATOMIC_H) && (defined(_LP64) || defined(_I32LPx))
return atomic_cas_ulong(ptr, oldval, newval);
-#else
+#elif defined(_WIN32) || (defined(__sun) && defined(HAVE_ATOMIC_H))
RBIMPL_STATIC_ASSERT(size_of_size_t, sizeof *ptr == sizeof(rb_atomic_t));
volatile rb_atomic_t *tmp = RBIMPL_CAST((volatile rb_atomic_t *)ptr);
- return rbimpl_atomic_cas(tmp, oldval, newval);
+ return rbimpl_atomic_cas(tmp, oldval, newval, success_memorder, failure_memorder);
+
+#elif defined(HAVE_STDATOMIC_H)
+ atomic_compare_exchange_strong_explicit(
+ (_Atomic volatile size_t *)ptr, &oldval, newval, success_memorder, failure_memorder);
+ return oldval;
+#else
+# error Unsupported platform.
#endif
}
@@ -842,8 +1069,10 @@ RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
static inline void *
-rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
+rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval, int success_memorder, int failure_memorder)
{
+ (void)success_memorder;
+ (void)failure_memorder;
#if 0
#elif defined(InterlockedExchangePointer)
@@ -866,7 +1095,7 @@ rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
const size_t snew = RBIMPL_CAST((size_t)newval);
const size_t sold = RBIMPL_CAST((size_t)oldval);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
- const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew);
+ const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew, success_memorder, failure_memorder);
return RBIMPL_CAST((void *)sret);
#endif
@@ -875,15 +1104,41 @@ rbimpl_atomic_ptr_cas(void **ptr, const void *oldval, const void *newval)
RBIMPL_ATTR_ARTIFICIAL()
RBIMPL_ATTR_NOALIAS()
RBIMPL_ATTR_NONNULL((1))
+static inline void *
+rbimpl_atomic_ptr_load(void **ptr, int memory_order)
+{
+ (void)memory_order;
+#if 0
+
+#elif defined(HAVE_GCC_ATOMIC_BUILTINS)
+ return __atomic_load_n(ptr, memory_order);
+#else
+ void *val = *ptr;
+ return rbimpl_atomic_ptr_cas(ptr, val, val, memory_order, memory_order);
+#endif
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
+static inline VALUE
+rbimpl_atomic_value_load(volatile VALUE *ptr, int memory_order)
+{
+ return RBIMPL_CAST((VALUE)rbimpl_atomic_ptr_load((void **)ptr, memory_order));
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NOALIAS()
+RBIMPL_ATTR_NONNULL((1))
static inline VALUE
-rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval)
+rbimpl_atomic_value_cas(volatile VALUE *ptr, VALUE oldval, VALUE newval, int success_memorder, int failure_memorder)
{
RBIMPL_STATIC_ASSERT(sizeof_value, sizeof *ptr == sizeof(size_t));
const size_t snew = RBIMPL_CAST((size_t)newval);
const size_t sold = RBIMPL_CAST((size_t)oldval);
volatile size_t *const sptr = RBIMPL_CAST((volatile size_t *)ptr);
- const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew);
+ const size_t sret = rbimpl_atomic_size_cas(sptr, sold, snew, success_memorder, failure_memorder);
return RBIMPL_CAST((VALUE)sret);
}
/** @endcond */
diff --git a/include/ruby/backward.h b/include/ruby/backward.h
index f804c2c36e..6726102158 100644
--- a/include/ruby/backward.h
+++ b/include/ruby/backward.h
@@ -11,12 +11,6 @@
#include "ruby/internal/interpreter.h"
#include "ruby/backward/2/attributes.h"
-#define RBIMPL_ATTR_DEPRECATED_SINCE(ver) RBIMPL_ATTR_DEPRECATED(("since " #ver))
-#define RBIMPL_ATTR_DEPRECATED_INTERNAL(ver) RBIMPL_ATTR_DEPRECATED(("since "#ver", also internal"))
-#define RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() RBIMPL_ATTR_DEPRECATED(("only for internal use"))
-
-RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() void rb_clear_constant_cache(void);
-
/* from version.c */
#if defined(RUBY_SHOW_COPYRIGHT_TO_DIE) && !!(RUBY_SHOW_COPYRIGHT_TO_DIE+0)
# error RUBY_SHOW_COPYRIGHT_TO_DIE is deprecated
diff --git a/include/ruby/backward/2/rmodule.h b/include/ruby/backward/2/rmodule.h
index 53b37831c0..76c0936462 100644
--- a/include/ruby/backward/2/rmodule.h
+++ b/include/ruby/backward/2/rmodule.h
@@ -23,7 +23,7 @@
* who is implementing the internals) could have used those macros for a while.
* Kept public as-is here to keep some theoretical backwards compatibility.
*/
-#define RMODULE_IV_TBL(m) RCLASS_IV_TBL(m)
+#define RMODULE_IV_TBL(m) RCLASS_FIELDS(m)
#define RMODULE_CONST_TBL(m) RCLASS_CONST_TBL(m)
#define RMODULE_M_TBL(m) RCLASS_M_TBL(m)
#define RMODULE_SUPER(m) RCLASS_SUPER(m)
diff --git a/include/ruby/backward/cxxanyargs.hpp b/include/ruby/backward/cxxanyargs.hpp
index 2414b7ae6d..0ca2745c20 100644
--- a/include/ruby/backward/cxxanyargs.hpp
+++ b/include/ruby/backward/cxxanyargs.hpp
@@ -190,33 +190,6 @@ rb_define_hooked_variable(const char *q, VALUE *w, std::nullptr_t e, void_type *
/// @name Exceptions and tag jumps
/// @{
-// RUBY_CXX_DEPRECATED("by rb_block_call since 1.9")
-RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
-/// @brief Old way to implement iterators.
-/// @param[in] q A function that can yield.
-/// @param[in] w Passed to `q`.
-/// @param[in] e What is to be yielded.
-/// @param[in] r Passed to `e`.
-/// @return The return value of `q`.
-/// @note `e` can be nullptr.
-/// @deprecated This function is obsoleted since long before 2.x era. Do not
-/// use it any longer. rb_block_call() is provided instead.
-inline VALUE
-rb_iterate(onearg_type *q, VALUE w, type *e, VALUE r)
-{
- rb_block_call_func_t t = reinterpret_cast<rb_block_call_func_t>(e);
- return backward::rb_iterate_deprecated(q, w, t, r);
-}
-
-#ifdef HAVE_NULLPTR
-RUBY_CXX_DEPRECATED("by rb_block_call since 1.9")
-inline VALUE
-rb_iterate(onearg_type *q, VALUE w, std::nullptr_t e, VALUE r)
-{
- return backward::rb_iterate_deprecated(q, w, e, r);
-}
-#endif
-
RUBY_CXX_DEPRECATED("Use of ANYARGS in this function is deprecated")
/// @brief Call a method with a block.
/// @param[in] q The self.
@@ -537,9 +510,7 @@ struct driver {
* this writing the version is 2.8. Let's warn this later, some time
* during 3.x. Hopefully codes in old (ANYARGS-ed) format should be
* less than now. */
-#if (RUBY_API_VERSION_MAJOR * 100 + RUBY_API_VERSION_MINOR) >= 301
RUBY_CXX_DEPRECATED("use of ANYARGS is deprecated")
-#endif
/// @copydoc define(VALUE klass, T mid, U func)
/// @deprecated Pass correctly typed function instead.
static inline void
diff --git a/include/ruby/debug.h b/include/ruby/debug.h
index f95acdb17e..547d5d94c4 100644
--- a/include/ruby/debug.h
+++ b/include/ruby/debug.h
@@ -10,6 +10,7 @@
* modify this file, provided that the conditions mentioned in the
* file COPYING are met. Consult the file for details.
*/
+#include "ruby/internal/attr/deprecated.h"
#include "ruby/internal/attr/nonnull.h"
#include "ruby/internal/attr/returns_nonnull.h"
#include "ruby/internal/dllexport.h"
@@ -51,6 +52,25 @@ RBIMPL_ATTR_NONNULL((3))
int rb_profile_frames(int start, int limit, VALUE *buff, int *lines);
/**
+ * Queries mysterious "frame"s of the given range.
+ *
+ * A per-thread version of rb_profile_frames().
+ * Arguments and return values are the same with rb_profile_frames() with the
+ * exception of the first argument _thread_, which accepts the Thread to be
+ * profiled/queried.
+ *
+ * @param[in] thread The Ruby Thread to be profiled.
+ * @param[in] start Start position (0 means the topmost).
+ * @param[in] limit Number objects of `buff`.
+ * @param[out] buff Return buffer.
+ * @param[out] lines Return buffer.
+ * @return Number of objects filled into `buff`.
+ * @post `buff` is filled with backtrace pointers.
+ * @post `lines` is filled with `__LINE__` of each backtraces.
+ */
+int rb_profile_thread_frames(VALUE thread, int start, int limit, VALUE *buff, int *lines);
+
+/**
* Queries the path of the passed backtrace.
*
* @param[in] frame What rb_profile_frames() returned.
@@ -277,7 +297,7 @@ VALUE rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index)
#define RB_DEBUG_INSPECTOR_FRAME_DEPTH(dc, index) rb_debug_inspector_frame_depth(dc, index)
/**
- * Return current frmae depth.
+ * Return current frame depth.
*
* @retval The depth of the current frame in Integer.
*/
@@ -459,7 +479,7 @@ RBIMPL_ATTR_RETURNS_NONNULL()
*/
rb_trace_arg_t *rb_tracearg_from_tracepoint(VALUE tpval);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Queries the event of the passed trace.
*
@@ -468,7 +488,7 @@ RBIMPL_ATTR_NONNULL(())
*/
rb_event_flag_t rb_tracearg_event_flag(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Identical to rb_tracearg_event_flag(), except it returns the name of the
* event in Ruby's symbol.
@@ -478,7 +498,7 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_event(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Queries the line of the point where the trace is at.
*
@@ -488,7 +508,7 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_lineno(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Queries the file name of the point where the trace is at.
*
@@ -498,7 +518,19 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_path(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
+/**
+ *
+ * Queries the parameters passed on a call or return event.
+ *
+ * @param[in] trace_arg A trace instance
+ * @exception rb_eRuntimeError The tracing event does not support querying parameters.
+ * @return Array of parameters in the format of `Method#parameters`.
+ *
+ */
+VALUE rb_tracearg_parameters(rb_trace_arg_t *trace_arg);
+
+RBIMPL_ATTR_NONNULL((1))
/**
* Queries the method name of the point where the trace is at.
*
@@ -508,7 +540,7 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_method_id(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Identical to rb_tracearg_method_id(), except it returns callee id like
* rb_frame_callee().
@@ -519,7 +551,7 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_callee_id(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Queries the class that defines the method that the passed trace is at. This
* can be different from the class of rb_tracearg_self()'s return value because
@@ -531,7 +563,7 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_defined_class(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Creates a binding object of the point where the trace is at.
*
@@ -546,7 +578,7 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_binding(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Queries the receiver of the point trace is at.
*
@@ -555,7 +587,7 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_self(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Queries the return value that the trace represents.
*
@@ -565,7 +597,7 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_return_value(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
/**
* Queries the raised exception that the trace represents.
*
@@ -575,7 +607,33 @@ RBIMPL_ATTR_NONNULL(())
*/
VALUE rb_tracearg_raised_exception(rb_trace_arg_t *trace_arg);
-RBIMPL_ATTR_NONNULL(())
+RBIMPL_ATTR_NONNULL((1))
+/**
+ * Queries the compiled source code of the 'script_compiled' event.
+ * If loaded from a file, it will return nil.
+ *
+ * @param[in] trace_arg A trace instance
+ * @exception rb_eRuntimeError The tracing event is not 'script_compiled'.
+ * @retval RUBY_Qnil The script was loaded from a file.
+ * @retval otherwise The compiled source code.
+ *
+ */
+VALUE rb_tracearg_eval_script(rb_trace_arg_t *trace_arg);
+
+RBIMPL_ATTR_NONNULL((1))
+/**
+ *
+ * Queries the compiled instruction sequence on a 'script_compiled' event.
+ * Note that this method is MRI specific.
+ *
+ * @param[in] trace_arg A trace instance
+ * @exception rb_eRuntimeError The tracing event is not 'script_compiled'.
+ * @return The `RubyVM::InstructionSequence` object representing the instruction sequence.
+ *
+ */
+VALUE rb_tracearg_instruction_sequence(rb_trace_arg_t *trace_arg);
+
+RBIMPL_ATTR_NONNULL((1))
/**
* Queries the allocated/deallocated object that the trace represents.
*
@@ -596,48 +654,157 @@ VALUE rb_tracearg_object(rb_trace_arg_t *trace_arg);
/*
* Postponed Job API
- * rb_postponed_job_register and rb_postponed_job_register_one are
- * async-signal-safe and used via SIGPROF by the "stackprof" RubyGem
+ *
+ * This API is designed to be called from contexts where it is not safe to run Ruby
+ * code (e.g. because they do not hold the GVL or because GC is in progress), and
+ * defer a callback to run in a context where it _is_ safe. The primary intended
+ * users of this API is for sampling profilers like the "stackprof" gem; these work
+ * by scheduling the periodic delivery of a SIGPROF signal, and inside the C-level
+ * signal handler, deferring a job to collect a Ruby backtrace when it is next safe
+ * to do so.
+ *
+ * Ruby maintains a small, fixed-size postponed job table. An extension using this
+ * API should first call `rb_postponed_job_preregister` to register a callback
+ * function in this table and obtain a handle of type `rb_postponed_job_handle_t`
+ * to it. Subsequently, the callback can be triggered by calling
+ * `rb_postponed_job_trigger` with that handle, or the `data` associated with the
+ * callback function can be changed by calling `rb_postponed_job_preregister` again.
+ *
+ * Because the postponed job table is quite small (it only has 32 entries on most
+ * common systems), extensions should generally only preregister one or two `func`
+ * values.
+ *
+ * Historically, this API provided two functions `rb_postponed_job_register` and
+ * `rb_postponed_job_register_one`, which claimed to be fully async-signal-safe and
+ * would call back the provided `func` and `data` at an appropriate time. However,
+ * these functions were subject to race conditions which could cause crashes when
+ * racing with Ruby's internal use of them. These two functions are still present,
+ * but are marked as deprecated and have slightly changed semantics:
+ *
+ * * rb_postponed_job_register now works like rb_postponed_job_register_one i.e.
+ * `func` will only be executed at most one time each time Ruby checks for
+ * interrupts, no matter how many times it is registered
+ * * They are also called with the last `data` to be registered, not the first
+ * (which is how rb_postponed_job_register_one previously worked)
*/
+
/**
* Type of postponed jobs.
*
- * @param[in,out] arg What was passed to rb_postponed_job_register().
+ * @param[in,out] arg What was passed to `rb_postponed_job_preregister`
*/
typedef void (*rb_postponed_job_func_t)(void *arg);
/**
- * Registers a postponed job.
+ * The type of a handle returned from `rb_postponed_job_preregister` and
+ * passed to `rb_postponed_job_trigger`
+ */
+typedef unsigned int rb_postponed_job_handle_t;
+#define POSTPONED_JOB_HANDLE_INVALID ((rb_postponed_job_handle_t)UINT_MAX)
+
+/**
+ * Pre-registers a func in Ruby's postponed job preregistration table,
+ * returning an opaque handle which can be used to trigger the job later. Generally,
+ * this function will be called during the initialization routine of an extension.
+ *
+ * The returned handle can be used later to call `rb_postponed_job_trigger`. This will
+ * cause Ruby to call back into the registered `func` with `data` at a later time, in
+ * a context where the GVL is held and it is safe to perform Ruby allocations.
+ *
+ * If the given `func` was already pre-registered, this function will overwrite the
+ * stored data with the newly passed data, and return the same handle instance as
+ * was previously returned.
+ *
+ * If this function is called concurrently with the same `func`, then the stored data
+ * could be the value from either call (but will definitely be one of them).
+ *
+ * If this function is called to update the data concurrently with a call to
+ * `rb_postponed_job_trigger` on the same handle, it's undefined whether `func` will
+ * be called with the old data or the new data.
+ *
+ * Although the current implementation of this function is in fact async-signal-safe and
+ * has defined semantics when called concurrently on the same `func`, a future Ruby
+ * version might require that this method be called under the GVL; thus, programs which
+ * aim to be forward-compatible should call this method whilst holding the GVL.
+ *
+ * @param[in] flags Unused and ignored
+ * @param[in] func The function to be pre-registered
+ * @param[in] data The data to be pre-registered
+ * @retval POSTPONED_JOB_HANDLE_INVALID The job table is full; this registration
+ * did not succeed and no further registration will do so for
+ * the lifetime of the program.
+ * @retval otherwise A handle which can be passed to `rb_postponed_job_trigger`
+ */
+rb_postponed_job_handle_t rb_postponed_job_preregister(unsigned int flags, rb_postponed_job_func_t func, void *data);
+
+/**
+ * Triggers a pre-registered job registered with rb_postponed_job_preregister,
+ * scheduling it for execution the next time the Ruby VM checks for interrupts.
+ * The context in which the job is called in holds the GVL and is safe to perform
+ * Ruby allocations within (i.e. it is not during GC).
+ *
+ * This method is async-signal-safe and can be called from any thread, at any
+ * time, including in signal handlers.
+ *
+ * If this method is called multiple times, Ruby will coalesce this into only
+ * one call to the job the next time it checks for interrupts.
+ *
+ * @params[in] h A handle returned from rb_postponed_job_preregister
+ */
+void rb_postponed_job_trigger(rb_postponed_job_handle_t h);
+
+/**
+ * Schedules the given `func` to be called with `data` when Ruby next checks for
+ * interrupts. If this function is called multiple times in between Ruby checking
+ * for interrupts, then `func` will be called only once with the `data` value from
+ * the first call to this function.
*
- * There are situations when running a ruby program is not possible. For
- * instance when a program is in a signal handler; for another instance when
- * the GC is busy. On such situations however, there might be needs to do
- * something. We cannot but defer such operations until we are 100% sure it is
- * safe to execute them. This mechanism is called postponed jobs. This
- * function registers a new one. The registered job would eventually gets
- * executed.
+ * Like `rb_postponed_job_trigger`, the context in which the job is called
+ * holds the GVL and can allocate Ruby objects.
*
- * @param[in] flags (Unused) reserved for future extensions.
+ * This method essentially has the same semantics as:
+ *
+ * ```
+ * rb_postponed_job_trigger(rb_postponed_job_preregister(func, data));
+ * ```
+ *
+ * @note Previous versions of Ruby promised that the (`func`, `data`) pairs would
+ * be executed as many times as they were registered with this function; in
+ * reality this was always subject to race conditions and this function no
+ * longer provides this guarantee. Instead, multiple calls to this function
+ * can be coalesced into a single execution of the passed `func`, with the
+ * most recent `data` registered at that time passed in.
+ *
+ * @deprecated This interface implies that arbitrarily many `func`'s can be enqueued
+ * over the lifetime of the program, whilst in reality the registration
+ * slots for postponed jobs are a finite resource. This is made clearer
+ * by the `rb_postponed_job_preregister` and `rb_postponed_job_trigger`
+ * functions, and a future version of Ruby might delete this function.
+ *
+ * @param[in] flags Unused and ignored.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
- * @retval 0 Postponed job buffer is full. Failed.
- * @retval otherwise Opaque return value.
- * @post The passed job is postponed.
+ * @retval 0 Postponed job registration table is full. Failed.
+ * @retval 1 Registration succeeded.
+ * @post The passed job will run on the next interrupt check.
*/
+ RBIMPL_ATTR_DEPRECATED(("use rb_postponed_job_preregister and rb_postponed_job_trigger"))
int rb_postponed_job_register(unsigned int flags, rb_postponed_job_func_t func, void *data);
/**
- * Identical to rb_postponed_job_register_one(), except it additionally checks
- * for duplicated registration. In case the passed job is already in the
- * postponed job buffer this function does nothing.
+ * Identical to `rb_postponed_job_register`
+ *
+ * @deprecated This is deprecated for the same reason as `rb_postponed_job_register`
*
- * @param[in] flags (Unused) reserved for future extensions.
+ * @param[in] flags Unused and ignored.
* @param[in] func Job body.
* @param[in,out] data Passed as-is to `func`.
- * @retval 0 Postponed job buffer is full. Failed.
- * @retval otherwise Opaque return value.
+ * @retval 0 Postponed job registration table is full. Failed.
+ * @retval 1 Registration succeeded.
+ * @post The passed job will run on the next interrupt check.
*/
+ RBIMPL_ATTR_DEPRECATED(("use rb_postponed_job_preregister and rb_postponed_job_trigger"))
int rb_postponed_job_register_one(unsigned int flags, rb_postponed_job_func_t func, void *data);
/** @} */
diff --git a/include/ruby/fiber/scheduler.h b/include/ruby/fiber/scheduler.h
index ad3d2d7483..4d764f68ae 100644
--- a/include/ruby/fiber/scheduler.h
+++ b/include/ruby/fiber/scheduler.h
@@ -23,9 +23,11 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
-#define RUBY_FIBER_SCHEDULER_VERSION 2
+// Version 3: Adds support for `fiber_interrupt`.
+#define RUBY_FIBER_SCHEDULER_VERSION 3
struct timeval;
+struct rb_thread_struct;
/**
* Wrap a `ssize_t` and `int errno` into a single `VALUE`. This interface should
@@ -97,7 +99,7 @@ VALUE rb_fiber_scheduler_get(void);
* current thread will call scheduler's `#close` method on finalisation
* (allowing the scheduler to properly manage all non-finished fibers).
* `scheduler` can be an object of any class corresponding to
- * `Fiber::SchedulerInterface`. Its implementation is up to the user.
+ * `Fiber::Scheduler` interface. Its implementation is up to the user.
*
* @param[in] scheduler The scheduler to set.
* @exception rb_eArgError `scheduler` does not conform the interface.
@@ -117,7 +119,7 @@ VALUE rb_fiber_scheduler_current(void);
/**
* Identical to rb_fiber_scheduler_current(), except it queries for that of the
- * passed thread instead of the implicit current one.
+ * passed thread value instead of the implicit current one.
*
* @param[in] thread Target thread.
* @exception rb_eTypeError `thread` is not a thread.
@@ -127,6 +129,17 @@ VALUE rb_fiber_scheduler_current(void);
VALUE rb_fiber_scheduler_current_for_thread(VALUE thread);
/**
+ * Identical to rb_fiber_scheduler_current_for_thread(), except it expects
+ * a threadptr instead of a thread value.
+ *
+ * @param[in] thread Target thread.
+ * @exception rb_eTypeError `thread` is not a thread.
+ * @retval RUBY_Qnil No scheduler is in effect in `thread`.
+ * @retval otherwise The scheduler that is in effect in `thread`.
+ */
+VALUE rb_fiber_scheduler_current_for_threadptr(struct rb_thread_struct *thread);
+
+/**
* Converts the passed timeout to an expression that rb_fiber_scheduler_block()
* etc. expects.
*
@@ -166,6 +179,14 @@ VALUE rb_fiber_scheduler_kernel_sleep(VALUE scheduler, VALUE duration);
*/
VALUE rb_fiber_scheduler_kernel_sleepv(VALUE scheduler, int argc, VALUE * argv);
+/**
+ * Yield to the scheduler, to be resumed on the next scheduling cycle.
+ *
+ * @param[in] scheduler Target scheduler.
+ * @return What `scheduler.yield` returns.
+ */
+VALUE rb_fiber_scheduler_yield(VALUE scheduler);
+
/* Description TBW */
#if 0
VALUE rb_fiber_scheduler_timeout_after(VALUE scheduler, VALUE timeout, VALUE exception, VALUE message);
@@ -199,6 +220,8 @@ VALUE rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout);
/**
* Wakes up a fiber previously blocked using rb_fiber_scheduler_block().
*
+ * This function may be called from a different thread.
+ *
* @param[in] scheduler Target scheduler.
* @param[in] blocker What was awaited for.
* @param[in] fiber What to unblock.
@@ -391,9 +414,89 @@ VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io);
*/
VALUE rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname);
+// The state of the blocking operation execution.
+struct rb_fiber_scheduler_blocking_operation_state {
+ void *result;
+ int saved_errno;
+};
+
+// The opaque handle for the blocking operation.
+typedef struct rb_fiber_scheduler_blocking_operation rb_fiber_scheduler_blocking_operation_t;
+
+/**
+ * Extract the blocking operation handle from a BlockingOperationRuby object.
+ *
+ * This function safely extracts the opaque handle from a BlockingOperation VALUE
+ * while holding the GVL. The returned pointer can be passed to worker threads
+ * and used with rb_fiber_scheduler_blocking_operation_execute.
+ *
+ * @param[in] self The BlockingOperation VALUE to extract from
+ * @return The opaque struct pointer on success, NULL on error
+ * @note Experimental.
+ */
+rb_fiber_scheduler_blocking_operation_t *rb_fiber_scheduler_blocking_operation_extract(VALUE self);
+
+/**
+ * Execute blocking operation from handle (GVL not required).
+ *
+ * This function executes a blocking operation using the opaque handle
+ * obtained from rb_fiber_scheduler_blocking_operation_extract.
+ * It can be called from native threads without holding the GVL.
+ *
+ * @param[in] blocking_operation The opaque handle.
+ * @return 0 on success, -1 on error.
+ * @note Experimental. Can be called from any thread without holding the GVL
+ */
+int rb_fiber_scheduler_blocking_operation_execute(rb_fiber_scheduler_blocking_operation_t *blocking_operation);
+
+/**
+ * Cancel a blocking operation.
+ *
+ * This function cancels a blocking operation. If the operation is queued,
+ * it just marks it as cancelled. If it's executing, it marks it as cancelled
+ * and calls the unblock function to interrupt the operation.
+ *
+ * @param blocking_operation The opaque struct pointer
+ * @return 1 if unblock function was called, 0 if just marked cancelled, -1 on error
+ * @note Experimental.
+ */
+int rb_fiber_scheduler_blocking_operation_cancel(rb_fiber_scheduler_blocking_operation_t *blocking_operation);
+
+/**
+ * Defer the execution of the passed function to the scheduler.
+ *
+ * @param[in] scheduler Target scheduler.
+ * @param[in] function The function to run.
+ * @param[in] data The data to pass to the function.
+ * @param[in] unblock_function The unblock function to use to interrupt the operation.
+ * @param[in] data2 The data to pass to the unblock function.
+ * @param[in] flags Flags passed to `rb_nogvl`.
+ * @param[out] state The result and errno of the operation.
+ * @retval RUBY_Qundef `scheduler` doesn't have `#blocking_operation_wait`.
+ * @return otherwise What `scheduler.blocking_operation_wait` returns.
+ */
+VALUE rb_fiber_scheduler_blocking_operation_wait(VALUE scheduler, void* (*function)(void *), void *data, rb_unblock_function_t *unblock_function, void *data2, int flags, struct rb_fiber_scheduler_blocking_operation_state *state);
+
+/**
+ * Interrupt a fiber by raising an exception. You can construct an exception using `rb_make_exception`.
+ *
+ * This hook may be invoked by a different thread.
+ *
+ * @param[in] scheduler Target scheduler.
+ * @param[in] fiber The fiber to interrupt.
+ * @param[in] exception The exception to raise in the fiber.
+ * @return What `scheduler.fiber_interrupt` returns.
+ */
+VALUE rb_fiber_scheduler_fiber_interrupt(VALUE scheduler, VALUE fiber, VALUE exception);
+
/**
* Create and schedule a non-blocking fiber.
*
+ * @param[in] scheduler Target scheduler.
+ * @param[in] argc Number of arguments in argv.
+ * @param[in] argv Array of arguments to pass to the fiber.
+ * @param[in] kw_splat Whether to expand last argument as keywords.
+ * @return The created and scheduled fiber.
*/
VALUE rb_fiber_scheduler_fiber(VALUE scheduler, int argc, VALUE *argv, int kw_splat);
diff --git a/include/ruby/intern.h b/include/ruby/intern.h
index 48e4cd546e..8718169ce2 100644
--- a/include/ruby/intern.h
+++ b/include/ruby/intern.h
@@ -51,6 +51,7 @@
#include "ruby/internal/intern/re.h"
#include "ruby/internal/intern/ruby.h"
#include "ruby/internal/intern/select.h"
+#include "ruby/internal/intern/set.h"
#include "ruby/internal/intern/signal.h"
#include "ruby/internal/intern/sprintf.h"
#include "ruby/internal/intern/string.h"
diff --git a/include/ruby/internal/abi.h b/include/ruby/internal/abi.h
index 8e1bbf3951..e6d1fa7e8f 100644
--- a/include/ruby/internal/abi.h
+++ b/include/ruby/internal/abi.h
@@ -24,7 +24,7 @@
* In released versions of Ruby, this number is not defined since teeny
* versions of Ruby should guarantee ABI compatibility.
*/
-#define RUBY_ABI_VERSION 0
+#define RUBY_ABI_VERSION 1
/* Windows does not support weak symbols so ruby_abi_version will not exist
* in the shared library. */
@@ -33,7 +33,7 @@
#endif
#endif /* RUBY_ABI_VERSION */
-#ifdef RUBY_DLN_CHECK_ABI
+#if defined(RUBY_DLN_CHECK_ABI) && !defined(RUBY_EXPORT)
# ifdef __cplusplus
extern "C" {
diff --git a/include/ruby/internal/anyargs.h b/include/ruby/internal/anyargs.h
index e3e1b6166d..e4c6d155cc 100644
--- a/include/ruby/internal/anyargs.h
+++ b/include/ruby/internal/anyargs.h
@@ -84,12 +84,15 @@
#elif defined(_WIN32) || defined(__CYGWIN__)
# /* Skip due to [Bug #16134] */
+# define RBIMPL_CAST_FN_PTR 1
#elif ! RBIMPL_HAS_ATTRIBUTE(transparent_union)
# /* :TODO: improve here, please find a way to support. */
+# define RBIMPL_CAST_FN_PTR 1
#elif ! defined(HAVE_VA_ARGS_MACRO)
# /* :TODO: improve here, please find a way to support. */
+# define RBIMPL_CAST_FN_PTR 1
#else
# /** @cond INTERNAL_MACRO */
@@ -348,6 +351,25 @@ RBIMPL_ANYARGS_DECL(rb_define_method, VALUE, const char *)
#endif /* __cplusplus */
+#if defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus)
+/* In C23, K&R style prototypes are gone and so `void foo(ANYARGS)` became
+ * equivalent to `void foo(void)` unlike in earlier versions. This is a problem
+ * for rb_define_* functions since that makes all valid functions one can pass
+ * trip -Wincompatible-pointer-types, which we treat as errors. This is mostly
+ * not a problem for the __builtin_choose_expr path, but outside of that we
+ * need to add a cast for compatibility.
+ */
+#define rb_define_method(klass, mid, func, arity) rb_define_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_method_id(klass, mid, func, arity) rb_define_method_id((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_singleton_method(obj, mid, func, arity) rb_define_singleton_method((obj), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_protected_method(klass, mid, func, arity) rb_define_protected_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_private_method(klass, mid, func, arity) rb_define_private_method((klass), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_module_function(mod, mid, func, arity) rb_define_module_function((mod), (mid), (VALUE (*)(ANYARGS))(func), (arity))
+#define rb_define_global_function(mid, func, arity) rb_define_global_function((mid), (VALUE (*)(ANYARGS))(func), (arity))
+
+#undef RBIMPL_CAST_FN_PTR
+#endif /* defined(RBIMPL_CAST_FN_PTR) && !defined(__cplusplus) */
+
/**
* This macro is to properly cast a function parameter of *_define_method
* family. It has been around since 1.x era so you can maximise backwards
diff --git a/include/ruby/internal/arithmetic/int.h b/include/ruby/internal/arithmetic/int.h
index 6bd8ec2184..7b24d16887 100644
--- a/include/ruby/internal/arithmetic/int.h
+++ b/include/ruby/internal/arithmetic/int.h
@@ -254,7 +254,7 @@ static inline VALUE
rb_uint2num_inline(unsigned int v)
{
if (RB_POSFIXABLE(v))
- return RB_LONG2FIX(v);
+ return RB_LONG2FIX(RBIMPL_CAST((long)v));
else
return rb_uint2big(v);
}
diff --git a/include/ruby/internal/arithmetic/intptr_t.h b/include/ruby/internal/arithmetic/intptr_t.h
index a354f4469c..70090f88e6 100644
--- a/include/ruby/internal/arithmetic/intptr_t.h
+++ b/include/ruby/internal/arithmetic/intptr_t.h
@@ -32,6 +32,18 @@
#define rb_int_new rb_int2inum /**< @alias{rb_int2inum} */
#define rb_uint_new rb_uint2inum /**< @alias{rb_uint2inum} */
+// These definitions are same as fiddle/conversions.h
+#if SIZEOF_VOIDP <= SIZEOF_LONG
+# define PTR2NUM(x) (LONG2NUM((long)(x)))
+# define NUM2PTR(x) ((void*)(NUM2ULONG(x)))
+#elif SIZEOF_VOIDP <= SIZEOF_LONG_LONG
+# define PTR2NUM(x) (LL2NUM((LONG_LONG)(x)))
+# define NUM2PTR(x) ((void*)(NUM2ULL(x)))
+#else
+// should have been an error in ruby/internal/value.h
+# error Need integer for VALUE
+#endif
+
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
diff --git a/include/ruby/internal/arithmetic/long.h b/include/ruby/internal/arithmetic/long.h
index 6b8fd8ffc3..6c00dbceb7 100644
--- a/include/ruby/internal/arithmetic/long.h
+++ b/include/ruby/internal/arithmetic/long.h
@@ -114,11 +114,11 @@ RB_INT2FIX(long i)
/* :NOTE: VALUE can be wider than long. As j being unsigned, 2j+1 is fully
* defined. Also it can be compiled into a single LEA instruction. */
- const unsigned long j = i;
+ const unsigned long j = RBIMPL_CAST((unsigned long)i);
const unsigned long k = (j << 1) + RUBY_FIXNUM_FLAG;
- const long l = k;
+ const long l = RBIMPL_CAST((long)k);
const SIGNED_VALUE m = l; /* Sign extend */
- const VALUE n = m;
+ const VALUE n = RBIMPL_CAST((VALUE)m);
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(n));
return n;
@@ -166,7 +166,7 @@ rbimpl_fix2long_by_idiv(VALUE x)
/* :NOTE: VALUE can be wider than long. (x-1)/2 never overflows because
* RB_FIXNUM_P(x) holds. Also it has no portability issue like y>>1
* below. */
- const SIGNED_VALUE y = x - RUBY_FIXNUM_FLAG;
+ const SIGNED_VALUE y = RBIMPL_CAST((SIGNED_VALUE)(x - RUBY_FIXNUM_FLAG));
const SIGNED_VALUE z = y / 2;
const long w = RBIMPL_CAST((long)z);
@@ -193,7 +193,7 @@ rbimpl_fix2long_by_shift(VALUE x)
/* :NOTE: VALUE can be wider than long. If right shift is arithmetic, this
* is noticeably faster than above. */
- const SIGNED_VALUE y = x;
+ const SIGNED_VALUE y = RBIMPL_CAST((SIGNED_VALUE)x);
const SIGNED_VALUE z = y >> 1;
const long w = RBIMPL_CAST((long)z);
@@ -252,7 +252,7 @@ static inline unsigned long
rb_fix2ulong(VALUE x)
{
RBIMPL_ASSERT_OR_ASSUME(RB_FIXNUM_P(x));
- return rb_fix2long(x);
+ return RBIMPL_CAST((unsigned long)rb_fix2long(x));
}
/**
@@ -323,7 +323,7 @@ static inline VALUE
rb_ulong2num_inline(unsigned long v)
{
if (RB_POSFIXABLE(v))
- return RB_LONG2FIX(v);
+ return RB_LONG2FIX(RBIMPL_CAST((long)v));
else
return rb_uint2big(v);
}
diff --git a/include/ruby/internal/arithmetic/long_long.h b/include/ruby/internal/arithmetic/long_long.h
index 65dec8729d..aab455c830 100644
--- a/include/ruby/internal/arithmetic/long_long.h
+++ b/include/ruby/internal/arithmetic/long_long.h
@@ -127,7 +127,7 @@ static inline unsigned LONG_LONG
rb_num2ull_inline(VALUE x)
{
if (RB_FIXNUM_P(x))
- return RB_FIX2LONG(x);
+ return RBIMPL_CAST((unsigned LONG_LONG)RB_FIX2LONG(x));
else
return rb_num2ull(x);
}
diff --git a/include/ruby/internal/arithmetic/st_data_t.h b/include/ruby/internal/arithmetic/st_data_t.h
index 3bff4ffc0b..91776b3fce 100644
--- a/include/ruby/internal/arithmetic/st_data_t.h
+++ b/include/ruby/internal/arithmetic/st_data_t.h
@@ -58,7 +58,7 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline VALUE
RB_ST2FIX(st_data_t i)
{
- SIGNED_VALUE x = i;
+ SIGNED_VALUE x = RBIMPL_CAST((SIGNED_VALUE)i);
if (x >= 0) {
x &= RUBY_FIXNUM_MAX;
@@ -69,7 +69,7 @@ RB_ST2FIX(st_data_t i)
RBIMPL_ASSERT_OR_ASSUME(RB_FIXABLE(x));
unsigned long y = RBIMPL_CAST((unsigned long)x);
- return RB_LONG2FIX(y);
+ return RB_LONG2FIX(RBIMPL_CAST((long)y));
}
#endif /* RBIMPL_ARITHMETIC_ST_DATA_T_H */
diff --git a/include/ruby/internal/attr/deprecated.h b/include/ruby/internal/attr/deprecated.h
index e1bbdbd15a..a374ace868 100644
--- a/include/ruby/internal/attr/deprecated.h
+++ b/include/ruby/internal/attr/deprecated.h
@@ -48,7 +48,7 @@
#elif RBIMPL_HAS_ATTRIBUTE(deprecated) /* but not with message. */
# define RBIMPL_ATTR_DEPRECATED(msg) __attribute__((__deprecated__))
-#elif RBIMPL_COMPILER_SINCE(MSVC, 14, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_DEPRECATED(msg) __declspec(deprecated msg)
#elif RBIMPL_HAS_DECLSPEC_ATTRIBUTE(deprecated)
@@ -72,4 +72,11 @@
# define RBIMPL_ATTR_DEPRECATED_EXT(msg) RBIMPL_ATTR_DEPRECATED(msg)
#endif
+#define RBIMPL_ATTR_DEPRECATED_SINCE(ver) \
+ RBIMPL_ATTR_DEPRECATED(("since " #ver))
+#define RBIMPL_ATTR_DEPRECATED_INTERNAL(ver) \
+ RBIMPL_ATTR_DEPRECATED(("since "#ver", also internal"))
+#define RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY() \
+ RBIMPL_ATTR_DEPRECATED(("only for internal use"))
+
#endif /* RBIMPL_ATTR_DEPRECATED_H */
diff --git a/include/ruby/internal/attr/forceinline.h b/include/ruby/internal/attr/forceinline.h
index b7daafede7..5b9ae794af 100644
--- a/include/ruby/internal/attr/forceinline.h
+++ b/include/ruby/internal/attr/forceinline.h
@@ -29,7 +29,7 @@
* `__forceinline` are mutually exclusive. We have to mimic that behaviour for
* non-MSVC compilers.
*/
-#if RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0)
+#if RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_FORCEINLINE() __forceinline
#elif RBIMPL_HAS_ATTRIBUTE(always_inline)
# define RBIMPL_ATTR_FORCEINLINE() __attribute__((__always_inline__)) inline
diff --git a/include/ruby/internal/attr/noexcept.h b/include/ruby/internal/attr/noexcept.h
index ea3001df2a..dd4c667407 100644
--- a/include/ruby/internal/attr/noexcept.h
+++ b/include/ruby/internal/attr/noexcept.h
@@ -54,7 +54,7 @@
* get smarter and smarter. Today they can infer if it actually throws
* or not without any annotations by humans (correct me if I'm wrong).
*
- * - When an inline function attributed `noexcepr` actually _does_ throw an
+ * - When an inline function attributed `noexcept` actually _does_ throw an
* exception: they have to call `std::terminate` then (C++ standard
* mandates so). This means exception handling routines are actually
* enforced, not omitted. This doesn't impact runtime performance (The
@@ -78,7 +78,7 @@
#elif defined(__INTEL_CXX11_MODE__)
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
-#elif RBIMPL_COMPILER_SINCE(MSVC, 19, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_NOEXCEPT(_) noexcept(noexcept(_))
#elif __cplusplus >= 201103L
diff --git a/include/ruby/internal/attr/nonstring.h b/include/ruby/internal/attr/nonstring.h
new file mode 100644
index 0000000000..5ad6ef2a86
--- /dev/null
+++ b/include/ruby/internal/attr/nonstring.h
@@ -0,0 +1,40 @@
+#ifndef RBIMPL_ATTR_NONSTRING_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_ATTR_NONSTRING_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief Defines #RBIMPL_ATTR_NONSTRING.
+ */
+#include "ruby/internal/has/attribute.h"
+
+/** Wraps (or simulates) `__attribute__((nonstring))` */
+#if RBIMPL_HAS_ATTRIBUTE(nonstring)
+# define RBIMPL_ATTR_NONSTRING() __attribute__((nonstring))
+# if RBIMPL_COMPILER_SINCE(GCC, 15, 0, 0)
+# define RBIMPL_ATTR_NONSTRING_ARRAY() RBIMPL_ATTR_NONSTRING()
+# elif RBIMPL_COMPILER_SINCE(Clang, 21, 0, 0)
+# define RBIMPL_ATTR_NONSTRING_ARRAY() RBIMPL_ATTR_NONSTRING()
+# else
+# define RBIMPL_ATTR_NONSTRING_ARRAY() /* void */
+# endif
+#else
+# define RBIMPL_ATTR_NONSTRING() /* void */
+# define RBIMPL_ATTR_NONSTRING_ARRAY() /* void */
+#endif
+
+#endif /* RBIMPL_ATTR_NONSTRING_H */
diff --git a/include/ruby/internal/attr/restrict.h b/include/ruby/internal/attr/restrict.h
index e39104138c..b12fdc9dbc 100644
--- a/include/ruby/internal/attr/restrict.h
+++ b/include/ruby/internal/attr/restrict.h
@@ -28,7 +28,7 @@
* `__has_declspec_attribute()` which involves macro substitution. */
/** Wraps (or simulates) `__declspec(restrict)` */
-#if RBIMPL_COMPILER_SINCE(MSVC, 14, 0, 0)
+#if RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_ATTR_RESTRICT() __declspec(re ## strict)
#elif RBIMPL_HAS_ATTRIBUTE(malloc)
diff --git a/include/ruby/internal/compiler_is/msvc.h b/include/ruby/internal/compiler_is/msvc.h
index 8a864ea558..824f0ecc21 100644
--- a/include/ruby/internal/compiler_is/msvc.h
+++ b/include/ruby/internal/compiler_is/msvc.h
@@ -38,19 +38,8 @@
# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_FULL_VER % 10000000 / 100000)
# define RBIMPL_COMPILER_VERSION_PATCH (_MSC_FULL_VER % 100000)
-#elif defined(_MSC_FULL_VER)
-# define RBIMPL_COMPILER_IS_MSVC 1
-# /* _MSC_FULL_VER = XXYYZZZZ */
-# define RBIMPL_COMPILER_VERSION_MAJOR (_MSC_FULL_VER / 1000000)
-# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_FULL_VER % 1000000 / 10000)
-# define RBIMPL_COMPILER_VERSION_PATCH (_MSC_FULL_VER % 10000)
-
#else
-# define RBIMPL_COMPILER_IS_MSVC 1
-# /* _MSC_VER = XXYY */
-# define RBIMPL_COMPILER_VERSION_MAJOR (_MSC_VER / 100)
-# define RBIMPL_COMPILER_VERSION_MINOR (_MSC_VER % 100)
-# define RBIMPL_COMPILER_VERSION_PATCH 0
+# error Unsupported MSVC version
#endif
#endif /* RBIMPL_COMPILER_IS_MSVC_H */
diff --git a/include/ruby/internal/config.h b/include/ruby/internal/config.h
index da070f0979..34862ded6e 100644
--- a/include/ruby/internal/config.h
+++ b/include/ruby/internal/config.h
@@ -50,7 +50,7 @@
# define HAVE_VA_ARGS_MACRO
# elif defined(__INTEL_CXX11_MODE__)
# define HAVE_VA_ARGS_MACRO
-# elif RBIMPL_COMPILER_SINCE(MSVC, 16, 0, 0)
+# elif RBIMPL_COMPILER_IS(MSVC)
# define HAVE_VA_ARGS_MACRO
# else
# /* NG, not known. */
diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h
index 90690fe794..73cc0f5dd9 100644
--- a/include/ruby/internal/core/rarray.h
+++ b/include/ruby/internal/core/rarray.h
@@ -80,6 +80,8 @@
* here is at least incomplete.
*/
enum ruby_rarray_flags {
+ /* RUBY_FL_USER0 is for ELTS_SHARED */
+
/**
* This flag has something to do with memory footprint. If the array is
* "small" enough, ruby tries to be creative to abuse padding bits of
@@ -99,8 +101,6 @@ enum ruby_rarray_flags {
*/
RARRAY_EMBED_FLAG = RUBY_FL_USER1,
- /* RUBY_FL_USER2 is for ELTS_SHARED */
-
/**
* When an array employs embedded strategy (see ::RARRAY_EMBED_FLAG), these
* bits are used to store the number of elements actually filled into
diff --git a/include/ruby/internal/core/rbasic.h b/include/ruby/internal/core/rbasic.h
index 4617f743a7..63cdff8e09 100644
--- a/include/ruby/internal/core/rbasic.h
+++ b/include/ruby/internal/core/rbasic.h
@@ -55,23 +55,27 @@ enum ruby_rvalue_flags {
RVALUE_EMBED_LEN_MAX = RBIMPL_RVALUE_EMBED_LEN_MAX
};
+#if (SIZEOF_VALUE < SIZEOF_UINT64_T)
+#define RBASIC_SHAPE_ID_FIELD 1
+#else
+#define RBASIC_SHAPE_ID_FIELD 0
+#endif
+
/**
- * Ruby's object's, base components. Every single ruby objects have them in
- * common.
+ * Ruby object's base components. All Ruby objects have them in common.
*/
struct
RUBY_ALIGNAS(SIZEOF_VALUE)
RBasic {
/**
- * Per-object flags. Each ruby objects have their own characteristics
- * apart from their classes. For instance whether an object is frozen or
- * not is not controlled by its class. This is where such properties are
- * stored.
+ * Per-object flags. Each Ruby object has its own characteristics apart
+ * from its class. For instance, whether an object is frozen or not is not
+ * controlled by its class. This is where such properties are stored.
*
* @see enum ::ruby_fl_type
*
- * @note This is ::VALUE rather than an enum for alignment purpose. Back
+ * @note This is ::VALUE rather than an enum for alignment purposes. Back
* in the 1990s there were no such thing like `_Alignas` in C.
*/
VALUE flags;
@@ -79,14 +83,18 @@ RBasic {
/**
* Class of an object. Every object has its class. Also, everything is an
* object in Ruby. This means classes are also objects. Classes have
- * their own classes, classes of classes have their classes, too ... and
- * it recursively continues forever.
+ * their own classes, classes of classes have their classes too, and it
+ * recursively continues forever.
*
- * Also note the `const` qualifier. In ruby an object cannot "change" its
+ * Also note the `const` qualifier. In Ruby, an object cannot "change" its
* class.
*/
const VALUE klass;
+#if RBASIC_SHAPE_ID_FIELD
+ VALUE shape_id;
+#endif
+
#ifdef __cplusplus
public:
RBIMPL_ATTR_CONSTEXPR(CXX11)
@@ -102,8 +110,14 @@ RBasic {
RBasic() :
flags(RBIMPL_VALUE_NULL),
klass(RBIMPL_VALUE_NULL)
+#if RBASIC_SHAPE_ID_FIELD
+ , shape_id(RBIMPL_VALUE_NULL)
+#endif
{
}
+# define RBASIC_INIT RBasic()
+#else
+# define RBASIC_INIT {RBIMPL_VALUE_NULL}
#endif
};
diff --git a/include/ruby/internal/core/rclass.h b/include/ruby/internal/core/rclass.h
index b0b6bfc80c..6f78cc569b 100644
--- a/include/ruby/internal/core/rclass.h
+++ b/include/ruby/internal/core/rclass.h
@@ -58,7 +58,7 @@ enum ruby_rmodule_flags {
* rb_mod_refine() has this flag set. This is the bit which controls
* difference between normal inclusion versus refinements.
*/
- RMODULE_IS_REFINEMENT = RUBY_FL_USER3
+ RMODULE_IS_REFINEMENT = RUBY_FL_USER1
};
struct RClass; /* Opaque, declared here for RCLASS() macro. */
diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h
index 43ab3c01e7..cee5e7b5ea 100644
--- a/include/ruby/internal/core/rdata.h
+++ b/include/ruby/internal/core/rdata.h
@@ -37,12 +37,8 @@
#include "ruby/defines.h"
/** @cond INTERNAL_MACRO */
-#ifdef RUBY_UNTYPED_DATA_WARNING
-# /* Take that. */
-#elif defined(RUBY_EXPORT)
-# define RUBY_UNTYPED_DATA_WARNING 1
-#else
-# define RUBY_UNTYPED_DATA_WARNING 0
+#ifndef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 1
#endif
#define RBIMPL_DATA_FUNC(f) RBIMPL_CAST((void (*)(void *))(f))
@@ -146,7 +142,10 @@ struct RData {
*/
RUBY_DATA_FUNC dfree;
- /** Pointer to the actual C level struct that you want to wrap. */
+ /** Pointer to the actual C level struct that you want to wrap.
+ * This is after dmark and dfree to allow DATA_PTR to continue to work for
+ * both RData and non-embedded RTypedData.
+ */
void *data;
};
@@ -181,11 +180,6 @@ VALUE rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_D
*/
VALUE rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree);
-/**
- * @private
- * Documented in include/ruby/internal/globals.h
- */
-RUBY_EXTERN VALUE rb_cObject;
RBIMPL_SYMBOL_EXPORT_END()
/**
@@ -331,15 +325,6 @@ rb_data_object_get_warning(VALUE obj)
return rb_data_object_get(obj);
}
-#if defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P)
-# define rb_data_object_wrap_warning(klass, ptr, mark, free) \
- RB_GNUC_EXTENSION( \
- __builtin_choose_expr( \
- __builtin_constant_p(klass) && !(klass), \
- rb_data_object_wrap(klass, ptr, mark, free), \
- (rb_data_object_wrap_warning)(klass, ptr, mark, free)))
-#endif
-
/**
* This is an implementation detail of #Data_Make_Struct. People don't use it
* directly.
@@ -361,14 +346,6 @@ rb_data_object_make(VALUE klass, RUBY_DATA_FUNC mark_func, RUBY_DATA_FUNC free_f
return result;
}
-RBIMPL_ATTR_DEPRECATED(("by: rb_data_object_wrap"))
-/** @deprecated This function was renamed to rb_data_object_wrap(). */
-static inline VALUE
-rb_data_object_alloc(VALUE klass, void *data, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
-{
- return rb_data_object_wrap(klass, data, dmark, dfree);
-}
-
/** @cond INTERNAL_MACRO */
#define rb_data_object_wrap_0 rb_data_object_wrap
#define rb_data_object_wrap_1 rb_data_object_wrap_warning
diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h
index c2bcae6306..99f6470ac1 100644
--- a/include/ruby/internal/core/robject.h
+++ b/include/ruby/internal/core/robject.h
@@ -42,10 +42,10 @@
*/
#define ROBJECT(obj) RBIMPL_CAST((struct RObject *)(obj))
/** @cond INTERNAL_MACRO */
-#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX
-#define ROBJECT_EMBED ROBJECT_EMBED
-#define ROBJECT_IV_CAPACITY ROBJECT_IV_CAPACITY
-#define ROBJECT_IVPTR ROBJECT_IVPTR
+#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX
+#define ROBJECT_HEAP ROBJECT_HEAP
+#define ROBJECT_FIELDS_CAPACITY ROBJECT_FIELDS_CAPACITY
+#define ROBJECT_FIELDS ROBJECT_FIELDS
/** @endcond */
/**
@@ -55,10 +55,12 @@
*/
enum ruby_robject_flags {
/**
- * This flag has something to do with memory footprint. If the object is
- * "small" enough, ruby tries to be creative to abuse padding bits of
- * struct ::RObject for storing instance variables. This flag denotes that
- * situation.
+ * This flag marks that the object's instance variables are stored in an
+ * external heap buffer.
+ * Normally, instance variable references are stored inside the object slot,
+ * but if it overflow, Ruby may have to allocate a separate buffer and spills
+ * the instance variables there.
+ * This flag denotes that situation.
*
* @warning This bit has to be considered read-only. Setting/clearing
* this bit without corresponding fix up must cause immediate
@@ -71,7 +73,7 @@ enum ruby_robject_flags {
* 3rd parties must not be aware that there even is more than one way to
* store instance variables. Might better be hidden.
*/
- ROBJECT_EMBED = RUBY_FL_USER1
+ ROBJECT_HEAP = RUBY_FL_USER4
};
struct st_table;
@@ -94,17 +96,7 @@ struct RObject {
*/
struct {
/** Pointer to a C array that holds instance variables. */
- VALUE *ivptr;
-
- /**
- * This is a table that holds instance variable name to index
- * mapping. Used when accessing instance variables using names.
- *
- * @internal
- *
- * This is a shortcut for `RCLASS_IV_INDEX_TBL(rb_obj_class(obj))`.
- */
- struct rb_id_table *iv_index_tbl;
+ VALUE *fields;
} heap;
/* Embedded instance variables. When an object is small enough, it
@@ -133,17 +125,17 @@ RBIMPL_ATTR_ARTIFICIAL()
* @shyouhei finds no reason for this to be visible from extension libraries.
*/
static inline VALUE *
-ROBJECT_IVPTR(VALUE obj)
+ROBJECT_FIELDS(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
struct RObject *const ptr = ROBJECT(obj);
- if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) {
- return ptr->as.ary;
+ if (RB_UNLIKELY(RB_FL_ANY_RAW(obj, ROBJECT_HEAP))) {
+ return ptr->as.heap.fields;
}
else {
- return ptr->as.heap.ivptr;
+ return ptr->as.ary;
}
}
diff --git a/include/ruby/internal/core/rstring.h b/include/ruby/internal/core/rstring.h
index 0bca74e688..35175ea94a 100644
--- a/include/ruby/internal/core/rstring.h
+++ b/include/ruby/internal/core/rstring.h
@@ -369,41 +369,6 @@ RSTRING_LEN(VALUE str)
return RSTRING(str)->len;
}
-RBIMPL_WARNING_PUSH()
-#if RBIMPL_COMPILER_IS(Intel)
-RBIMPL_WARNING_IGNORED(413)
-#endif
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * @private
- *
- * "Expands" an embedded string into an ordinal one. This is a function that
- * returns aggregated type. The returned struct always has its `as.heap.len`
- * an `as.heap.ptr` fields set appropriately.
- *
- * This is an implementation detail that 3rd parties should never bother.
- */
-static inline struct RString
-rbimpl_rstring_getmem(VALUE str)
-{
- RBIMPL_ASSERT_TYPE(str, RUBY_T_STRING);
-
- if (RB_FL_ANY_RAW(str, RSTRING_NOEMBED)) {
- return *RSTRING(str);
- }
- else {
- /* Expecting compilers to optimize this on-stack struct away. */
- struct RString retval;
- retval.len = RSTRING_LEN(str);
- retval.as.heap.ptr = RSTRING(str)->as.embed.ary;
- return retval;
- }
-}
-
-RBIMPL_WARNING_POP()
-
RBIMPL_ATTR_ARTIFICIAL()
/**
* Queries the contents pointer of the string.
@@ -415,7 +380,9 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline char *
RSTRING_PTR(VALUE str)
{
- char *ptr = rbimpl_rstring_getmem(str).as.heap.ptr;
+ char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ?
+ RSTRING(str)->as.heap.ptr :
+ RSTRING(str)->as.embed.ary;
if (RUBY_DEBUG && RB_UNLIKELY(! ptr)) {
/* :BEWARE: @shyouhei thinks that currently, there are rooms for this
@@ -441,14 +408,17 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline char *
RSTRING_END(VALUE str)
{
- struct RString buf = rbimpl_rstring_getmem(str);
+ char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ?
+ RSTRING(str)->as.heap.ptr :
+ RSTRING(str)->as.embed.ary;
+ long len = RSTRING_LEN(str);
- if (RUBY_DEBUG && RB_UNLIKELY(! buf.as.heap.ptr)) {
+ if (RUBY_DEBUG && RB_UNLIKELY(!ptr)) {
/* Ditto. */
rb_debug_rstring_null_ptr("RSTRING_END");
}
- return &buf.as.heap.ptr[buf.len];
+ return &ptr[len];
}
RBIMPL_ATTR_ARTIFICIAL()
@@ -477,16 +447,7 @@ RSTRING_LENINT(VALUE str)
* @param ptrvar Variable where its contents is stored.
* @param lenvar Variable where its length is stored.
*/
-#ifdef HAVE_STMT_AND_DECL_IN_EXPR
-# define RSTRING_GETMEM(str, ptrvar, lenvar) \
- __extension__ ({ \
- struct RString rbimpl_str = rbimpl_rstring_getmem(str); \
- (ptrvar) = rbimpl_str.as.heap.ptr; \
- (lenvar) = rbimpl_str.len; \
- })
-#else
# define RSTRING_GETMEM(str, ptrvar, lenvar) \
((ptrvar) = RSTRING_PTR(str), \
(lenvar) = RSTRING_LEN(str))
-#endif /* HAVE_STMT_AND_DECL_IN_EXPR */
#endif /* RBIMPL_RSTRING_H */
diff --git a/include/ruby/internal/core/rstruct.h b/include/ruby/internal/core/rstruct.h
index 69be487b59..0028a1bdcd 100644
--- a/include/ruby/internal/core/rstruct.h
+++ b/include/ruby/internal/core/rstruct.h
@@ -31,18 +31,6 @@
# include "ruby/backward.h"
#endif
-/**
- * @private
- *
- * @deprecated This macro once was a thing in the old days, but makes no sense
- * any longer today. Exists here for backwards compatibility
- * only. You can safely forget about it.
- *
- * @internal
- *
- * Declaration of rb_struct_ptr() is at include/ruby/backward.h.
- */
-#define RSTRUCT_PTR(st) rb_struct_ptr(st)
/** @cond INTERNAL_MACRO */
#define RSTRUCT_LEN RSTRUCT_LEN
#define RSTRUCT_SET RSTRUCT_SET
diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h
index c7904746fd..ec0794e387 100644
--- a/include/ruby/internal/core/rtypeddata.h
+++ b/include/ruby/internal/core/rtypeddata.h
@@ -37,6 +37,7 @@
#include "ruby/internal/dllexport.h"
#include "ruby/internal/error.h"
#include "ruby/internal/fl_type.h"
+#include "ruby/internal/static_assert.h"
#include "ruby/internal/stdbool.h"
#include "ruby/internal/value_type.h"
@@ -108,11 +109,17 @@
/** @cond INTERNAL_MACRO */
#define RTYPEDDATA_P RTYPEDDATA_P
#define RTYPEDDATA_TYPE RTYPEDDATA_TYPE
+#define TYPED_DATA_EMBEDDED ((VALUE)1)
+#define TYPED_DATA_PTR_MASK (~(TYPED_DATA_EMBEDDED))
+/** @endcond */
+
+/**
+ * Macros to see if each corresponding flag is defined.
+ */
#define RUBY_TYPED_FREE_IMMEDIATELY RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
#define RUBY_TYPED_WB_PROTECTED RUBY_TYPED_WB_PROTECTED
#define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1
-/** @endcond */
/**
* @private
@@ -137,6 +144,8 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FREE_IMMEDIATELY = 1,
+ RUBY_TYPED_EMBEDDABLE = 2,
+
/**
* This flag has something to do with Ractor. Multiple Ractors run without
* protecting each other. Sharing an object among Ractors is basically
@@ -151,6 +160,12 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FROZEN_SHAREABLE = RUBY_FL_SHAREABLE,
+ // experimental flag
+ // Similar to RUBY_TYPED_FROZEN_SHAREABLE, but doesn't make shareable
+ // reachable objects from this T_DATA object on the Ractor.make_shareable.
+ // If it refers to unshareable objects, simply raise an error.
+ // RUBY_TYPED_FROZEN_SHAREABLE_NO_REC = RUBY_FL_FINALIZE,
+
/**
* This flag has something to do with our garbage collector. These days
* ruby objects are "generational". There are those who are young and
@@ -173,9 +188,9 @@ rbimpl_typeddata_flags {
RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */
/**
- * This flag no longer in use
+ * This flag is used to distinguish RTypedData from deprecated RData objects.
*/
- RUBY_TYPED_UNUSED = RUBY_FL_UNUSED6,
+ RUBY_TYPED_FL_IS_TYPED_DATA = RUBY_FL_USERPRIV0,
/**
* This flag determines whether marking and compaction should be carried out
@@ -247,10 +262,15 @@ struct rb_data_type_struct {
RUBY_DATA_FUNC dcompact;
/**
- * This field is reserved for future extension. For now, it must be
- * filled with zeros.
+ * @internal
*/
- void *reserved[1]; /* For future extension.
+ void (*handle_weak_references)(void *);
+
+ /**
+ * This field is reserved for future extension. For now, it must be
+ * filled with zeros.
+ */
+ void *reserved[7]; /* For future extension.
This array *must* be filled with ZERO. */
} function;
@@ -348,24 +368,28 @@ struct RTypedData {
/** The part that all ruby objects have in common. */
struct RBasic basic;
+ /** Direct reference to the slots that holds instance variables, if any **/
+ VALUE fields_obj;
+
/**
+ * This is a `const rb_data_type_t *const` value, with the low bits set:
+ *
+ * 1: Set if object is embedded.
+ *
* This field stores various information about how Ruby should handle a
* data. This roughly resembles a Ruby level class (apart from method
* definition etc.)
*/
- const rb_data_type_t *const type;
-
- /**
- * This has to be always 1.
- *
- * @internal
- */
- const VALUE typed_flag;
+ const VALUE type;
/** Pointer to the actual C level struct that you want to wrap. */
void *data;
};
+#if !defined(__cplusplus) || __cplusplus >= 201103L
+RBIMPL_STATIC_ASSERT(data_in_rtypeddata, offsetof(struct RData, data) == offsetof(struct RTypedData, data));
+#endif
+
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NONNULL((3))
/**
@@ -380,6 +404,7 @@ RBIMPL_ATTR_NONNULL((3))
*/
VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type);
+RBIMPL_ATTR_NONNULL((3))
/**
* Identical to rb_data_typed_object_wrap(), except it allocates a new data
* region internally instead of taking an existing one. The allocation is done
@@ -395,6 +420,7 @@ VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *
*/
VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type);
+RBIMPL_ATTR_NONNULL(())
/**
* Checks for the domestic relationship between the two.
*
@@ -409,6 +435,7 @@ VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t
*/
int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent);
+RBIMPL_ATTR_NONNULL((2))
/**
* Checks if the given object is of given kind.
*
@@ -419,6 +446,7 @@ int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *
*/
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type);
+RBIMPL_ATTR_NONNULL((2))
/**
* Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead
* of returning false.
@@ -430,8 +458,49 @@ int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type);
* @post Upon successful return `obj`'s type is guaranteed `data_type`.
*/
void *rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type);
+
+RBIMPL_ATTR_NORETURN()
+RBIMPL_ATTR_NONNULL((2))
+/**
+ * @private
+ *
+ * Fails with the given object's type incompatibility to the type.
+ *
+ * This is an implementation detail of Check_Type. People don't use it
+ * directly.
+ *
+ * @param[in] obj The object in question.
+ * @param[in] expected Name of expected data type of `obj`.
+ */
+void rb_unexpected_object_type(VALUE obj, const char *expected);
+
+RBIMPL_ATTR_NORETURN()
+RBIMPL_ATTR_NONNULL(())
+/**
+ * @private
+ *
+ * Fails with the given object's type incompatibility to the type.
+ *
+ * This is an implementation detail of #TypedData_Make_Struct. People don't
+ * use it directly.
+ *
+ * @param[in] actual Actual data type.
+ * @param[in] expected Expected data type.
+ */
+void rb_unexpected_typeddata(const rb_data_type_t *actual, const rb_data_type_t *expected);
RBIMPL_SYMBOL_EXPORT_END()
+#if RUBY_DEBUG
+# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \
+ while (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) { \
+ rb_unexpected_object_type(obj, "Data"); \
+ unreachable; \
+ }
+#else
+# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \
+ RBIMPL_ASSERT_NOTHING
+#endif
+
/**
* Converts sval, a pointer to your struct, into a Ruby object.
*
@@ -460,14 +529,13 @@ RBIMPL_SYMBOL_EXPORT_END()
*/
#define TypedData_Make_Struct0(result, klass, type, size, data_type, sval) \
VALUE result = rb_data_typed_object_zalloc(klass, size, data_type); \
- (sval) = RBIMPL_CAST((type *)RTYPEDDATA_DATA(result)); \
+ (sval) = RBIMPL_CAST((type *)rbimpl_typeddata_get_data(result)); \
RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval))
/**
* Identical to #TypedData_Wrap_Struct, except it allocates a new data region
* internally instead of taking an existing one. The allocation is done using
- * ruby_calloc(). Hence it makes no sense for `data_type->function.dfree` to
- * be anything other than ::RUBY_TYPED_DEFAULT_FREE.
+ * ruby_calloc().
*
* @param klass Ruby level class of the object.
* @param type Type name of the C struct.
@@ -498,18 +566,37 @@ RBIMPL_SYMBOL_EXPORT_END()
sizeof(type))
#endif
-/**
- * Obtains a C struct from inside of a wrapper Ruby object.
- *
- * @param obj An instance of ::RTypedData.
- * @param type Type name of the C struct.
- * @param data_type The data type describing `type`.
- * @param sval Variable name of obtained C struct.
- * @exception rb_eTypeError `obj` is not a kind of `data_type`.
- * @return Unwrapped C struct that `obj` holds.
- */
-#define TypedData_Get_Struct(obj,type,data_type,sval) \
- ((sval) = RBIMPL_CAST((type *)rb_check_typeddata((obj), (data_type))))
+static inline bool
+rbimpl_typeddata_embedded_p(VALUE obj)
+{
+ return (RTYPEDDATA(obj)->type) & TYPED_DATA_EMBEDDED;
+}
+
+RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
+static inline bool
+RTYPEDDATA_EMBEDDED_P(VALUE obj)
+{
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
+
+ return rbimpl_typeddata_embedded_p(obj);
+}
+
+static inline void *
+rbimpl_typeddata_get_data(VALUE obj)
+{
+ /* We reuse the data pointer in embedded TypedData. */
+ return rbimpl_typeddata_embedded_p(obj) ?
+ RBIMPL_CAST((void *)&RTYPEDDATA_DATA(obj)) :
+ RTYPEDDATA_DATA(obj);
+}
+
+static inline void *
+RTYPEDDATA_GET_DATA(VALUE obj)
+{
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL));
+
+ return rbimpl_typeddata_get_data(obj);
+}
RBIMPL_ATTR_PURE()
RBIMPL_ATTR_ARTIFICIAL()
@@ -527,7 +614,28 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline bool
rbimpl_rtypeddata_p(VALUE obj)
{
- return RTYPEDDATA(obj)->typed_flag == 1;
+ return FL_TEST_RAW(obj, RUBY_TYPED_FL_IS_TYPED_DATA);
+}
+
+RBIMPL_ATTR_PURE()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * @private
+ *
+ * Identical to rbimpl_rtypeddata_p(), except it is allowed to call on non-data
+ * objects.
+ *
+ * This is an implementation detail of inline functions defined in this file.
+ * People don't use it directly.
+ *
+ * @param[in] obj Object in question
+ * @retval true `obj` is an instance of ::RTypedData.
+ * @retval false `obj` is not an instance of ::RTypedData
+ */
+static inline bool
+rbimpl_obj_typeddata_p(VALUE obj)
+{
+ return RB_TYPE_P(obj, RUBY_T_DATA) && rbimpl_rtypeddata_p(obj);
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
@@ -543,19 +651,14 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline bool
RTYPEDDATA_P(VALUE obj)
{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(! RB_TYPE_P(obj, RUBY_T_DATA))) {
- Check_Type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(false);
- }
-#endif
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
return rbimpl_rtypeddata_p(obj);
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
-/* :TODO: can this function be __attribute__((returns_nonnull)) or not? */
+RBIMPL_ATTR_RETURNS_NONNULL()
/**
* Queries for the type of given object.
*
@@ -563,19 +666,77 @@ RBIMPL_ATTR_ARTIFICIAL()
* @return Data type struct that corresponds to `obj`.
* @pre `obj` must be an instance of ::RTypedData.
*/
-static inline const struct rb_data_type_struct *
+static inline const rb_data_type_t *
RTYPEDDATA_TYPE(VALUE obj)
{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(! RTYPEDDATA_P(obj))) {
- rb_unexpected_type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(NULL);
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL));
+
+ VALUE type = RTYPEDDATA(obj)->type & TYPED_DATA_PTR_MASK;
+ const rb_data_type_t *ptr = RBIMPL_CAST((const rb_data_type_t *)type);
+ RBIMPL_ASSERT_OR_ASSUME(ptr);
+ return ptr;
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL(())
+static inline bool
+rbimpl_typeddata_inherited_p_inline(const rb_data_type_t *child, const rb_data_type_t *parent)
+{
+ do {
+ if (RB_LIKELY(child == parent)) return true;
+ } while ((child = child->parent) != NULL);
+ return false;
+}
+#define rb_typeddata_inherited_p rbimpl_typeddata_inherited_p_inline
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL((2))
+static inline bool
+rbimpl_typeddata_is_kind_of_inline(VALUE obj, const rb_data_type_t *data_type)
+{
+ if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) return false;
+ return rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type);
+}
+#define rb_typeddata_is_kind_of rbimpl_typeddata_is_kind_of_inline
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL((2))
+/**
+ * @private
+ *
+ * This is an implementation detail of TypedData_Get_Struct(). Don't use it
+ * directly.
+ */
+static inline void *
+rbimpl_check_typeddata(VALUE obj, const rb_data_type_t *expected_type)
+{
+ if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) {
+ rb_unexpected_object_type(obj, expected_type->wrap_struct_name);
}
-#endif
- return RTYPEDDATA(obj)->type;
+ const rb_data_type_t *actual_type = RTYPEDDATA_TYPE(obj);
+ if (RB_UNLIKELY(!rb_typeddata_inherited_p(actual_type, expected_type))){
+ rb_unexpected_typeddata(actual_type, expected_type);
+ }
+
+ return RTYPEDDATA_GET_DATA(obj);
}
+
+/**
+ * Obtains a C struct from inside of a wrapper Ruby object.
+ *
+ * @param obj An instance of ::RTypedData.
+ * @param type Type name of the C struct.
+ * @param data_type The data type describing `type`.
+ * @param sval Variable name of obtained C struct.
+ * @exception rb_eTypeError `obj` is not a kind of `data_type`.
+ * @return Unwrapped C struct that `obj` holds.
+ */
+#define TypedData_Get_Struct(obj,type,data_type,sval) \
+ ((sval) = RBIMPL_CAST((type *)rbimpl_check_typeddata((obj), (data_type))))
+
+RBIMPL_ATTR_NONNULL((2))
/**
* While we don't stop you from using this function, it seems to be an
* implementation detail of #TypedData_Make_Struct, which is preferred over
@@ -597,12 +758,4 @@ rb_data_typed_object_make(VALUE klass, const rb_data_type_t *type, void **datap,
return result;
}
-RBIMPL_ATTR_DEPRECATED(("by: rb_data_typed_object_wrap"))
-/** @deprecated This function was renamed to rb_data_typed_object_wrap(). */
-static inline VALUE
-rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type)
-{
- return rb_data_typed_object_wrap(klass, datap, type);
-}
-
#endif /* RBIMPL_RTYPEDDATA_H */
diff --git a/include/ruby/internal/ctype.h b/include/ruby/internal/ctype.h
index 0f7ca6c516..8b24026311 100644
--- a/include/ruby/internal/ctype.h
+++ b/include/ruby/internal/ctype.h
@@ -498,8 +498,8 @@ RBIMPL_ATTR_ARTIFICIAL()
* Our own locale-insensitive version of `tolower(3)`.
*
* @param[in] c Byte in question to convert.
- * @retval c The byte is not listed in in IEEE 1003.1 section
- * 7.3.1.1 "upper".
+ * @retval c The byte is not listed in IEEE 1003.1 section 7.3.1.1
+ * "upper".
* @retval otherwise Byte converted using the map defined in IEEE 1003.1
* section 7.3.1 "tolower".
* @note Not only does this function works under the POSIX Locale, but
diff --git a/include/ruby/internal/encoding/coderange.h b/include/ruby/internal/encoding/coderange.h
index 7a81208c9e..c89f871518 100644
--- a/include/ruby/internal/encoding/coderange.h
+++ b/include/ruby/internal/encoding/coderange.h
@@ -79,7 +79,7 @@ RBIMPL_ATTR_CONST()
static inline bool
RB_ENC_CODERANGE_CLEAN_P(enum ruby_coderange_type cr)
{
- return rb_enc_coderange_clean_p(cr);
+ return rb_enc_coderange_clean_p(RBIMPL_CAST((int)cr));
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
diff --git a/include/ruby/internal/encoding/encoding.h b/include/ruby/internal/encoding/encoding.h
index dc3e0151f0..a58f9f2b15 100644
--- a/include/ruby/internal/encoding/encoding.h
+++ b/include/ruby/internal/encoding/encoding.h
@@ -28,6 +28,7 @@
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/attr/returns_nonnull.h"
#include "ruby/internal/dllexport.h"
+#include "ruby/internal/encoding/coderange.h"
#include "ruby/internal/value.h"
#include "ruby/internal/core/rbasic.h"
#include "ruby/internal/fl_type.h"
@@ -79,7 +80,7 @@ enum ruby_encoding_consts {
static inline void
RB_ENCODING_SET_INLINED(VALUE obj, int encindex)
{
- VALUE f = /* upcast */ encindex;
+ VALUE f = /* upcast */ RBIMPL_CAST((VALUE)encindex);
f <<= RUBY_ENCODING_SHIFT;
RB_FL_UNSET_RAW(obj, RUBY_ENCODING_MASK);
diff --git a/include/ruby/internal/encoding/string.h b/include/ruby/internal/encoding/string.h
index 6ed7ca1c90..2cfa91c01e 100644
--- a/include/ruby/internal/encoding/string.h
+++ b/include/ruby/internal/encoding/string.h
@@ -30,7 +30,7 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
- * Identical to rb_enc_str_new(), except it additionally takes an encoding.
+ * Identical to rb_str_new(), except it additionally takes an encoding.
*
* @param[in] ptr A memory region of `len` bytes length.
* @param[in] len Length of `ptr`, in bytes, not including the
@@ -307,13 +307,13 @@ RBIMPL_ATTR_NONNULL(())
/**
* Looks for the passed string in the passed buffer.
*
- * @param[in] x Buffer that potentially includes `y`.
+ * @param[in] x Query string.
* @param[in] m Number of bytes of `x`.
- * @param[in] y Query string.
+ * @param[in] y Buffer that potentially includes `x`.
* @param[in] n Number of bytes of `y`.
* @param[in] enc Encoding of both `x` and `y`.
* @retval -1 Not found.
- * @retval otherwise Found index in `x`.
+ * @retval otherwise Found index in `y`.
* @note This API can match at a non-character-boundary.
*/
long rb_memsearch(const void *x, long m, const void *y, long n, rb_encoding *enc);
diff --git a/include/ruby/internal/error.h b/include/ruby/internal/error.h
index 1ce9a30e6f..5bf82bfe7d 100644
--- a/include/ruby/internal/error.h
+++ b/include/ruby/internal/error.h
@@ -53,6 +53,9 @@ typedef enum {
/** Warning is for performance issues (not enabled by -w). */
RB_WARN_CATEGORY_PERFORMANCE,
+ /** Warning is for checking unused block strictly */
+ RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK,
+
RB_WARN_CATEGORY_DEFAULT_BITS = (
(1U << RB_WARN_CATEGORY_DEPRECATED) |
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
@@ -62,6 +65,7 @@ typedef enum {
(1U << RB_WARN_CATEGORY_DEPRECATED) |
(1U << RB_WARN_CATEGORY_EXPERIMENTAL) |
(1U << RB_WARN_CATEGORY_PERFORMANCE) |
+ (1U << RB_WARN_CATEGORY_STRICT_UNUSED_BLOCK) |
0)
} rb_warning_category_t;
@@ -417,11 +421,12 @@ void rb_readwrite_syserr_fail(enum rb_io_wait_readwrite waiting, int err, const
RBIMPL_ATTR_COLD()
RBIMPL_ATTR_NORETURN()
/**
+ * @private
+ *
* Fails with the given object's type incompatibility to the type.
*
- * It seems this function is visible from extension libraries only because
- * RTYPEDDATA_TYPE() uses it on RUBY_DEBUG. So you can basically ignore it;
- * use some other fine-grained method instead.
+ * This is an implementation detail of Check_Type. People don't use it
+ * directly.
*
* @param[in] self The object in question.
* @param[in] t Expected type of the object.
@@ -481,7 +486,7 @@ VALUE *rb_ruby_debug_ptr(void);
*/
#define ruby_debug (*rb_ruby_debug_ptr())
-/* reports if `-W' specified */
+/* reports if $VERBOSE is true */
RBIMPL_ATTR_NONNULL((1))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
/**
@@ -496,7 +501,8 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
* default, the method just emits its passed contents to ::rb_stderr using
* rb_io_write().
*
- * @note This function is affected by the `-W` flag.
+ * @note This function is affected by the value of $VERBOSE, it does
+ * nothing unless $VERBOSE is true.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
*
* @internal
@@ -521,7 +527,7 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
* Issues a compile-time warning that happens at `__file__:__line__`. Purpose
* of this function being exposed to CAPI is unclear.
*
- * @note This function is affected by the `-W` flag.
+ * @note This function is affected by the value of $VERBOSE.
* @param[in] file The path corresponding to Ruby level `__FILE__`.
* @param[in] line The number corresponding to Ruby level `__LINE__`.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
@@ -534,19 +540,20 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
* Identical to rb_sys_fail(), except it does not raise an exception to render
* a warning instead.
*
- * @note This function is affected by the `-W` flag.
+ * @note This function is affected by the value of $VERBOSE.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
*/
void rb_sys_warning(const char *fmt, ...);
-/* reports always */
+/* reports if $VERBOSE is not nil (so if it is true or false) */
RBIMPL_ATTR_COLD()
RBIMPL_ATTR_NONNULL((1))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 1, 2)
/**
- * Identical to rb_warning(), except it reports always regardless of runtime
- * `-W` flag.
+ * Identical to rb_warning(), except it reports unless $VERBOSE is nil.
*
+ * @note This function is affected by the value of $VERBOSE, it does
+ * nothing if $VERBOSE is nil.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
*/
void rb_warn(const char *fmt, ...);
@@ -555,8 +562,7 @@ RBIMPL_ATTR_COLD()
RBIMPL_ATTR_NONNULL((2))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 2, 3)
/**
- * Identical to rb_category_warning(), except it reports always regardless of
- * runtime `-W` flag.
+ * Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
*
* @param[in] cat Category e.g. deprecated.
* @param[in] fmt Format specifier string compatible with rb_sprintf().
@@ -566,8 +572,7 @@ void rb_category_warn(rb_warning_category_t cat, const char *fmt, ...);
RBIMPL_ATTR_NONNULL((1, 3))
RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 4)
/**
- * Identical to rb_compile_warning(), except it reports always regardless of
- * runtime `-W` flag.
+ * Identical to rb_compile_warning(), except it reports unless $VERBOSE is nil.
*
* @param[in] file The path corresponding to Ruby level `__FILE__`.
* @param[in] line The number corresponding to Ruby level `__LINE__`.
diff --git a/include/ruby/internal/eval.h b/include/ruby/internal/eval.h
index 5bcbb97746..23aa1d9580 100644
--- a/include/ruby/internal/eval.h
+++ b/include/ruby/internal/eval.h
@@ -155,7 +155,8 @@ VALUE rb_funcallv(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eException Any exceptions happen inside.
* @return What the method evaluates to.
@@ -189,7 +190,8 @@ VALUE rb_funcallv_public(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eNoMethodError The method is private or protected.
* @exception rb_eException Any exceptions happen inside.
@@ -261,7 +263,8 @@ VALUE rb_funcall_passing_block(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eNoMethodError The method is private or protected.
* @exception rb_eException Any exceptions happen inside.
@@ -307,7 +310,8 @@ VALUE rb_funcall_with_block(VALUE recv, ID mid, int argc, const VALUE *argv, VAL
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No such method.
* @exception rb_eNoMethodError The method is private or protected.
* @exception rb_eException Any exceptions happen inside.
@@ -335,7 +339,8 @@ VALUE rb_call_super(int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eNoMethodError No super method are there.
* @exception rb_eException Any exceptions happen inside.
* @return What the super method evaluates to.
diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h
index f7f5abdd9b..2afb3f1fa3 100644
--- a/include/ruby/internal/fl_type.h
+++ b/include/ruby/internal/fl_type.h
@@ -59,10 +59,8 @@
#define FL_WB_PROTECTED RBIMPL_CAST((VALUE)RUBY_FL_WB_PROTECTED) /**< @old{RUBY_FL_WB_PROTECTED} */
#define FL_PROMOTED RBIMPL_CAST((VALUE)RUBY_FL_PROMOTED) /**< @old{RUBY_FL_PROMOTED} */
#define FL_FINALIZE RBIMPL_CAST((VALUE)RUBY_FL_FINALIZE) /**< @old{RUBY_FL_FINALIZE} */
-#define FL_TAINT RBIMPL_CAST((VALUE)RUBY_FL_TAINT) /**< @old{RUBY_FL_TAINT} */
#define FL_SHAREABLE RBIMPL_CAST((VALUE)RUBY_FL_SHAREABLE) /**< @old{RUBY_FL_SHAREABLE} */
#define FL_UNTRUSTED RBIMPL_CAST((VALUE)RUBY_FL_UNTRUSTED) /**< @old{RUBY_FL_UNTRUSTED} */
-#define FL_SEEN_OBJ_ID RBIMPL_CAST((VALUE)RUBY_FL_SEEN_OBJ_ID) /**< @old{RUBY_FL_SEEN_OBJ_ID} */
#define FL_EXIVAR RBIMPL_CAST((VALUE)RUBY_FL_EXIVAR) /**< @old{RUBY_FL_EXIVAR} */
#define FL_FREEZE RBIMPL_CAST((VALUE)RUBY_FL_FREEZE) /**< @old{RUBY_FL_FREEZE} */
@@ -218,11 +216,11 @@ ruby_fl_type {
RUBY_FL_PROMOTED = (1<<5),
/**
- * This flag is no longer in use
+ * This flag meaning is type dependent, currently only used by T_DATA.
*
* @internal
*/
- RUBY_FL_UNUSED6 = (1<<6),
+ RUBY_FL_USERPRIV0 = (1<<6),
/**
* This flag has something to do with finalisers. A ruby object can have
@@ -239,16 +237,16 @@ ruby_fl_type {
RUBY_FL_FINALIZE = (1<<7),
/**
- * @deprecated This flag once was a thing back in the old days, but makes
- * no sense any longer today. Exists here for backwards
+ * @deprecated This flag was an implementation detail that should never have
+ * no been exposed. Exists here for backwards
* compatibility only. You can safely forget about it.
*/
- RUBY_FL_TAINT
+ RUBY_FL_EXIVAR
#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
+ RBIMPL_ATTR_DEPRECATED(("FL_EXIVAR is an outdated implementation detail, it should not be used."))
#elif defined(_MSC_VER)
-# pragma deprecated(RUBY_FL_TAINT)
+# pragma deprecated(RUBY_FL_EXIVAR)
#endif
= 0,
@@ -265,52 +263,19 @@ ruby_fl_type {
*/
RUBY_FL_SHAREABLE = (1<<8),
- /**
- * @deprecated This flag once was a thing back in the old days, but makes
- * no sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- */
- RUBY_FL_UNTRUSTED
-
-#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("trustedness turned out to be a wrong idea."))
-#elif defined(_MSC_VER)
-# pragma deprecated(RUBY_FL_UNTRUSTED)
-#endif
-
- = 0,
-
- /**
- * This flag has something to do with object IDs. Unlike in the old days,
- * an object's object ID (that a user can query using `Object#object_id`)
- * is no longer its physical address represented using Ruby level integers.
- * It is now a monotonic-increasing integer unrelated to the underlying
- * memory arrangement. Object IDs are assigned when necessary; objects are
- * born without one, and will eventually have such property when queried.
- * The interpreter has to manage which one is which. This is the flag that
- * helps the management. Objects with this flag set are the ones with
- * object IDs assigned.
- *
- * @internal
- *
- * But honestly, @shyouhei doesn't think this flag should be visible from
- * 3rd parties. It must be an implementation detail that they should never
- * know. Might better be hidden.
- */
- RUBY_FL_SEEN_OBJ_ID = (1<<9),
+ /**
+ * This object weakly refers to other objects.
+ *
+ * @internal
+ */
+ RUBY_FL_WEAK_REFERENCE = (1<<9),
- /**
- * This flag has something to do with instance variables. 3rd parties need
- * not know, but there are several ways to store an object's instance
- * variables. Objects with this flag use so-called "generic" backend
- * storage. This distinction is purely an implementation detail. People
- * need not be aware of this working behind-the-scene.
- *
- * @internal
- *
- * As of writing everything except ::RObject and RModule use this scheme.
- */
- RUBY_FL_EXIVAR = (1<<10),
+ /**
+ * This flag is no longer in use
+ *
+ * @internal
+ */
+ RUBY_FL_UNUSED10 = (1<<10),
/**
* This flag has something to do with data immutability. When this flag is
@@ -370,7 +335,7 @@ ruby_fl_type {
* 3rd parties. It must be an implementation detail that they should never
* know. Might better be hidden.
*/
- RUBY_ELTS_SHARED = RUBY_FL_USER2,
+ RUBY_ELTS_SHARED = RUBY_FL_USER0,
/**
* This flag has something to do with an object's class. There are kind of
@@ -395,24 +360,7 @@ ruby_fl_type {
* 3rd parties. It must be an implementation detail that they should never
* know. Might better be hidden.
*/
- RUBY_FL_SINGLETON = RUBY_FL_USER0,
-};
-
-enum {
- /**
- * @deprecated This flag once was a thing back in the old days, but makes
- * no sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- */
- RUBY_FL_DUPPED
-
-#if defined(RBIMPL_HAVE_ENUM_ATTRIBUTE)
- RBIMPL_ATTR_DEPRECATED(("It seems there is no actual usage of this enum."))
-#elif defined(_MSC_VER)
-# pragma deprecated(RUBY_FL_DUPPED)
-#endif
-
- = (int)RUBY_T_MASK | (int)RUBY_FL_EXIVAR
+ RUBY_FL_SINGLETON = RUBY_FL_USER1,
};
#undef RBIMPL_HAVE_ENUM_ATTRIBUTE
@@ -446,10 +394,8 @@ RB_FL_ABLE(VALUE obj)
if (RB_SPECIAL_CONST_P(obj)) {
return false;
}
- else if (RB_TYPE_P(obj, RUBY_T_NODE)) {
- return false;
- }
else {
+ RBIMPL_ASSERT_OR_ASSUME(!RB_TYPE_P(obj, RUBY_T_NODE));
return true;
}
}
@@ -457,7 +403,7 @@ RB_FL_ABLE(VALUE obj)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implenentation detail of RB_FL_TEST(). 3rd parties need not use
+ * This is an implementation detail of RB_FL_TEST(). 3rd parties need not use
* this. Just always use RB_FL_TEST().
*
* @param[in] obj Object in question.
@@ -505,7 +451,7 @@ RB_FL_TEST(VALUE obj, VALUE flags)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implenentation detail of RB_FL_ANY(). 3rd parties need not use
+ * This is an implementation detail of RB_FL_ANY(). 3rd parties need not use
* this. Just always use RB_FL_ANY().
*
* @param[in] obj Object in question.
@@ -539,7 +485,7 @@ RB_FL_ANY(VALUE obj, VALUE flags)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implenentation detail of RB_FL_ALL(). 3rd parties need not use
+ * This is an implementation detail of RB_FL_ALL(). 3rd parties need not use
* this. Just always use RB_FL_ALL().
*
* @param[in] obj Object in question.
@@ -575,7 +521,7 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implenentation detail of RB_FL_SET(). 3rd parties need not use
+ * This is an implementation detail of RB_FL_SET(). 3rd parties need not use
* this. Just always use RB_FL_SET().
*
* @param[out] obj Object in question.
@@ -595,7 +541,7 @@ rbimpl_fl_set_raw_raw(struct RBasic *obj, VALUE flags)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implenentation detail of RB_FL_SET(). 3rd parties need not use
+ * This is an implementation detail of RB_FL_SET(). 3rd parties need not use
* this. Just always use RB_FL_SET().
*
* @param[out] obj Object in question.
@@ -635,7 +581,7 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implenentation detail of RB_FL_UNSET(). 3rd parties need not use
+ * This is an implementation detail of RB_FL_UNSET(). 3rd parties need not use
* this. Just always use RB_FL_UNSET().
*
* @param[out] obj Object in question.
@@ -655,7 +601,7 @@ rbimpl_fl_unset_raw_raw(struct RBasic *obj, VALUE flags)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implenentation detail of RB_FL_UNSET(). 3rd parties need not use
+ * This is an implementation detail of RB_FL_UNSET(). 3rd parties need not use
* this. Just always use RB_FL_UNSET().
*
* @param[out] obj Object in question.
@@ -690,7 +636,7 @@ RBIMPL_ATTR_ARTIFICIAL()
/**
* @private
*
- * This is an implenentation detail of RB_FL_REVERSE(). 3rd parties need not
+ * This is an implementation detail of RB_FL_REVERSE(). 3rd parties need not
* use this. Just always use RB_FL_REVERSE().
*
* @param[out] obj Object in question.
@@ -710,7 +656,7 @@ rbimpl_fl_reverse_raw_raw(struct RBasic *obj, VALUE flags)
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implenentation detail of RB_FL_REVERSE(). 3rd parties need not
+ * This is an implementation detail of RB_FL_REVERSE(). 3rd parties need not
* use this. Just always use RB_FL_REVERSE().
*
* @param[out] obj Object in question.
@@ -743,130 +689,8 @@ RB_FL_REVERSE(VALUE obj, VALUE flags)
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function once was a thing in the old days, but makes no
- * sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- *
- * @param[in] obj Object in question.
- * @return false always.
- */
-static inline bool
-RB_OBJ_TAINTABLE(VALUE obj)
-{
- (void)obj;
- return false;
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
/**
- * @deprecated This function once was a thing in the old days, but makes no
- * sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- *
- * @param[in] obj Object in question.
- * @return false always.
- */
-static inline VALUE
-RB_OBJ_TAINTED_RAW(VALUE obj)
-{
- (void)obj;
- return false;
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function once was a thing in the old days, but makes no
- * sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- *
- * @param[in] obj Object in question.
- * @return false always.
- */
-static inline bool
-RB_OBJ_TAINTED(VALUE obj)
-{
- (void)obj;
- return false;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function once was a thing in the old days, but makes no
- * sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- *
- * @param[in] obj Object in question.
- */
-static inline void
-RB_OBJ_TAINT_RAW(VALUE obj)
-{
- (void)obj;
- return;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function once was a thing in the old days, but makes no
- * sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- *
- * @param[in] obj Object in question.
- */
-static inline void
-RB_OBJ_TAINT(VALUE obj)
-{
- (void)obj;
- return;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function once was a thing in the old days, but makes no
- * sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- *
- * @param[in] dst Victim object.
- * @param[in] src Infectant object.
- */
-static inline void
-RB_OBJ_INFECT_RAW(VALUE dst, VALUE src)
-{
- (void)dst;
- (void)src;
- return;
-}
-
-RBIMPL_ATTR_ARTIFICIAL()
-RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea."))
-/**
- * @deprecated This function once was a thing in the old days, but makes no
- * sense any longer today. Exists here for backwards
- * compatibility only. You can safely forget about it.
- *
- * @param[in] dst Victim object.
- * @param[in] src Infectant object.
- */
-static inline void
-RB_OBJ_INFECT(VALUE dst, VALUE src)
-{
- (void)dst;
- (void)src;
- return;
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * This is an implenentation detail of RB_OBJ_FROZEN(). 3rd parties need not
+ * This is an implementation detail of RB_OBJ_FROZEN(). 3rd parties need not
* use this. Just always use RB_OBJ_FROZEN().
*
* @param[in] obj Object in question.
@@ -905,9 +729,21 @@ RB_OBJ_FROZEN(VALUE obj)
}
}
+RUBY_SYMBOL_EXPORT_BEGIN
+/**
+ * Prevents further modifications to the given object. ::rb_eFrozenError shall
+ * be raised if modification is attempted.
+ *
+ * @param[out] x Object in question.
+ * @exception rb_eNoMemError Failed to allocate memory for the frozen
+ * representation of the object.
+ */
+void rb_obj_freeze_inline(VALUE obj);
+RUBY_SYMBOL_EXPORT_END
+
RBIMPL_ATTR_ARTIFICIAL()
/**
- * This is an implenentation detail of RB_OBJ_FREEZE(). 3rd parties need not
+ * This is an implementation detail of RB_OBJ_FREEZE(). 3rd parties need not
* use this. Just always use RB_OBJ_FREEZE().
*
* @param[out] obj Object in question.
@@ -915,11 +751,7 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline void
RB_OBJ_FREEZE_RAW(VALUE obj)
{
- RB_FL_SET_RAW(obj, RUBY_FL_FREEZE);
+ rb_obj_freeze_inline(obj);
}
-RUBY_SYMBOL_EXPORT_BEGIN
-void rb_obj_freeze_inline(VALUE obj);
-RUBY_SYMBOL_EXPORT_END
-
#endif /* RBIMPL_FL_TYPE_H */
diff --git a/include/ruby/internal/gc.h b/include/ruby/internal/gc.h
index 2a5180671c..21c2b670b3 100644
--- a/include/ruby/internal/gc.h
+++ b/include/ruby/internal/gc.h
@@ -44,10 +44,11 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
-#define REF_EDGE(s, p) (offsetof(struct s, p))
-#define REFS_LIST_PTR(l) ((RUBY_DATA_FUNC)l)
+#define RUBY_REF_EDGE(s, p) offsetof(s, p)
+#define RUBY_REFS_LIST_PTR(l) (RUBY_DATA_FUNC)(uintptr_t)(l)
#define RUBY_REF_END SIZE_MAX
-#define RUBY_REFERENCES_START(t) static size_t t[] = {
+#define RUBY_REFERENCES(t) static const size_t t[]
+#define RUBY_REFERENCES_START(t) RUBY_REFERENCES(t) = {
#define RUBY_REFERENCES_END RUBY_REF_END, };
/* gc.c */
@@ -209,22 +210,6 @@ void rb_gc_mark_movable(VALUE obj);
VALUE rb_gc_location(VALUE obj);
/**
- * Asserts that the passed object is no longer needed. Such objects are
- * reclaimed sooner or later so this function is not mandatory. But sometimes
- * you can know from your application knowledge that an object is surely dead
- * at some point. Calling this as a hint can be a polite way.
- *
- * @param[out] obj Object, dead.
- * @pre `obj` have never been passed to this function before.
- * @post `obj` could be invalidated.
- * @warning It is a failure to pass an object multiple times to this
- * function.
- * @deprecated This is now a no-op function.
- */
-RBIMPL_ATTR_DEPRECATED(("this is now a no-op function"))
-void rb_gc_force_recycle(VALUE obj);
-
-/**
* Triggers a GC process. This was the only GC entry point that we had at the
* beginning. Over time our GC evolved. Now what this function does is just a
* very simplified variation of the entire GC algorithms. A series of
diff --git a/include/ruby/internal/globals.h b/include/ruby/internal/globals.h
index 5a414fc472..9beb215c0c 100644
--- a/include/ruby/internal/globals.h
+++ b/include/ruby/internal/globals.h
@@ -68,6 +68,7 @@ RUBY_EXTERN VALUE rb_cBasicObject; /**< `BasicObject` class. */
RUBY_EXTERN VALUE rb_cObject; /**< `Object` class. */
RUBY_EXTERN VALUE rb_cArray; /**< `Array` class. */
RUBY_EXTERN VALUE rb_cBinding; /**< `Binding` class. */
+RUBY_EXTERN VALUE rb_cBox; /**< `Ruby::Box` class. */
RUBY_EXTERN VALUE rb_cClass; /**< `Class` class. */
RUBY_EXTERN VALUE rb_cDir; /**< `Dir` class. */
RUBY_EXTERN VALUE rb_cEncoding; /**< `Encoding` class. */
@@ -91,10 +92,11 @@ RUBY_EXTERN VALUE rb_cRandom; /**< `Random` class. */
RUBY_EXTERN VALUE rb_cRange; /**< `Range` class. */
RUBY_EXTERN VALUE rb_cRational; /**< `Rational` class. */
RUBY_EXTERN VALUE rb_cRegexp; /**< `Regexp` class. */
+RUBY_EXTERN VALUE rb_cSet; /**< `Set` class. */
RUBY_EXTERN VALUE rb_cStat; /**< `File::Stat` class. */
RUBY_EXTERN VALUE rb_cString; /**< `String` class. */
RUBY_EXTERN VALUE rb_cStruct; /**< `Struct` class. */
-RUBY_EXTERN VALUE rb_cSymbol; /**< `Sumbol` class. */
+RUBY_EXTERN VALUE rb_cSymbol; /**< `Symbol` class. */
RUBY_EXTERN VALUE rb_cThread; /**< `Thread` class. */
RUBY_EXTERN VALUE rb_cTime; /**< `Time` class. */
RUBY_EXTERN VALUE rb_cTrueClass; /**< `TrueClass` class. */
diff --git a/include/ruby/internal/has/builtin.h b/include/ruby/internal/has/builtin.h
index 243ba2a34c..8e7fb173d8 100644
--- a/include/ruby/internal/has/builtin.h
+++ b/include/ruby/internal/has/builtin.h
@@ -48,6 +48,7 @@
# /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66970 */
# define RBIMPL_HAS_BUILTIN(_) (RBIMPL_HAS_BUILTIN_ ## _)
# define RBIMPL_HAS_BUILTIN___builtin_add_overflow RBIMPL_COMPILER_SINCE(GCC, 5, 1, 0)
+# define RBIMPL_HAS_BUILTIN___builtin_add_overflow_p RBIMPL_COMPILER_SINCE(GCC, 7, 0, 0)
# define RBIMPL_HAS_BUILTIN___builtin_alloca RBIMPL_COMPILER_SINCE(GCC, 0, 0, 0)
# define RBIMPL_HAS_BUILTIN___builtin_alloca_with_align RBIMPL_COMPILER_SINCE(GCC, 6, 1, 0)
# define RBIMPL_HAS_BUILTIN___builtin_assume 0
@@ -75,6 +76,7 @@
# define RBIMPL_HAS_BUILTIN___builtin_rotateright32 0
# define RBIMPL_HAS_BUILTIN___builtin_rotateright64 0
# define RBIMPL_HAS_BUILTIN___builtin_sub_overflow RBIMPL_COMPILER_SINCE(GCC, 5, 1, 0)
+# define RBIMPL_HAS_BUILTIN___builtin_sub_overflow_p RBIMPL_COMPILER_SINCE(GCC, 7, 0, 0)
# define RBIMPL_HAS_BUILTIN___builtin_unreachable RBIMPL_COMPILER_SINCE(GCC, 4, 5, 0)
# /* Note that "0, 0, 0" might be inaccurate. */
@@ -82,6 +84,7 @@
# /* Take config.h definition when available */
# define RBIMPL_HAS_BUILTIN(_) ((RBIMPL_HAS_BUILTIN_ ## _)+0)
# define RBIMPL_HAS_BUILTIN___builtin_add_overflow HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW
+# define RBIMPL_HAS_BUILTIN___builtin_add_overflow_p HAVE_BUILTIN___BUILTIN_ADD_OVERFLOW_P
# define RBIMPL_HAS_BUILTIN___builtin_alloca 0
# define RBIMPL_HAS_BUILTIN___builtin_alloca_with_align HAVE_BUILTIN___BUILTIN_ALLOCA_WITH_ALIGN
# define RBIMPL_HAS_BUILTIN___builtin_assume 0
@@ -107,6 +110,7 @@
# define RBIMPL_HAS_BUILTIN___builtin_rotateright64 0
# define RBIMPL_HAS_BUILTIN___builtin_popcountll HAVE_BUILTIN___BUILTIN_POPCOUNTLL
# define RBIMPL_HAS_BUILTIN___builtin_sub_overflow HAVE_BUILTIN___BUILTIN_SUB_OVERFLOW
+# define RBIMPL_HAS_BUILTIN___builtin_sub_overflow_p HAVE_BUILTIN___BUILTIN_SUB_OVERFLOW_P
# if defined(HAVE___BUILTIN_UNREACHABLE)
# define RBIMPL_HAS_BUILTIN___builtin_unreachable 1
# else
diff --git a/include/ruby/internal/has/c_attribute.h b/include/ruby/internal/has/c_attribute.h
index c5c48867bf..69b0f402cd 100644
--- a/include/ruby/internal/has/c_attribute.h
+++ b/include/ruby/internal/has/c_attribute.h
@@ -21,11 +21,23 @@
* @brief Defines #RBIMPL_HAS_C_ATTRIBUTE.
*/
+#include "ruby/internal/has/extension.h"
+#include "ruby/internal/has/warning.h"
+
/** Wraps (or simulates) `__has_c_attribute`. */
#if defined(__cplusplus)
# /* Makes no sense. */
# define RBIMPL_HAS_C_ATTRIBUTE(_) 0
+#elif RBIMPL_HAS_EXTENSION(c_attributes)
+# /* Hmm. It seems Clang 17 has this macro defined even when -std=c99 mode,
+# * _and_ fails to compile complaining that attributes are C2X feature. We
+# * need to work around this nonsense. */
+# define RBIMPL_HAS_C_ATTRIBUTE(_) __has_c_attribute(_)
+
+#elif RBIMPL_HAS_WARNING("-Wc2x-extensions")
+# define RBIMPL_HAS_C_ATTRIBUTE(_) 0
+
#elif defined(__has_c_attribute)
# define RBIMPL_HAS_C_ATTRIBUTE(_) __has_c_attribute(_)
diff --git a/include/ruby/internal/intern/array.h b/include/ruby/internal/intern/array.h
index 2262c6f0c6..b2cc6b132d 100644
--- a/include/ruby/internal/intern/array.h
+++ b/include/ruby/internal/intern/array.h
@@ -144,7 +144,13 @@ void rb_ary_free(VALUE ary);
*/
void rb_ary_modify(VALUE ary);
-/** @alias{rb_obj_freeze} */
+/**
+ * Freeze an array, preventing further modifications. The underlying buffer may
+ * be shrunk before freezing to conserve memory.
+ *
+ * @param[out] obj Object assumed to be an array to freeze.
+ * @see RB_OBJ_FREEZE()
+ */
VALUE rb_ary_freeze(VALUE obj);
RBIMPL_ATTR_PURE()
@@ -187,7 +193,7 @@ VALUE rb_ary_shared_with_p(VALUE lhs, VALUE rhs);
* : (int i) -> T?
* | (int beg, int len) -> ::Array[T]?
* | (Range[int] r) -> ::Array[T]?
- * | (ArithmeticSequence as) -> ::Array[T]? # This also raises RagneError.
+ * | (ArithmeticSequence as) -> ::Array[T]? # This also raises RangeError.
* end
* ```
*/
diff --git a/include/ruby/internal/intern/bignum.h b/include/ruby/internal/intern/bignum.h
index 43d68018de..c27f77a1fb 100644
--- a/include/ruby/internal/intern/bignum.h
+++ b/include/ruby/internal/intern/bignum.h
@@ -51,7 +51,7 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
VALUE rb_big_new(size_t len, int sign);
/**
- * Queries if the passed bignum instance is a "bigzro". What is a bigzero?
+ * Queries if the passed bignum instance is a "bigzero". What is a bigzero?
* Well, bignums are for very big integers, but can also represent tiny ones
* like -1, 0, 1. Bigzero are instances of bignums whose values are zero.
* Knowing if a bignum is bigzero can be handy on occasions, like for instance
@@ -793,7 +793,7 @@ size_t rb_absint_size(VALUE val, int *nlz_bits_ret);
* @exception rb_eTypeError `val` doesn't respond to `#to_int`.
* @retval (size_t)-1 Overflowed.
* @retval otherwise
- `((val_numbits * CHAR_BIT + word_numbits - 1) / word_numbits)`,
+ * `((val_numbits * CHAR_BIT + word_numbits - 1) / word_numbits)`,
* where val_numbits is the number of bits of `abs(val)`.
* @post If `nlz_bits_ret` is not `NULL` and there is no overflow,
* `(return_value * word_numbits - val_numbits)` is stored in
diff --git a/include/ruby/internal/intern/class.h b/include/ruby/internal/intern/class.h
index 0fb2d001bc..357af5d176 100644
--- a/include/ruby/internal/intern/class.h
+++ b/include/ruby/internal/intern/class.h
@@ -88,8 +88,8 @@ VALUE rb_define_class_id(ID id, VALUE super);
* @post `outer::id` refers the returned class.
* @note If a class named `id` is already defined and its superclass is
* `super`, the function just returns the defined class.
- * @note The compaction GC does not move classes returned by this
- * function.
+ * @note The GC does not collect nor move classes returned by this
+ * function. They are immortal.
*/
VALUE rb_define_class_id_under(VALUE outer, ID id, VALUE super);
@@ -127,8 +127,8 @@ VALUE rb_define_module_id(ID id);
* constant is not a module.
* @return The created module.
* @post `outer::id` refers the returned module.
- * @note The compaction GC does not move classes returned by this
- * function.
+ * @note The GC does not collect nor move classes returned by this
+ * function. They are immortal.
*/
VALUE rb_define_module_id_under(VALUE outer, ID id);
diff --git a/include/ruby/internal/intern/complex.h b/include/ruby/internal/intern/complex.h
index e111bd8ced..1efc093631 100644
--- a/include/ruby/internal/intern/complex.h
+++ b/include/ruby/internal/intern/complex.h
@@ -87,10 +87,6 @@ VALUE rb_complex_new(VALUE real, VALUE imag);
*/
VALUE rb_complex_new_polar(VALUE abs, VALUE arg);
-RBIMPL_ATTR_DEPRECATED(("by: rb_complex_new_polar"))
-/** @old{rb_complex_new_polar} */
-VALUE rb_complex_polar(VALUE abs, VALUE arg);
-
RBIMPL_ATTR_PURE()
/**
* Queries the real part of the passed Complex.
diff --git a/include/ruby/internal/intern/cont.h b/include/ruby/internal/intern/cont.h
index 32647f48aa..2d813ceb9d 100644
--- a/include/ruby/internal/intern/cont.h
+++ b/include/ruby/internal/intern/cont.h
@@ -148,7 +148,8 @@ VALUE rb_fiber_resume(VALUE fiber, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eFiberError `fiber` is terminated etc.
* @exception rb_eException Any exceptions happen in `fiber`.
* @return Either what was yielded or the last value of the fiber body.
@@ -192,7 +193,8 @@ VALUE rb_fiber_yield(int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eException What was raised using `Fiber#raise`.
* @return (See rb_fiber_resume() for details)
*/
@@ -247,7 +249,8 @@ VALUE rb_fiber_transfer(VALUE fiber, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eFiberError (See above)
* @exception rb_eException What was raised using `Fiber#raise`.
* @return (See rb_fiber_resume() for details)
@@ -275,7 +278,7 @@ VALUE rb_fiber_transfer_kw(VALUE fiber, int argc, const VALUE *argv, int kw_spla
* @exception rb_eFiberError `fiber` is terminated etc.
* @return (See rb_fiber_resume() for details)
*/
-VALUE rb_fiber_raise(VALUE fiber, int argc, const VALUE *argv);
+VALUE rb_fiber_raise(VALUE fiber, int argc, VALUE *argv);
RBIMPL_SYMBOL_EXPORT_END()
diff --git a/include/ruby/internal/intern/enumerator.h b/include/ruby/internal/intern/enumerator.h
index 20e5d7c6fc..00804d786a 100644
--- a/include/ruby/internal/intern/enumerator.h
+++ b/include/ruby/internal/intern/enumerator.h
@@ -100,7 +100,8 @@ VALUE rb_enumeratorize_with_size(VALUE recv, VALUE meth, int argc, const VALUE *
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `meth` is not an instance of ::rb_cSymbol.
* @return A new instance of ::rb_cEnumerator which, when yielded,
* enumerates by calling `meth` on `recv` with `argv`.
@@ -186,7 +187,8 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @return A new instance of ::rb_cEnumerator which, when yielded,
* enumerates by calling the current method on `recv` with `argv`.
*/
@@ -220,7 +222,8 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @note This macro may return inside.
*/
#define RETURN_SIZED_ENUMERATOR_KW(obj, argc, argv, size_fn, kw_splat) do { \
@@ -250,7 +253,8 @@ RBIMPL_SYMBOL_EXPORT_END()
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @note This macro may return inside.
*/
#define RETURN_ENUMERATOR_KW(obj, argc, argv, kw_splat) \
diff --git a/include/ruby/internal/intern/error.h b/include/ruby/internal/intern/error.h
index bf8daadd3e..1fd9ec2f51 100644
--- a/include/ruby/internal/intern/error.h
+++ b/include/ruby/internal/intern/error.h
@@ -237,6 +237,8 @@ RBIMPL_ATTR_NORETURN()
*/
void rb_error_arity(int argc, int min, int max);
+void rb_str_modify(VALUE str);
+
RBIMPL_SYMBOL_EXPORT_END()
/**
@@ -244,12 +246,7 @@ RBIMPL_SYMBOL_EXPORT_END()
*
* Does anyone use this? Remain not deleted for compatibility.
*/
-#define rb_check_frozen_internal(obj) do { \
- VALUE frozen_obj = (obj); \
- if (RB_UNLIKELY(RB_OBJ_FROZEN(frozen_obj))) { \
- rb_error_frozen_object(frozen_obj); \
- } \
- } while (0)
+#define rb_check_frozen_internal rb_check_frozen
/** @alias{rb_check_frozen} */
static inline void
@@ -258,9 +255,16 @@ rb_check_frozen_inline(VALUE obj)
if (RB_UNLIKELY(RB_OBJ_FROZEN(obj))) {
rb_error_frozen_object(obj);
}
+
+ /* ref: internal CHILLED_STRING_P()
+ This is an implementation detail subject to change. */
+ if (RB_UNLIKELY(RB_TYPE_P(obj, T_STRING) && FL_TEST_RAW(obj, RUBY_FL_USER2 | RUBY_FL_USER3))) { // STR_CHILLED
+ rb_str_modify(obj);
+ }
}
-/** @alias{rb_check_frozen} */
+/* rb_check_frozen() is available as a symbol, but have
+ * the inline version take priority for native consumers. */
#define rb_check_frozen rb_check_frozen_inline
/**
diff --git a/include/ruby/internal/intern/file.h b/include/ruby/internal/intern/file.h
index 79820fdc61..8508b7ab9e 100644
--- a/include/ruby/internal/intern/file.h
+++ b/include/ruby/internal/intern/file.h
@@ -24,6 +24,9 @@
#include "ruby/internal/attr/pure.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/value.h"
+#if !defined RUBY_EXPORT && !defined RUBY_NO_OLD_COMPATIBILITY
+# include "ruby/backward.h"
+#endif
RBIMPL_SYMBOL_EXPORT_BEGIN()
diff --git a/include/ruby/internal/intern/hash.h b/include/ruby/internal/intern/hash.h
index af8dfd5d8f..504770fa5f 100644
--- a/include/ruby/internal/intern/hash.h
+++ b/include/ruby/internal/intern/hash.h
@@ -284,20 +284,6 @@ typedef VALUE rb_hash_update_func(VALUE newkey, VALUE oldkey, VALUE value);
*/
VALUE rb_hash_update_by(VALUE hash1, VALUE hash2, rb_hash_update_func *func);
-/* file.c */
-
-/**
- * This function is mysterious. What it does is not immediately obvious. Also
- * what it does seems platform dependent.
- *
- * @param[in] path A local path.
- * @retval 0 The "check" succeeded.
- * @retval otherwise The "check" failed.
- */
-int rb_path_check(const char *path);
-
-/* hash.c */
-
/**
* Destructively removes every environment variables of the running process.
*
diff --git a/include/ruby/internal/intern/io.h b/include/ruby/internal/intern/io.h
index 02c249723e..b9eb258cc1 100644
--- a/include/ruby/internal/intern/io.h
+++ b/include/ruby/internal/intern/io.h
@@ -385,7 +385,7 @@ VALUE rb_io_puts(int argc, const VALUE *argv, VALUE io);
* @param[in] fd Target file descriptor.
* @param[in] flags Flags, e.g. `O_CREAT|O_EXCL`
* @param[in] path The path of the file that backs `fd`, for diagnostics.
- * @return An allocated instance of ::rb_cIO.
+ * @return An allocated instance of ::rb_cIO with the autoclose flag set.
* @note Leave `path` NULL if you don't know.
*/
VALUE rb_io_fdopen(int fd, int flags, const char *path);
diff --git a/include/ruby/internal/intern/load.h b/include/ruby/internal/intern/load.h
index 288a16c2ec..9ceb98c2e4 100644
--- a/include/ruby/internal/intern/load.h
+++ b/include/ruby/internal/intern/load.h
@@ -177,6 +177,43 @@ VALUE rb_f_require(VALUE self, VALUE feature);
VALUE rb_require_string(VALUE feature);
/**
+ * Resolves and returns a symbol of a function in the native extension
+ * specified by the feature and symbol names. Extensions will use this function
+ * to access the symbols provided by other native extensions.
+ *
+ * @param[in] feature Name of a feature, e.g. `"json"`.
+ * @param[in] symbol Name of a symbol defined by the feature.
+ * @return The resolved symbol of a function, defined and externed by the
+ * specified feature. It may be NULL if the feature is not loaded,
+ * the feature is not extension, or the symbol is not found.
+ */
+void *rb_ext_resolve_symbol(const char *feature, const char *symbol);
+
+/**
+ * This macro is to provide backwards compatibility. It provides a way to
+ * define function prototypes and resolving function symbols in a safe way.
+ *
+ * ```CXX
+ * // prototypes
+ * #ifdef HAVE_RB_EXT_RESOLVE_SYMBOL
+ * VALUE *(*other_extension_func)(VALUE,VALUE);
+ * #else
+ * VALUE other_extension_func(VALUE);
+ * #endif
+ *
+ * // in Init_xxx()
+ * #ifdef HAVE_RB_EXT_RESOLVE_SYMBOL
+ * other_extension_func = \
+ * (VALUE(*)(VALUE,VALUE))rb_ext_resolve_symbol(fname, sym_name);
+ * if (other_extension_func == NULL) {
+ * // raise your own error
+ * }
+ * #endif
+ * ```
+ */
+#define HAVE_RB_EXT_RESOLVE_SYMBOL 1
+
+/**
* @name extension configuration
* @{
*/
diff --git a/include/ruby/internal/intern/object.h b/include/ruby/internal/intern/object.h
index b9ffa57c06..3897639a0a 100644
--- a/include/ruby/internal/intern/object.h
+++ b/include/ruby/internal/intern/object.h
@@ -80,7 +80,8 @@ VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `klass`'s allocator is undefined.
* @exception rb_eException Any exceptions can happen inside.
* @return An allocated new instance of `klass`.
@@ -151,13 +152,12 @@ VALUE rb_obj_is_kind_of(VALUE obj, VALUE klass);
* @return An allocated, not yet initialised instance of `klass`.
* @note It calls the allocator defined by rb_define_alloc_func(). You
* cannot use this function to define an allocator. Use
- * rb_newobj_of(), #TypedData_Make_Struct or others, instead.
+ * TypedData_Make_Struct or others, instead.
* @note Usually prefer rb_class_new_instance() to rb_obj_alloc() and
* rb_obj_call_init().
* @see rb_class_new_instance()
* @see rb_obj_call_init()
* @see rb_define_alloc_func()
- * @see rb_newobj_of()
* @see #TypedData_Make_Struct
*/
VALUE rb_obj_alloc(VALUE klass);
diff --git a/include/ruby/internal/intern/proc.h b/include/ruby/internal/intern/proc.h
index b8c3c5e146..2635d672eb 100644
--- a/include/ruby/internal/intern/proc.h
+++ b/include/ruby/internal/intern/proc.h
@@ -101,7 +101,8 @@ VALUE rb_proc_call(VALUE recv, VALUE args);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eException Any exceptions happen inside.
* @return What the proc evaluates to.
*/
@@ -141,7 +142,8 @@ VALUE rb_proc_call_with_block(VALUE recv, int argc, const VALUE *argv, VALUE pro
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eException Any exceptions happen inside.
* @return What the proc evaluates to.
*/
@@ -245,7 +247,8 @@ VALUE rb_method_call(int argc, const VALUE *argv, VALUE recv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `recv` is not a method.
* @exception rb_eException Any exceptions happen inside.
* @return What the method returns.
@@ -279,7 +282,8 @@ VALUE rb_method_call_with_block(int argc, const VALUE *argv, VALUE recv, VALUE p
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `args`' last is not a keyword argument.
* - RB_PASS_KEYWORDS `args`' last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @exception rb_eTypeError `recv` is not a method.
* @exception rb_eException Any exceptions happen inside.
* @return What the method returns.
diff --git a/include/ruby/internal/intern/process.h b/include/ruby/internal/intern/process.h
index 7a7b24ed4b..cfa5e13162 100644
--- a/include/ruby/internal/intern/process.h
+++ b/include/ruby/internal/intern/process.h
@@ -31,6 +31,15 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
/* process.c */
/**
+ * Wait for the specified process to terminate, reap it, and return its status.
+ *
+ * @param[in] pid The process ID to wait for.
+ * @param[in] flags The flags to pass to waitpid(2).
+ * @return VALUE An instance of Process::Status.
+ */
+VALUE rb_process_status_wait(rb_pid_t pid, int flags);
+
+/**
* Sets the "last status", or the `$?`.
*
* @param[in] status The termination status, as defined in `waitpid(3posix)`.
@@ -247,7 +256,7 @@ rb_pid_t rb_spawn_err(int argc, const VALUE *argv, char *errbuf, size_t buflen);
*
* @internal
*
- * This function might or might not exist depending on `./confiugre` result.
+ * This function might or might not exist depending on `./configure` result.
* It must be a portability hell. Better not use.
*/
VALUE rb_proc_times(VALUE _);
diff --git a/include/ruby/internal/intern/select.h b/include/ruby/internal/intern/select.h
index fabc287cd1..ba75213618 100644
--- a/include/ruby/internal/intern/select.h
+++ b/include/ruby/internal/intern/select.h
@@ -72,11 +72,13 @@ struct timeval;
* someone else, vastly varies among operating systems. You would better avoid
* touching an fd from more than one threads.
*
+ * NOTE: this function is used in native extensions, so change its API with care.
+ *
* @internal
*
* Although any file descriptors are possible here, it makes completely no
* sense to pass a descriptor that is not `O_NONBLOCK`. If you want to know
- * the reason for this limitatuon in detail, you might find this thread super
+ * the reason for this limitation in detail, you might find this thread super
* interesting: https://lkml.org/lkml/2004/10/6/117
*/
int rb_thread_fd_select(int nfds, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout);
diff --git a/include/ruby/internal/intern/select/win32.h b/include/ruby/internal/intern/select/win32.h
index edaf7a8523..b7301e63f3 100644
--- a/include/ruby/internal/intern/select/win32.h
+++ b/include/ruby/internal/intern/select/win32.h
@@ -206,7 +206,7 @@ rb_fd_dup(rb_fdset_t *dst, const rb_fdset_t *src)
* property we heavily touch the internals of MSVCRT. We `CreateFile` a
* `"NUL"` alongside of a socket and directly manipulate its `struct ioinfo`.
* This is of course a very dirty hack. If we could design the API today we
- * could use `CancellIoEx`. But we are older than that Win32 API.
+ * could use `CancelIoEx`. But we are older than that Win32 API.
*/
static inline int
rb_fd_select(int n, rb_fdset_t *rfds, rb_fdset_t *wfds, rb_fdset_t *efds, struct timeval *timeout)
@@ -253,7 +253,7 @@ rb_fd_max(const rb_fdset_t *f)
const fd_set *p = f->fdset;
RBIMPL_ASSERT_OR_ASSUME(p);
- return p->fd_count;
+ return RBIMPL_CAST((int)p->fd_count);
}
#endif /* RBIMPL_INTERN_SELECT_WIN32_H */
diff --git a/include/ruby/internal/intern/set.h b/include/ruby/internal/intern/set.h
new file mode 100644
index 0000000000..f4ff8665e2
--- /dev/null
+++ b/include/ruby/internal/intern/set.h
@@ -0,0 +1,111 @@
+#ifndef RBIMPL_INTERN_SET_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_INTERN_SET_H
+/**
+ * @file
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief Public APIs related to ::rb_cSet.
+ */
+#include "ruby/internal/attr/nonnull.h"
+#include "ruby/internal/dllexport.h"
+#include "ruby/internal/value.h"
+
+RBIMPL_SYMBOL_EXPORT_BEGIN()
+
+/* set.c */
+
+RBIMPL_ATTR_NONNULL(())
+/**
+ * Iterates over a set. Calls func with each element of the set and the
+ * argument given. func should return ST_CONTINUE, ST_STOP, or ST_DELETE.
+ *
+ * @param[in] set An instance of ::rb_cSet to iterate over.
+ * @param[in] func Callback function to yield.
+ * @param[in] arg Passed as-is to `func`.
+ * @exception rb_eRuntimeError `set` was tampered during iterating.
+ */
+void rb_set_foreach(VALUE set, int (*func)(VALUE element, VALUE arg), VALUE arg);
+
+/**
+ * Creates a new, empty set object.
+ *
+ * @return An allocated new instance of ::rb_cSet.
+ */
+VALUE rb_set_new(void);
+
+/**
+ * Identical to rb_set_new(), except it additionally specifies how many elements
+ * it is expected to contain. This way you can create a set that is large enough
+ * for your need. For large sets, it means it won't need to be reallocated
+ * much, improving performance.
+ *
+ * @param[in] capa Designed capacity of the set.
+ * @return An empty Set, whose capacity is `capa`.
+ */
+VALUE rb_set_new_capa(size_t capa);
+
+/**
+ * Whether the set contains the given element.
+ *
+ * @param[in] set Set to look into.
+ * @param[in] element Set element to look for.
+ * @return true if element is in the set, falst otherwise.
+ */
+bool rb_set_lookup(VALUE set, VALUE element);
+
+/**
+ * Adds element to set.
+ *
+ * @param[in] set Target set table to modify.
+ * @param[in] element Arbitrary Ruby object.
+ * @exception rb_eFrozenError `set` is frozen.
+ * @return true if element was not already in set, false otherwise
+ * @post `element` is in `set`.
+ */
+bool rb_set_add(VALUE set, VALUE element);
+
+/**
+ * Removes all entries from set.
+ *
+ * @param[out] set Target to clear.
+ * @exception rb_eFrozenError `set`is frozen.
+ * @return The passed `set`
+ * @post `set` has no elements.
+ */
+VALUE rb_set_clear(VALUE set);
+
+/**
+ * Removes the element from from set.
+ *
+ * @param[in] set Target set to modify.
+ * @param[in] element Key to delete.
+ * @retval true if element was already in set, false otherwise
+ * @post `set` does not have `element` as an element.
+ */
+bool rb_set_delete(VALUE set, VALUE element);
+
+/**
+ * Returns the number of elements in the set.
+ *
+ * @param[in] set A set object.
+ * @return The size of the set.
+ */
+size_t rb_set_size(VALUE set);
+
+RBIMPL_SYMBOL_EXPORT_END()
+
+#endif /* RBIMPL_INTERN_SET_H */
diff --git a/include/ruby/internal/intern/signal.h b/include/ruby/internal/intern/signal.h
index e5b6d6c3d5..4773788651 100644
--- a/include/ruby/internal/intern/signal.h
+++ b/include/ruby/internal/intern/signal.h
@@ -97,7 +97,7 @@ RBIMPL_ATTR_NONNULL(())
* - Case #11: When signo and PID are both negative, the behaviour of this
* function depends on how `killpg(3)` works. On Linux, it seems such
* attempt is strictly prohibited and `Errno::EINVAL` is raised. But on
- * macOS, it seems it tries to to send the signal actually to the process
+ * macOS, it seems it tries to send the signal actually to the process
* group.
*
* @note Above description is in fact different from how `kill(2)` works.
diff --git a/include/ruby/internal/intern/string.h b/include/ruby/internal/intern/string.h
index 3083125e56..2ec08fc81f 100644
--- a/include/ruby/internal/intern/string.h
+++ b/include/ruby/internal/intern/string.h
@@ -412,7 +412,7 @@ VALUE rb_utf8_str_new_static(const char *ptr, long len);
/**
* Identical to rb_interned_str(), except it takes a Ruby's string instead of
- * C's. It can also be seen as a routine identical to to rb_str_new_shared(),
+ * C's. It can also be seen as a routine identical to rb_str_new_shared(),
* except it returns an infamous "f"string.
*
* @param[in] str An object of ::RString.
@@ -444,8 +444,8 @@ VALUE rb_str_to_interned_str(VALUE str);
* terminating NUL character.
* @exception rb_eArgError `len` is negative.
* @return A found or created instance of ::rb_cString, of `len` bytes
- * length, of "binary" encoding, whose contents are identical to
- * that of `ptr`.
+ * length, of US-ASCII or "binary" encoding, whose contents are
+ * identical to that of `ptr`.
* @pre At least `len` bytes of continuous memory region shall be
* accessible via `ptr`.
*/
@@ -454,7 +454,7 @@ VALUE rb_interned_str(const char *ptr, long len);
RBIMPL_ATTR_NONNULL(())
/**
* Identical to rb_interned_str(), except it assumes the passed pointer is a
- * pointer to a C's string. It can also be seen as a routine identical to to
+ * pointer to a C's string. It can also be seen as a routine identical to
* rb_str_to_interned_str(), except it takes a C's string instead of Ruby's.
* Or it can also be seen as a routine identical to rb_str_new_cstr(), except
* it returns an infamous "f"string.
@@ -591,10 +591,9 @@ void rb_must_asciicompat(VALUE obj);
VALUE rb_str_dup(VALUE str);
/**
- * I guess there is no use case of this function in extension libraries, but
- * this is a routine identical to rb_str_dup(), except it always creates an
- * instance of ::rb_cString regardless of the given object's class. This makes
- * the most sense when the passed string is formerly hidden by rb_obj_hide().
+ * Like rb_str_dup(), but always create an instance of ::rb_cString
+ * regardless of the given object's class. This makes the most sense
+ * when the passed string is formerly hidden by rb_obj_hide().
*
* @param[in] str A string, possibly hidden.
* @return A duplicated new instance of ::rb_cString.
@@ -970,8 +969,8 @@ st_index_t rb_str_hash(VALUE str);
*
* @param[in] str1 A string.
* @param[in] str2 Another string.
- * @retval 1 They have identical contents, length, and encodings.
- * @retval 0 Otherwise.
+ * @retval 0 They have identical contents, length, and encodings.
+ * @retval 1 Otherwise.
* @pre Both objects must not be any arbitrary objects except
* ::RString.
*
@@ -1686,10 +1685,10 @@ rbimpl_exc_new_cstr(VALUE exc, const char *str)
* Length of a string literal.
*
* @param[in] str A C String literal.
- * @return An integer constant expression that represents `str`'s length,
- * in bytes, not including the terminating NUL character.
+ * @return An integer constant expression that represents the number of
+ * `str`'s elements, not including the terminating NUL character.
*/
-#define rb_strlen_lit(str) (sizeof(str "") - 1)
+#define rb_strlen_lit(str) ((sizeof(str "") / sizeof(str ""[0])) - 1)
/**
* Identical to rb_str_new_static(), except it cannot take string variables.
diff --git a/include/ruby/internal/intern/struct.h b/include/ruby/internal/intern/struct.h
index 4510508d77..16b3fad4e0 100644
--- a/include/ruby/internal/intern/struct.h
+++ b/include/ruby/internal/intern/struct.h
@@ -54,6 +54,8 @@ VALUE rb_struct_new(VALUE klass, ...);
* @post Global toplevel constant `name` is defined.
* @note `name` is allowed to be a null pointer. This function creates
* an anonymous struct class then.
+ * @note The GC does not collect nor move classes returned by this
+ * function. They are immortal.
*
* @internal
*
@@ -78,6 +80,8 @@ RBIMPL_ATTR_NONNULL((2))
* @post `name` is a constant under `space`.
* @note In contrast to rb_struct_define(), it doesn't make any sense to
* pass a null pointer to this function.
+ * @note The GC does not collect nor move classes returned by this
+ * function. They are immortal.
*/
VALUE rb_struct_define_under(VALUE space, const char *name, ...);
@@ -195,6 +199,8 @@ RBIMPL_ATTR_NONNULL((2))
* @post `class_name` is a constant under `outer`.
* @note In contrast to rb_struct_define_without_accessor(), it doesn't
* make any sense to pass a null name.
+ * @note The GC does not collect nor move classes returned by this
+ * function. They are immortal.
*/
VALUE rb_struct_define_without_accessor_under(VALUE outer, const char *class_name, VALUE super, rb_alloc_func_t alloc, ...);
@@ -209,6 +215,8 @@ VALUE rb_struct_define_without_accessor_under(VALUE outer, const char *class_nam
* NULL. Each of which are the name of fields.
* @exception rb_eArgError Duplicated field name.
* @return The defined class.
+ * @note The GC does not collect nor move classes returned by this
+ * function. They are immortal.
*/
VALUE rb_data_define(VALUE super, ...);
diff --git a/include/ruby/internal/intern/thread.h b/include/ruby/internal/intern/thread.h
index 716375acd7..4d87452745 100644
--- a/include/ruby/internal/intern/thread.h
+++ b/include/ruby/internal/intern/thread.h
@@ -61,10 +61,10 @@ int rb_thread_wait_fd(int fd);
int rb_thread_fd_writable(int fd);
/**
- * Notifies a closing of a file descriptor to other threads. Multiple threads
- * can wait for the given file descriptor at once. If such file descriptor is
- * closed, threads need to start propagating their exceptions. This is the API
- * to kick that process.
+ * This funciton is now a no-op. It was previously used to interrupt threads
+ * that were using the given file descriptor and wait for them to finish.
+ *
+ * @deprecated Use IO with RUBY_IO_MODE_EXTERNAL and `rb_io_close` instead.
*
* @param[in] fd A file descriptor.
* @note This function blocks until all the threads waiting for such fd
diff --git a/include/ruby/internal/intern/vm.h b/include/ruby/internal/intern/vm.h
index 76af796b54..f0b54c702c 100644
--- a/include/ruby/internal/intern/vm.h
+++ b/include/ruby/internal/intern/vm.h
@@ -89,7 +89,8 @@ VALUE rb_check_funcall(VALUE recv, ID mid, int argc, const VALUE *argv);
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @retval RUBY_Qundef `recv` doesn't respond to `mid`.
* @retval otherwise What the method evaluates to.
*/
@@ -106,9 +107,11 @@ VALUE rb_check_funcall_kw(VALUE recv, ID mid, int argc, const VALUE *argv, int k
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `arg`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `arg`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @return What the command evaluates to.
*/
+RBIMPL_ATTR_DEPRECATED_INTERNAL(4.0)
VALUE rb_eval_cmd_kw(VALUE cmd, VALUE arg, int kw_splat);
/**
@@ -229,8 +232,7 @@ void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func);
* restrict creation of an instance of a class. For example it rarely makes
* sense for a DB adaptor class to allow programmers creating DB row objects
* without querying the DB itself. You can kill sporadic creation of such
- * objects then, by nullifying the allocator function using this API. Your
- * object shall be allocated using #RB_NEWOBJ_OF() directly.
+ * objects then, by nullifying the allocator function using this API.
*
* @param[out] klass The class to modify.
* @pre `klass` must be an instance of Class.
diff --git a/include/ruby/internal/interpreter.h b/include/ruby/internal/interpreter.h
index 662d39c0ec..a10e7ad2d8 100644
--- a/include/ruby/internal/interpreter.h
+++ b/include/ruby/internal/interpreter.h
@@ -141,7 +141,7 @@ void ruby_show_copyright(void);
*
* @param[in] addr A pointer somewhere on the stack, near its bottom.
*/
-void ruby_init_stack(volatile VALUE *addr);
+void ruby_init_stack(void *addr);
/**
* Initializes the VM and builtin libraries.
diff --git a/include/ruby/internal/iterator.h b/include/ruby/internal/iterator.h
index 5f706460f8..891045363e 100644
--- a/include/ruby/internal/iterator.h
+++ b/include/ruby/internal/iterator.h
@@ -265,48 +265,6 @@ int rb_block_given_p(void);
*/
void rb_need_block(void);
-#ifndef __cplusplus
-RBIMPL_ATTR_DEPRECATED(("by: rb_block_call since 1.9"))
-#endif
-/**
- * Old way to iterate a block.
- *
- * @deprecated This is an old API. Use rb_block_call() instead.
- * @warning The passed function must at least once call a ruby method
- * (to handle interrupts etc.)
- * @param[in] func1 A function that could yield a value.
- * @param[in,out] data1 Passed to `func1`
- * @param[in] proc A function acts as a block.
- * @param[in,out] data2 Passed to `proc` as the data2 parameter.
- * @return What `func1` returns.
- */
-VALUE rb_iterate(VALUE (*func1)(VALUE), VALUE data1, rb_block_call_func_t proc, VALUE data2);
-
-#ifdef __cplusplus
-namespace ruby {
-namespace backward {
-/**
- * Old way to iterate a block.
- *
- * @deprecated This is an old API. Use rb_block_call() instead.
- * @warning The passed function must at least once call a ruby method
- * (to handle interrupts etc.)
- * @param[in] iter A function that could yield a value.
- * @param[in,out] data1 Passed to `func1`
- * @param[in] bl A function acts as a block.
- * @param[in,out] data2 Passed to `proc` as the data2 parameter.
- * @return What `func1` returns.
- */
-static inline VALUE
-rb_iterate_deprecated(VALUE (*iter)(VALUE), VALUE data1, rb_block_call_func_t bl, VALUE data2)
-{
- return ::rb_iterate(iter, data1, bl, data2);
-}}}
-
-RBIMPL_ATTR_DEPRECATED(("by: rb_block_call since 1.9"))
-VALUE rb_iterate(VALUE (*func1)(VALUE), VALUE data1, rb_block_call_func_t proc, VALUE data2);
-#endif
-
/**
* Identical to rb_funcallv(), except it additionally passes a function as a
* block. When the method yields, `proc` is called with the yielded value as
@@ -337,7 +295,8 @@ VALUE rb_block_call(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_cal
* @param[in] kw_splat Handling of keyword parameters:
* - RB_NO_KEYWORDS `argv`'s last is not a keyword argument.
* - RB_PASS_KEYWORDS `argv`'s last is a keyword argument.
- * - RB_PASS_CALLED_KEYWORDS it depends if there is a passed block.
+ * - RB_PASS_CALLED_KEYWORDS Pass keyword arguments if the current method
+ * was called with keyword arguments.
* @return What `obj.mid` returns.
*/
VALUE rb_block_call_kw(VALUE obj, ID mid, int argc, const VALUE *argv, rb_block_call_func_t proc, VALUE data2, int kw_splat);
diff --git a/include/ruby/internal/memory.h b/include/ruby/internal/memory.h
index 6884db195d..cd099f85db 100644
--- a/include/ruby/internal/memory.h
+++ b/include/ruby/internal/memory.h
@@ -40,7 +40,12 @@
#if defined(_MSC_VER) && defined(_WIN64)
# include <intrin.h>
+# if defined(_M_AMD64)
# pragma intrinsic(_umul128)
+# endif
+# if defined(_M_ARM64)
+# pragma intrinsic(__umulh)
+# endif
#endif
#include "ruby/internal/attr/alloc_size.h"
@@ -56,13 +61,14 @@
#include "ruby/internal/has/builtin.h"
#include "ruby/internal/stdalign.h"
#include "ruby/internal/stdbool.h"
+#include "ruby/internal/stdckdint.h"
#include "ruby/internal/xmalloc.h"
#include "ruby/backward/2/limits.h"
#include "ruby/backward/2/long_long.h"
#include "ruby/backward/2/assume.h"
#include "ruby/defines.h"
-/** @cond INTENAL_MACRO */
+/** @cond INTERNAL_MACRO */
/* Make alloca work the best possible way. */
#if defined(alloca)
@@ -402,7 +408,8 @@ typedef uint128_t DSIZE_T;
/**
* @private
*
- * This is an implementation detail of rbimpl_size_mul_overflow().
+ * This is an implementation detail of rbimpl_size_mul_overflow() and
+ * rbimpl_size_add_overflow().
*
* @internal
*
@@ -410,9 +417,9 @@ typedef uint128_t DSIZE_T;
* nothing more than std::variant<std::size_t> if we could use recent C++, but
* reality is we cannot.
*/
-struct rbimpl_size_mul_overflow_tag {
- bool left; /**< Whether overflow happened or not. */
- size_t right; /**< Multiplication result. */
+struct rbimpl_size_overflow_tag {
+ bool overflowed; /**< Whether overflow happened or not. */
+ size_t result; /**< Calculation result. */
};
RBIMPL_SYMBOL_EXPORT_BEGIN()
@@ -482,6 +489,18 @@ RBIMPL_ATTR_NORETURN()
*/
void ruby_malloc_size_overflow(size_t x, size_t y);
+RBIMPL_ATTR_NORETURN()
+/**
+ * @private
+ *
+ * This is an implementation detail. People don't use this directly.
+ *
+ * @param[in] x Arbitrary value.
+ * @param[in] y Arbitrary value.
+ * @exception rb_eArgError `x` + `y` would integer overflow.
+ */
+void ruby_malloc_add_size_overflow(size_t x, size_t y);
+
#ifdef HAVE_RB_GC_GUARDED_PTR_VAL
volatile VALUE *rb_gc_guarded_ptr_val(volatile VALUE *ptr, VALUE val);
#endif
@@ -554,39 +573,46 @@ RBIMPL_ATTR_CONST()
*
* @param[in] x Arbitrary value.
* @param[in] y Arbitrary value.
- * @return `{ left, right }`, where `left` is whether there is an integer
- * overflow or not, and `right` is a (possibly overflowed) result
- * of `x` * `y`.
+ * @return `{ overflowed, result }`, where `overflowed` is whether there is
+ * an integer overflow or not, and `result` is a (possibly
+ * overflowed) result of `x` * `y`.
*
* @internal
*
* This is in fact also an implementation detail of ruby_xmalloc2() etc.
*/
-static inline struct rbimpl_size_mul_overflow_tag
+static inline struct rbimpl_size_overflow_tag
rbimpl_size_mul_overflow(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag ret = { false, 0, };
+ struct rbimpl_size_overflow_tag ret = { false, 0, };
+
+#if defined(ckd_mul)
+ ret.overflowed = ckd_mul(&ret.result, x, y);
-#if RBIMPL_HAS_BUILTIN(__builtin_mul_overflow)
- ret.left = __builtin_mul_overflow(x, y, &ret.right);
+#elif RBIMPL_HAS_BUILTIN(__builtin_mul_overflow)
+ ret.overflowed = __builtin_mul_overflow(x, y, &ret.result);
#elif defined(DSIZE_T)
RB_GNUC_EXTENSION DSIZE_T dx = x;
RB_GNUC_EXTENSION DSIZE_T dy = y;
RB_GNUC_EXTENSION DSIZE_T dz = dx * dy;
- ret.left = dz > SIZE_MAX;
- ret.right = RBIMPL_CAST((size_t)dz);
+ ret.overflowed = dz > SIZE_MAX;
+ ret.result = RBIMPL_CAST((size_t)dz);
-#elif defined(_MSC_VER) && defined(_WIN64)
+#elif defined(_MSC_VER) && defined(_M_AMD64)
unsigned __int64 dp = 0;
unsigned __int64 dz = _umul128(x, y, &dp);
- ret.left = RBIMPL_CAST((bool)dp);
- ret.right = RBIMPL_CAST((size_t)dz);
+ ret.overflowed = RBIMPL_CAST((bool)dp);
+ ret.result = RBIMPL_CAST((size_t)dz);
+
+#elif defined(_MSC_VER) && defined(_M_ARM64)
+ ret.overflowed = __umulh(x, y) != 0;
+ ret.result = x * y;
#else
/* https://wiki.sei.cmu.edu/confluence/display/c/INT30-C.+Ensure+that+unsigned+integer+operations+do+not+wrap */
- ret.left = (y != 0) && (x > SIZE_MAX / y);
- ret.right = x * y;
+ ret.overflowed = (y != 0) && (x > SIZE_MAX / y);
+ ret.result = x * y;
#endif
return ret;
@@ -610,11 +636,11 @@ rbimpl_size_mul_overflow(size_t x, size_t y)
static inline size_t
rbimpl_size_mul_or_raise(size_t x, size_t y)
{
- struct rbimpl_size_mul_overflow_tag size =
+ struct rbimpl_size_overflow_tag size =
rbimpl_size_mul_overflow(x, y);
- if (RB_LIKELY(! size.left)) {
- return size.right;
+ if (RB_LIKELY(! size.overflowed)) {
+ return size.result;
}
else {
ruby_malloc_size_overflow(x, y);
@@ -622,6 +648,81 @@ rbimpl_size_mul_or_raise(size_t x, size_t y)
}
}
+#if defined(__DOXYGEN__)
+RBIMPL_ATTR_CONSTEXPR(CXX14)
+#elif RBIMPL_COMPILER_SINCE(GCC, 7, 0, 0)
+RBIMPL_ATTR_CONSTEXPR(CXX14) /* https://gcc.gnu.org/bugzilla/show_bug.cgi?id=70507 */
+#elif RBIMPL_COMPILER_SINCE(Clang, 7, 0, 0)
+RBIMPL_ATTR_CONSTEXPR(CXX14) /* https://bugs.llvm.org/show_bug.cgi?id=37633 */
+#endif
+RBIMPL_ATTR_CONST()
+/**
+ * @private
+ *
+ * This is an implementation detail. People don't use this directly.
+ *
+ * @param[in] x Arbitrary value.
+ * @param[in] y Arbitrary value.
+ * @return `{ overflowed, result }`, where `overflowed` is whether there is
+ * an integer overflow or not, and `result` is a (possibly
+ * overflowed) result of `x` + `y`.
+ *
+ * @internal
+ */
+static inline struct rbimpl_size_overflow_tag
+rbimpl_size_add_overflow(size_t x, size_t y)
+{
+ struct rbimpl_size_overflow_tag ret = { false, 0, };
+
+#if defined(ckd_add)
+ ret.overflowed = ckd_add(&ret.result, x, y);
+
+#elif RBIMPL_HAS_BUILTIN(__builtin_add_overflow)
+ ret.overflowed = __builtin_add_overflow(x, y, &ret.result);
+
+#elif defined(DSIZE_T)
+ RB_GNUC_EXTENSION DSIZE_T dx = x;
+ RB_GNUC_EXTENSION DSIZE_T dy = y;
+ RB_GNUC_EXTENSION DSIZE_T dz = dx + dy;
+ ret.overflowed = dz > SIZE_MAX;
+ ret.result = (size_t)dz;
+
+#else
+ ret.result = x + y;
+ ret.overflowed = ret.result < y;
+
+#endif
+
+ return ret;
+}
+
+/**
+ * @private
+ *
+ * This is an implementation detail. People don't use this directly.
+ *
+ * @param[in] x Arbitrary value.
+ * @param[in] y Arbitrary value.
+ * @exception rb_eArgError Multiplication could integer overflow.
+ * @return `x` + `y`.
+ *
+ * @internal
+ */
+static inline size_t
+rbimpl_size_add_or_raise(size_t x, size_t y)
+{
+ struct rbimpl_size_overflow_tag size =
+ rbimpl_size_add_overflow(x, y);
+
+ if (RB_LIKELY(!size.overflowed)) {
+ return size.result;
+ }
+ else {
+ ruby_malloc_add_size_overflow(x, y);
+ RBIMPL_UNREACHABLE_RETURN(0);
+ }
+}
+
/**
* This is an implementation detail of #RB_ALLOCV_N(). People don't use this
* directly.
@@ -639,7 +740,7 @@ rbimpl_size_mul_or_raise(size_t x, size_t y)
static inline void *
rb_alloc_tmp_buffer2(volatile VALUE *store, long count, size_t elsize)
{
- const size_t total_size = rbimpl_size_mul_or_raise(count, elsize);
+ const size_t total_size = rbimpl_size_mul_or_raise(RBIMPL_CAST((size_t)count), elsize);
const size_t cnt = (total_size + sizeof(VALUE) - 1) / sizeof(VALUE);
return rb_alloc_tmp_buffer_with_count(store, total_size, cnt);
}
diff --git a/include/ruby/internal/module.h b/include/ruby/internal/module.h
index d678dd2102..97b0b2b8b0 100644
--- a/include/ruby/internal/module.h
+++ b/include/ruby/internal/module.h
@@ -56,8 +56,8 @@ RBIMPL_ATTR_NONNULL(())
* @post Top-level constant named `name` refers the returned class.
* @note If a class named `name` is already defined and its superclass is
* `super`, the function just returns the defined class.
- * @note The compaction GC does not move classes returned by this
- * function.
+ * @note The GC does not collect nor move classes returned by this
+ * function. They are immortal.
*
* @internal
*
@@ -75,8 +75,8 @@ RBIMPL_ATTR_NONNULL(())
* constant is not a module.
* @return The created module.
* @post Top-level constant named `name` refers the returned module.
- * @note The compaction GC does not move classes returned by this
- * function.
+ * @note The GC does not collect nor move modules returned by this
+ * function. They are immortal.
*
* @internal
*
@@ -103,8 +103,8 @@ RBIMPL_ATTR_NONNULL(())
* @post `outer::name` refers the returned class.
* @note If a class named `name` is already defined and its superclass
* is `super`, the function just returns the defined class.
- * @note The compaction GC does not move classes returned by this
- * function.
+ * @note The GC does not collect nor move classes returned by this
+ * function. They are immortal.
*/
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super);
@@ -118,8 +118,8 @@ RBIMPL_ATTR_NONNULL(())
* the constant is not a class.
* @return The created module.
* @post `outer::name` refers the returned module.
- * @note The compaction GC does not move classes returned by this
- * function.
+ * @note The GC does not collect nor move modules returned by this
+ * function. They are immortal.
*/
VALUE rb_define_module_under(VALUE outer, const char *name);
diff --git a/include/ruby/internal/newobj.h b/include/ruby/internal/newobj.h
index ba1d7cbe59..13030ae279 100644
--- a/include/ruby/internal/newobj.h
+++ b/include/ruby/internal/newobj.h
@@ -29,63 +29,14 @@
#include "ruby/internal/value.h"
#include "ruby/assert.h"
-/**
- * Declares, allocates, then assigns a new object to the given variable.
- *
- * @param obj Variable name.
- * @param type Variable type.
- * @exception rb_eNoMemError No space left.
- * @return An allocated object, not initialised.
- * @note Modern programs tend to use #NEWOBJ_OF instead.
- *
- * @internal
- *
- * :FIXME: Should we deprecate it?
- */
-#define RB_NEWOBJ(obj,type) type *(obj) = RBIMPL_CAST((type *)rb_newobj())
-
-/**
- * Identical to #RB_NEWOBJ, except it also accepts the allocating object's
- * class and flags.
- *
- * @param obj Variable name.
- * @param type Variable type.
- * @param klass Object's class.
- * @param flags Object's flags.
- * @exception rb_eNoMemError No space left.
- * @return An allocated object, filled with the arguments.
- */
-#define RB_NEWOBJ_OF(obj,type,klass,flags) type *(obj) = RBIMPL_CAST((type *)rb_newobj_of(klass, flags))
-
-#define NEWOBJ RB_NEWOBJ /**< @old{RB_NEWOBJ} */
-#define NEWOBJ_OF RB_NEWOBJ_OF /**< @old{RB_NEWOBJ_OF} */
#define OBJSETUP rb_obj_setup /**< @old{rb_obj_setup} */
#define CLONESETUP rb_clone_setup /**< @old{rb_clone_setup} */
#define DUPSETUP rb_dup_setup /**< @old{rb_dup_setup} */
RBIMPL_SYMBOL_EXPORT_BEGIN()
/**
- * This is the implementation detail of #RB_NEWOBJ.
- *
- * @exception rb_eNoMemError No space left.
- * @return An allocated object, not initialised.
- */
-VALUE rb_newobj(void);
-
-/**
- * This is the implementation detail of #RB_NEWOBJ_OF.
- *
- * @param klass Object's class.
- * @param flags Object's flags.
- * @exception rb_eNoMemError No space left.
- * @return An allocated object, filled with the arguments.
- */
-VALUE rb_newobj_of(VALUE klass, VALUE flags);
-
-/**
* Fills common fields in the object.
*
- * @note Prefer rb_newobj_of() to this function.
* @param[in,out] obj A Ruby object to be set up.
* @param[in] klass `obj` will belong to this class.
* @param[in] type One of ::ruby_value_type.
@@ -158,42 +109,4 @@ void rb_singleton_class_attached(VALUE klass, VALUE obj);
void rb_copy_generic_ivar(VALUE clone, VALUE obj);
RBIMPL_SYMBOL_EXPORT_END()
-RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#clone works."))
-/**
- * @deprecated Not sure exactly when but at some time, the implementation of
- * `Object#clone` stopped using this function. It remained
- * untouched for a while, and then @shyouhei realised that they
- * are no longer doing the same thing. It seems nobody seriously
- * uses this function any longer. Let's just abandon it.
- *
- * @param[out] clone The destination object.
- * @param[in] obj The source object.
- */
-static inline void
-rb_clone_setup(VALUE clone, VALUE obj)
-{
- (void)clone;
- (void)obj;
- return;
-}
-
-RBIMPL_ATTR_DEPRECATED(("This is no longer how Object#dup works."))
-/**
- * @deprecated Not sure exactly when but at some time, the implementation of
- * `Object#dup` stopped using this function. It remained
- * untouched for a while, and then @shyouhei realised that they
- * are no longer the same thing. It seems nobody seriously uses
- * this function any longer. Let's just abandon it.
- *
- * @param[out] dup The destination object.
- * @param[in] obj The source object.
- */
-static inline void
-rb_dup_setup(VALUE dup, VALUE obj)
-{
- (void)dup;
- (void)obj;
- return;
-}
-
#endif /* RBIMPL_NEWOBJ_H */
diff --git a/include/ruby/internal/scan_args.h b/include/ruby/internal/scan_args.h
index 1ed2bf6368..2dbc1ee7bc 100644
--- a/include/ruby/internal/scan_args.h
+++ b/include/ruby/internal/scan_args.h
@@ -75,7 +75,7 @@
* Pass keywords if current method is called with keywords, useful for argument
* delegation
*/
-#define RB_PASS_CALLED_KEYWORDS rb_keyword_given_p()
+#define RB_PASS_CALLED_KEYWORDS !!rb_keyword_given_p()
/** @} */
diff --git a/include/ruby/internal/special_consts.h b/include/ruby/internal/special_consts.h
index dc0a6b41d6..1e2636da48 100644
--- a/include/ruby/internal/special_consts.h
+++ b/include/ruby/internal/special_consts.h
@@ -156,7 +156,7 @@ RB_TEST(VALUE obj)
*
* RTEST(v) can be 0 if and only if (v == Qfalse || v == Qnil).
*/
- return obj & ~RUBY_Qnil;
+ return obj & RBIMPL_CAST((VALUE)~RUBY_Qnil);
}
RBIMPL_ATTR_CONST()
@@ -226,7 +226,7 @@ RB_NIL_OR_UNDEF_P(VALUE obj)
*
* NIL_OR_UNDEF_P(v) can be true only when v is Qundef or Qnil.
*/
- const VALUE mask = ~(RUBY_Qundef ^ RUBY_Qnil);
+ const VALUE mask = RBIMPL_CAST((VALUE)~(RUBY_Qundef ^ RUBY_Qnil));
const VALUE common_bits = RUBY_Qundef & RUBY_Qnil;
return (obj & mask) == common_bits;
}
@@ -326,7 +326,7 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline bool
RB_SPECIAL_CONST_P(VALUE obj)
{
- return RB_IMMEDIATE_P(obj) || obj == RUBY_Qfalse;
+ return (obj == RUBY_Qfalse) || RB_IMMEDIATE_P(obj);
}
RBIMPL_ATTR_CONST()
@@ -346,7 +346,7 @@ RBIMPL_ATTR_CONSTEXPR(CXX11)
static inline VALUE
rb_special_const_p(VALUE obj)
{
- return RB_SPECIAL_CONST_P(obj) * RUBY_Qtrue;
+ return (unsigned int)RB_SPECIAL_CONST_P(obj) * RUBY_Qtrue;
}
/**
diff --git a/include/ruby/internal/static_assert.h b/include/ruby/internal/static_assert.h
index 594c2b2917..30bfd3bb79 100644
--- a/include/ruby/internal/static_assert.h
+++ b/include/ruby/internal/static_assert.h
@@ -23,13 +23,14 @@
#include <assert.h>
#include "ruby/internal/has/extension.h"
#include "ruby/internal/compiler_since.h"
+#include "ruby/internal/attr/maybe_unused.h"
/** @cond INTERNAL_MACRO */
#if defined(__cplusplus) && defined(__cpp_static_assert)
# /* https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations */
# define RBIMPL_STATIC_ASSERT0 static_assert
-#elif defined(__cplusplus) && RBIMPL_COMPILER_SINCE(MSVC, 16, 0, 0)
+#elif defined(__cplusplus) && RBIMPL_COMPILER_IS(MSVC)
# define RBIMPL_STATIC_ASSERT0 static_assert
#elif defined(__INTEL_CXX11_MODE__)
@@ -71,7 +72,7 @@
#else
# define RBIMPL_STATIC_ASSERT(name, expr) \
- typedef int static_assert_ ## name ## _check[1 - 2 * !(expr)]
+ RBIMPL_ATTR_MAYBE_UNUSED() typedef int static_assert_ ## name ## _check[1 - 2 * !(expr)]
#endif
#endif /* RBIMPL_STATIC_ASSERT_H */
diff --git a/include/ruby/internal/stdbool.h b/include/ruby/internal/stdbool.h
index 1ca61136ba..5d9026434b 100644
--- a/include/ruby/internal/stdbool.h
+++ b/include/ruby/internal/stdbool.h
@@ -27,25 +27,13 @@
#elif defined(__cplusplus)
# /* bool is a keyword in C++. */
-# if defined(HAVE_STDBOOL_H) && (__cplusplus >= 201103L)
-# include <cstdbool>
-# endif
-#
# ifndef __bool_true_false_are_defined
# define __bool_true_false_are_defined
# endif
-#elif defined(HAVE_STDBOOL_H)
-# /* Take stdbool.h definition. */
+#else
+# /* Take stdbool.h definition. It exists since GCC 3.0 and VS 2015. */
# include <stdbool.h>
-
-#elif !defined(HAVE__BOOL)
-typedef unsigned char _Bool;
-# /* See also http://www.open-std.org/jtc1/sc22/wg14/www/docs/n2229.htm */
-# define bool _Bool
-# define true ((_Bool)+1)
-# define false ((_Bool)+0)
-# define __bool_true_false_are_defined
#endif
#endif /* RBIMPL_STDBOOL_H */
diff --git a/include/ruby/internal/stdckdint.h b/include/ruby/internal/stdckdint.h
new file mode 100644
index 0000000000..e5b5b8b751
--- /dev/null
+++ b/include/ruby/internal/stdckdint.h
@@ -0,0 +1,68 @@
+#ifndef RBIMPL_STDCKDINT_H /*-*-C++-*-vi:se ft=cpp:*/
+#define RBIMPL_STDCKDINT_H
+/**
+ * @author Ruby developers <ruby-core@ruby-lang.org>
+ * @copyright This file is a part of the programming language Ruby.
+ * Permission is hereby granted, to either redistribute and/or
+ * modify this file, provided that the conditions mentioned in the
+ * file COPYING are met. Consult the file for details.
+ * @warning Symbols prefixed with either `RBIMPL` or `rbimpl` are
+ * implementation details. Don't take them as canon. They could
+ * rapidly appear then vanish. The name (path) of this header file
+ * is also an implementation detail. Do not expect it to persist
+ * at the place it is now. Developers are free to move it anywhere
+ * anytime at will.
+ * @note To ruby-core: remember that this header can be possibly
+ * recursively included from extension libraries written in C++.
+ * Do not expect for instance `__VA_ARGS__` is always available.
+ * We assume C99 for ruby itself but we don't assume languages of
+ * extension libraries. They could be written in C++98.
+ * @brief C23 shim for <stdckdint.h>
+ */
+#include "ruby/internal/config.h"
+#include "ruby/internal/cast.h"
+#include "ruby/internal/has/builtin.h"
+#include "ruby/internal/stdbool.h"
+
+#ifdef __has_include
+# if __has_include(<stdckdint.h>)
+# /* Conforming C23 situation; e.g. recent clang */
+# define RBIMPL_HAVE_STDCKDINT_H
+# endif
+#endif
+
+#ifdef HAVE_STDCKDINT_H
+# /* Some OSes (most notably FreeBSD) have this file. */
+# define RBIMPL_HAVE_STDCKDINT_H
+#endif
+
+#ifdef __cplusplus
+# /* It seems OS/Compiler provided stdckdint.h tend not support C++ yet.
+# * Situations could improve someday but in a meantime let us work around.
+# */
+# undef RBIMPL_HAVE_STDCKDINT_H
+#endif
+
+#ifdef RBIMPL_HAVE_STDCKDINT_H
+# /* Take that. */
+# include <stdckdint.h>
+
+#elif RBIMPL_HAS_BUILTIN(__builtin_add_overflow)
+# define ckd_add(x, y, z) RBIMPL_CAST((bool)__builtin_add_overflow((y), (z), (x)))
+# define ckd_sub(x, y, z) RBIMPL_CAST((bool)__builtin_sub_overflow((y), (z), (x)))
+# define ckd_mul(x, y, z) RBIMPL_CAST((bool)__builtin_mul_overflow((y), (z), (x)))
+# define __STDC_VERSION_STDCKDINT_H__ 202311L
+
+#/* elif defined(__cplusplus) */
+#/* :TODO: if we assume C++11 we can use `<type_traits>` to implement them. */
+
+#else
+# /* intentionally leave them undefined */
+# /* to make `#ifdef ckd_add` etc. work as intended. */
+# undef ckd_add
+# undef ckd_sub
+# undef ckd_mul
+# undef __STDC_VERSION_STDCKDINT_H__
+#endif
+
+#endif /* RBIMPL_STDCKDINT_H */
diff --git a/include/ruby/internal/symbol.h b/include/ruby/internal/symbol.h
index 869a31115c..8bfd686fbe 100644
--- a/include/ruby/internal/symbol.h
+++ b/include/ruby/internal/symbol.h
@@ -101,12 +101,11 @@ ID rb_intern(const char *name);
ID rb_intern2(const char *name, long len);
/**
- * Identical to rb_intern(), except it takes an instance of ::rb_cString.
+ * Identical to rb_intern(), except it takes a `T_STRING` object.
*
* @param[in] str The name of the id.
- * @pre `str` must either be an instance of ::rb_cSymbol, or an instance
- * of ::rb_cString, or responds to `#to_str` method.
- * @exception rb_eTypeError Can't convert `str` into ::rb_cString.
+ * @pre `rb_type(str)` must be `T_STRING`.
+ * @exception rb_eEncodingError `str` contains invalid character(s).
* @exception rb_eRuntimeError Too many symbols.
* @return A (possibly new) id whose value is the given str.
* @note These days Ruby internally has two kinds of symbols
@@ -121,10 +120,17 @@ ID rb_intern_str(VALUE str);
* Retrieves the name mapped to the given id.
*
* @param[in] id An id to query.
- * @retval NULL No such id ever existed in the history.
+ * @retval NULL Unknown id.
* @retval otherwise A name that the id represents.
* @note The return value is managed by the interpreter. Don't pass it
* to free().
+ * @note The underlying name can contain internal NUL bytes, so the return
+ * value might be a truncated representation due to the nature of C
+ * strings.
+ * @note This C string is backed by an underlying Ruby string. The Ruby
+ * string may move during GC compaction which would make this
+ * C string point to invalid memory. Do not use the return value
+ * of this function after a potential GC entry point.
*/
const char *rb_id2name(ID id);
@@ -159,34 +165,40 @@ RBIMPL_ATTR_NONNULL(())
* of ::rb_cSymbol, or an instance of ::rb_cString, or responds
* to `#to_str` method.
* @exception rb_eTypeError Can't convert `*namep` into ::rb_cString.
- * @exception rb_eEncodingError Given string is non-ASCII.
+ * @exception rb_eEncodingError Given string contains invalid character(s).
* @retval 0 No such id ever existed in the history.
* @retval otherwise The id that represents the given name.
* @post The object that `*namep` points to is a converted result
* object, which is always an instance of either ::rb_cSymbol
* or ::rb_cString.
+ * @see rb_str_to_str
* @see https://bugs.ruby-lang.org/issues/5072
- *
- * @internal
- *
- * @shyouhei doesn't know why this has to raise rb_eEncodingError.
*/
ID rb_check_id(volatile VALUE *namep);
/**
- * @copydoc rb_intern_str()
- *
- * @internal
+ * Identical to rb_intern_str(), except it tries to convert the parameter object
+ * to an instance of ::rb_cString or its subclasses.
*
- * :FIXME: Can anyone tell us what is the difference between this one and
- * rb_intern_str()? As far as @shyouhei reads the implementation it seems what
- * rb_to_id() does is is just waste some CPU time, then call rb_intern_str().
- * He hopes he is wrong.
+ * @param[in] str The name of the id.
+ * @pre `str` must either be an instance of ::rb_cSymbol, or an instance
+ * of ::rb_cString, or responds to `#to_str` method.
+ * @exception rb_eTypeError Can't convert `str` into ::rb_cString.
+ * @exception rb_eEncodingError Given string contains invalid character(s).
+ * @exception rb_eRuntimeError Too many symbols.
+ * @return A (possibly new) id whose value is the given str.
+ * @note These days Ruby internally has two kinds of symbols
+ * (static/dynamic). Symbols created using this function would
+ * become static ones; i.e. would never be garbage collected. It
+ * is up to you to avoid memory leaks. Think twice before using
+ * it.
+ * @see rb_str_to_str
*/
ID rb_to_id(VALUE str);
/**
- * Identical to rb_id2name(), except it returns a Ruby's String instead of C's.
+ * Identical to rb_id2name(), except it returns a frozen Ruby String instead of
+ * a C String.
*
* @param[in] id An id to query.
* @retval RUBY_Qfalse No such id ever existed in the history.
@@ -201,14 +213,14 @@ ID rb_to_id(VALUE str);
VALUE rb_id2str(ID id);
/**
- * Identical to rb_id2str(), except it takes an instance of ::rb_cSymbol rather
- * than an ::ID.
+ * Obtain a frozen string representation of a symbol (not including the leading
+ * colon). Done without any object allocations.
*
- * @param[in] id An id to query.
- * @retval RUBY_Qfalse No such id ever existed in the history.
- * @retval otherwise An instance of ::rb_cString with the name of id.
+ * @param[in] symbol A ::rb_cSymbol instance to query.
+ * @return A frozen instance of ::rb_cString with the name of `symbol`.
+ * @note This does not create a permanent ::ID using the symbol.
*/
-VALUE rb_sym2str(VALUE id);
+VALUE rb_sym2str(VALUE symbol);
/**
* Identical to rb_intern_str(), except it generates a dynamic symbol if
@@ -237,17 +249,14 @@ RBIMPL_ATTR_NONNULL(())
* of ::rb_cSymbol, or an instance of ::rb_cString, or responds
* to `#to_str` method.
* @exception rb_eTypeError Can't convert `*namep` into ::rb_cString.
- * @exception rb_eEncodingError Given string is non-ASCII.
+ * @exception rb_eEncodingError Given string contains invalid character(s).
* @retval RUBY_Qnil No such id ever existed in the history.
* @retval otherwise The id that represents the given name.
* @post The object that `*namep` points to is a converted result
* object, which is always an instance of either ::rb_cSymbol
* or ::rb_cString.
* @see https://bugs.ruby-lang.org/issues/5072
- *
- * @internal
- *
- * @shyouhei doesn't know why this has to raise rb_eEncodingError.
+ * @see rb_str_to_str
*/
VALUE rb_check_symbol(volatile VALUE *namep);
RBIMPL_SYMBOL_EXPORT_END()
@@ -308,8 +317,9 @@ rbimpl_intern_const(ID *ptr, const char *str)
}
/**
- * Old implementation detail of rb_intern().
- * @deprecated Does anyone use it? Preserved for backward compat.
+ * Returns the cached ID for the given str in var, in compiler
+ * independent manner. Use this instead of GCC specific rb_intern()
+ * when you want to cache the ID on all platforms certainly.
*/
#define RUBY_CONST_ID(var, str) \
do { \
@@ -318,7 +328,8 @@ rbimpl_intern_const(ID *ptr, const char *str)
} while (0)
#if defined(HAVE_STMT_AND_DECL_IN_EXPR)
-/* __builtin_constant_p and statement expression is available
+/* GCC specific shorthand for RUBY_CONST_ID().
+ * __builtin_constant_p and statement expression is available
* since gcc-2.7.2.3 at least. */
#define rb_intern(str) \
(RBIMPL_CONSTANT_P(str) ? \
diff --git a/include/ruby/internal/value_type.h b/include/ruby/internal/value_type.h
index 977f60a009..b47d8afb97 100644
--- a/include/ruby/internal/value_type.h
+++ b/include/ruby/internal/value_type.h
@@ -96,10 +96,11 @@
#define RB_TYPE_P RB_TYPE_P
#define Check_Type Check_Type
-#if !RUBY_DEBUG
-# define RBIMPL_ASSERT_TYPE(v, t) RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P((v), (t)))
+#ifdef RBIMPL_VA_OPT_ARGS
+# define RBIMPL_ASSERT_TYPE(v, t) \
+ RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P(v, t), "actual type: %d", rb_type(v))
#else
-# define RBIMPL_ASSERT_TYPE Check_Type
+# define RBIMPL_ASSERT_TYPE(v, t) RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P(v, t))
#endif
/** @endcond */
@@ -129,8 +130,8 @@ ruby_value_type {
RUBY_T_RATIONAL = 0x0f, /**< @see struct ::RRational */
RUBY_T_NIL = 0x11, /**< @see ::RUBY_Qnil */
- RUBY_T_TRUE = 0x12, /**< @see ::RUBY_Qfalse */
- RUBY_T_FALSE = 0x13, /**< @see ::RUBY_Qtrue */
+ RUBY_T_TRUE = 0x12, /**< @see ::RUBY_Qtrue */
+ RUBY_T_FALSE = 0x13, /**< @see ::RUBY_Qfalse */
RUBY_T_SYMBOL = 0x14, /**< @see struct ::RSymbol */
RUBY_T_FIXNUM = 0x15, /**< Integers formerly known as Fixnums. */
RUBY_T_UNDEF = 0x16, /**< @see ::RUBY_Qundef */
@@ -443,7 +444,7 @@ Check_Type(VALUE v, enum ruby_value_type t)
}
unexpected_type:
- rb_unexpected_type(v, t);
+ rb_unexpected_type(v, RBIMPL_CAST((int)t));
}
#endif /* RBIMPL_VALUE_TYPE_H */
diff --git a/include/ruby/internal/warning_push.h b/include/ruby/internal/warning_push.h
index f5981633f8..91d62cb00d 100644
--- a/include/ruby/internal/warning_push.h
+++ b/include/ruby/internal/warning_push.h
@@ -79,7 +79,7 @@
*/
#define RBIMPL_WARNING_IGNORED(flag) __pragma(warning(disable: flag))
-#elif RBIMPL_COMPILER_SINCE(MSVC, 12, 0, 0)
+#elif RBIMPL_COMPILER_IS(MSVC)
# /* Not sure exactly when but it seems VC++ 6.0 is a version with it.*/
# define RBIMPL_WARNING_PUSH() __pragma(warning(push))
# define RBIMPL_WARNING_POP() __pragma(warning(pop))
diff --git a/include/ruby/internal/xmalloc.h b/include/ruby/internal/xmalloc.h
index 57552e4e7d..132bc478ce 100644
--- a/include/ruby/internal/xmalloc.h
+++ b/include/ruby/internal/xmalloc.h
@@ -283,110 +283,6 @@ void ruby_xfree(void *ptr)
RBIMPL_ATTR_NOEXCEPT(free(ptr))
;
-#if USE_GC_MALLOC_OBJ_INFO_DETAILS
-# define ruby_xmalloc(s1) ruby_xmalloc_with_location(s1, __FILE__, __LINE__)
-# define ruby_xmalloc2(s1, s2) ruby_xmalloc2_with_location(s1, s2, __FILE__, __LINE__)
-# define ruby_xcalloc(s1, s2) ruby_xcalloc_with_location(s1, s2, __FILE__, __LINE__)
-# define ruby_xrealloc(ptr, s1) ruby_xrealloc_with_location(ptr, s1, __FILE__, __LINE__)
-# define ruby_xrealloc2(ptr, s1, s2) ruby_xrealloc2_with_location(ptr, s1, s2, __FILE__, __LINE__)
-
-RBIMPL_ATTR_NODISCARD()
-RBIMPL_ATTR_RESTRICT()
-RBIMPL_ATTR_RETURNS_NONNULL()
-RBIMPL_ATTR_ALLOC_SIZE((1))
-void *ruby_xmalloc_body(size_t size)
-RBIMPL_ATTR_NOEXCEPT(malloc(size))
-;
-
-RBIMPL_ATTR_NODISCARD()
-RBIMPL_ATTR_RESTRICT()
-RBIMPL_ATTR_RETURNS_NONNULL()
-RBIMPL_ATTR_ALLOC_SIZE((1,2))
-void *ruby_xmalloc2_body(size_t nelems, size_t elemsiz)
-RBIMPL_ATTR_NOEXCEPT(malloc(nelems * elemsiz))
-;
-
-RBIMPL_ATTR_NODISCARD()
-RBIMPL_ATTR_RESTRICT()
-RBIMPL_ATTR_RETURNS_NONNULL()
-RBIMPL_ATTR_ALLOC_SIZE((1,2))
-void *ruby_xcalloc_body(size_t nelems, size_t elemsiz)
-RBIMPL_ATTR_NOEXCEPT(calloc(nelems, elemsiz))
-;
-
-RBIMPL_ATTR_NODISCARD()
-RBIMPL_ATTR_RETURNS_NONNULL()
-RBIMPL_ATTR_ALLOC_SIZE((2))
-void *ruby_xrealloc_body(void *ptr, size_t newsiz)
-RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newsiz))
-;
-
-RBIMPL_ATTR_NODISCARD()
-RBIMPL_ATTR_RETURNS_NONNULL()
-RBIMPL_ATTR_ALLOC_SIZE((2,3))
-void *ruby_xrealloc2_body(void *ptr, size_t newelems, size_t newsiz)
-RBIMPL_ATTR_NOEXCEPT(realloc(ptr, newelems * newsiz))
-;
-
-RUBY_EXTERN const char *ruby_malloc_info_file;
-RUBY_EXTERN int ruby_malloc_info_line;
-
-static inline void *
-ruby_xmalloc_with_location(size_t s, const char *file, int line)
-{
- void *ptr;
- ruby_malloc_info_file = file;
- ruby_malloc_info_line = line;
- ptr = ruby_xmalloc_body(s);
- ruby_malloc_info_file = NULL;
- return ptr;
-}
-
-static inline void *
-ruby_xmalloc2_with_location(size_t s1, size_t s2, const char *file, int line)
-{
- void *ptr;
- ruby_malloc_info_file = file;
- ruby_malloc_info_line = line;
- ptr = ruby_xmalloc2_body(s1, s2);
- ruby_malloc_info_file = NULL;
- return ptr;
-}
-
-static inline void *
-ruby_xcalloc_with_location(size_t s1, size_t s2, const char *file, int line)
-{
- void *ptr;
- ruby_malloc_info_file = file;
- ruby_malloc_info_line = line;
- ptr = ruby_xcalloc_body(s1, s2);
- ruby_malloc_info_file = NULL;
- return ptr;
-}
-
-static inline void *
-ruby_xrealloc_with_location(void *ptr, size_t s, const char *file, int line)
-{
- void *rptr;
- ruby_malloc_info_file = file;
- ruby_malloc_info_line = line;
- rptr = ruby_xrealloc_body(ptr, s);
- ruby_malloc_info_file = NULL;
- return rptr;
-}
-
-static inline void *
-ruby_xrealloc2_with_location(void *ptr, size_t s1, size_t s2, const char *file, int line)
-{
- void *rptr;
- ruby_malloc_info_file = file;
- ruby_malloc_info_line = line;
- rptr = ruby_xrealloc2_body(ptr, s1, s2);
- ruby_malloc_info_file = NULL;
- return rptr;
-}
-#endif
-
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RBIMPL_XMALLOC_H */
diff --git a/include/ruby/io.h b/include/ruby/io.h
index 60029fedb6..ed0967abad 100644
--- a/include/ruby/io.h
+++ b/include/ruby/io.h
@@ -66,6 +66,21 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
struct stat;
struct timeval;
+#if defined(HAVE_STRUCT_STAT_ST_BIRTHTIMESPEC)
+# define RUBY_USE_STATX 0
+#elif defined(HAVE_STRUCT_STATX_STX_BTIME)
+# define RUBY_USE_STATX 1
+struct statx;
+#else
+# define RUBY_USE_STATX 0
+#endif
+
+#if RUBY_USE_STATX
+typedef struct statx rb_io_stat_data;
+#else
+typedef struct stat rb_io_stat_data;
+#endif
+
/**
* Indicates that a timeout has occurred while performing an IO operation.
*/
@@ -137,7 +152,145 @@ struct rb_io_encoding {
VALUE ecopts;
};
+/**
+ * @name Possible flags for ::rb_io_t::mode
+ *
+ * @{
+ */
+
+/** The IO is opened for reading. */
+#define FMODE_READABLE 0x00000001
+
+/** The IO is opened for writing. */
+#define FMODE_WRITABLE 0x00000002
+
+/** The IO is opened for both read/write. */
+#define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE)
+
+/**
+ * The IO is in "binary mode". This is not what everything rb_io_binmode()
+ * concerns. This low-level flag is to stop CR <-> CRLF conversions that would
+ * happen in the underlying operating system.
+ *
+ * Setting this one and #FMODE_TEXTMODE at the same time is a contradiction.
+ * Setting this one and #ECONV_NEWLINE_DECORATOR_MASK at the same time is also
+ * a contradiction.
+ */
+#define FMODE_BINMODE 0x00000004
+
+/**
+ * The IO is in "sync mode". All output is immediately flushed to the
+ * underlying operating system then. Can be set via rb_io_synchronized(), but
+ * there is no way except calling `IO#sync=` to reset.
+ */
+#define FMODE_SYNC 0x00000008
+
+/**
+ * The IO is a TTY. What is a TTY and what isn't depends on the underlying
+ * operating system's `isatty(3)` output. You cannot change this.
+ */
+#define FMODE_TTY 0x00000010
+
+/**
+ * Ruby eventually detects that the IO is bidirectional. For instance a TTY
+ * has such property. There are several other things known to be duplexed.
+ * Additionally you (extension library authors) can also implement your own
+ * bidirectional IO subclasses. One of such example is `Socket`.
+ */
+#define FMODE_DUPLEX 0x00000020
+
+/**
+ * The IO is opened for appending. This mode always writes at the end of the
+ * IO. Ruby manages this flag for record but basically the logic behind this
+ * mode is at the underlying operating system. We almost do nothing.
+ */
+#define FMODE_APPEND 0x00000040
+
+/**
+ * The IO is opened for creating. This makes sense only when the destination
+ * file does not exist at the time the IO object was created. This is the
+ * default mode for writing, but you can pass `"r+"` to `IO.open` etc., to
+ * reroute this creation.
+ */
+#define FMODE_CREATE 0x00000080
+/* #define FMODE_NOREVLOOKUP 0x00000100 */
+
+/**
+ * This flag amends the effect of #FMODE_CREATE, so that if there already is a
+ * file at the given path the operation fails. Using this you can be sure that
+ * the file you get is a fresh new one.
+ */
+#define FMODE_EXCL 0x00000400
+
+/**
+ * This flag amends the effect of #FMODE_CREATE, so that if there already is a
+ * file at the given path it gets truncated.
+ */
+#define FMODE_TRUNC 0x00000800
+
+/**
+ * The IO is in "text mode". On systems where such mode make sense, this flag
+ * changes the way the IO handles the contents. On POSIX systems it is
+ * basically a no-op, but with this flag set you can optionally let Ruby
+ * manually convert newlines, unlike when in binary mode:
+ *
+ * ```ruby
+ * IO.open("/p/a/t/h", "wt", crlf_newline: true) # "wb" is NG.
+ * ```
+ *
+ * Setting this one and #FMODE_BINMODE at the same time is a contradiction.
+ */
+#define FMODE_TEXTMODE 0x00001000
+/**
+ * This flag means that an IO object is wrapping an "external" file descriptor,
+ * which is owned by something outside the Ruby interpreter (usually a C extension).
+ * Ruby will not close this file when the IO object is garbage collected.
+ * If this flag is set, then IO#autoclose? is false, and vice-versa.
+ *
+ * This flag was previously called FMODE_PREP internally.
+ */
+#define FMODE_EXTERNAL 0x00010000
+
+/* #define FMODE_SIGNAL_ON_EPIPE 0x00020000 */
+
+/**
+ * This flag amends the encoding of the IO so that the BOM of the contents of
+ * the IO takes effect.
+ */
+#define FMODE_SETENC_BY_BOM 0x00100000
+/* #define FMODE_UNIX 0x00200000 */
+/* #define FMODE_INET 0x00400000 */
+/* #define FMODE_INET6 0x00800000 */
+
+/** @} */
+
+enum rb_io_mode {
+ RUBY_IO_MODE_EXTERNAL = FMODE_EXTERNAL,
+
+ RUBY_IO_MODE_READABLE = FMODE_READABLE,
+ RUBY_IO_MODE_WRITABLE = FMODE_WRITABLE,
+ RUBY_IO_MODE_READABLE_WRITABLE = (RUBY_IO_MODE_READABLE|RUBY_IO_MODE_WRITABLE),
+
+ RUBY_IO_MODE_BINARY = FMODE_BINMODE,
+ RUBY_IO_MODE_TEXT = FMODE_TEXTMODE,
+ RUBY_IO_MODE_TEXT_SET_ENCODING_FROM_BOM = FMODE_SETENC_BY_BOM,
+
+ RUBY_IO_MODE_SYNCHRONISED = FMODE_SYNC,
+
+ RUBY_IO_MODE_TTY = FMODE_TTY,
+
+ RUBY_IO_MODE_DUPLEX = FMODE_DUPLEX,
+
+ RUBY_IO_MODE_APPEND = FMODE_APPEND,
+ RUBY_IO_MODE_CREATE = FMODE_CREATE,
+ RUBY_IO_MODE_EXCLUSIVE = FMODE_EXCL,
+ RUBY_IO_MODE_TRUNCATE = FMODE_TRUNC,
+};
+
+typedef enum rb_io_mode rb_io_mode_t;
+
#ifndef HAVE_RB_IO_T
+#define HAVE_RB_IO_T 1
/** Ruby's IO, metadata and buffers. */
struct rb_io {
/** The IO's Ruby level counterpart. */
@@ -154,7 +307,7 @@ struct rb_io {
/** mode flags: FMODE_XXXs */
RBIMPL_ATTR_DEPRECATED(("rb_io_mode"))
- int mode;
+ enum rb_io_mode mode;
/** child's pid (for pipes) */
RBIMPL_ATTR_DEPRECATED(("with no replacement"))
@@ -260,118 +413,6 @@ typedef struct rb_io rb_io_t;
typedef struct rb_io_encoding rb_io_enc_t;
/**
- * @name Possible flags for ::rb_io_t::mode
- *
- * @{
- */
-
-/** The IO is opened for reading. */
-#define FMODE_READABLE 0x00000001
-
-/** The IO is opened for writing. */
-#define FMODE_WRITABLE 0x00000002
-
-/** The IO is opened for both read/write. */
-#define FMODE_READWRITE (FMODE_READABLE|FMODE_WRITABLE)
-
-/**
- * The IO is in "binary mode". This is not what everything rb_io_binmode()
- * concerns. This low-level flag is to stop CR <-> CRLF conversions that would
- * happen in the underlying operating system.
- *
- * Setting this one and #FMODE_TEXTMODE at the same time is a contradiction.
- * Setting this one and #ECONV_NEWLINE_DECORATOR_MASK at the same time is also
- * a contradiction.
- */
-#define FMODE_BINMODE 0x00000004
-
-/**
- * The IO is in "sync mode". All output is immediately flushed to the
- * underlying operating system then. Can be set via rb_io_synchronized(), but
- * there is no way except calling `IO#sync=` to reset.
- */
-#define FMODE_SYNC 0x00000008
-
-/**
- * The IO is a TTY. What is a TTY and what isn't depends on the underlying
- * operating system's `isatty(3)` output. You cannot change this.
- */
-#define FMODE_TTY 0x00000010
-
-/**
- * Ruby eventually detects that the IO is bidirectional. For instance a TTY
- * has such property. There are several other things known to be duplexed.
- * Additionally you (extension library authors) can also implement your own
- * bidirectional IO subclasses. One of such example is `Socket`.
- */
-#define FMODE_DUPLEX 0x00000020
-
-/**
- * The IO is opened for appending. This mode always writes at the end of the
- * IO. Ruby manages this flag for record but basically the logic behind this
- * mode is at the underlying operating system. We almost do nothing.
- */
-#define FMODE_APPEND 0x00000040
-
-/**
- * The IO is opened for creating. This makes sense only when the destination
- * file does not exist at the time the IO object was created. This is the
- * default mode for writing, but you can pass `"r+"` to `IO.open` etc., to
- * reroute this creation.
- */
-#define FMODE_CREATE 0x00000080
-/* #define FMODE_NOREVLOOKUP 0x00000100 */
-
-/**
- * This flag amends the effect of #FMODE_CREATE, so that if there already is a
- * file at the given path the operation fails. Using this you can be sure that
- * the file you get is a fresh new one.
- */
-#define FMODE_EXCL 0x00000400
-
-/**
- * This flag amends the effect of #FMODE_CREATE, so that if there already is a
- * file at the given path it gets truncated.
- */
-#define FMODE_TRUNC 0x00000800
-
-/**
- * The IO is in "text mode". On systems where such mode make sense, this flag
- * changes the way the IO handles the contents. On POSIX systems it is
- * basically a no-op, but with this flag set you can optionally let Ruby
- * manually convert newlines, unlike when in binary mode:
- *
- * ```ruby
- * IO.open("/p/a/t/h", "wt", crlf_newline: true) # "wb" is NG.
- * ```
- *
- * Setting this one and #FMODE_BINMODE at the same time is a contradiction.
- */
-#define FMODE_TEXTMODE 0x00001000
-/**
- * This flag means that an IO object is wrapping an "external" file descriptor,
- * which is owned by something outside the Ruby interpreter (usually a C extension).
- * Ruby will not close this file when the IO object is garbage collected.
- * If this flag is set, then IO#autoclose? is false, and vice-versa.
- *
- * This flag was previously called FMODE_PREP internally.
- */
-#define FMODE_EXTERNAL 0x00010000
-
-/* #define FMODE_SIGNAL_ON_EPIPE 0x00020000 */
-
-/**
- * This flag amends the encoding of the IO so that the BOM of the contents of
- * the IO takes effect.
- */
-#define FMODE_SETENC_BY_BOM 0x00100000
-/* #define FMODE_UNIX 0x00200000 */
-/* #define FMODE_INET 0x00400000 */
-/* #define FMODE_INET6 0x00800000 */
-
-/** @} */
-
-/**
* Allocate a new IO object, with the given file descriptor.
*/
VALUE rb_io_open_descriptor(VALUE klass, int descriptor, int mode, VALUE path, VALUE timeout, struct rb_io_encoding *encoding);
@@ -524,7 +565,7 @@ FILE *rb_fdopen(int fd, const char *modestr);
*
* rb_io_modestr_fmode() is not a pure function because it raises.
*/
-int rb_io_modestr_fmode(const char *modestr);
+enum rb_io_mode rb_io_modestr_fmode(const char *modestr);
/**
* Identical to rb_io_modestr_fmode(), except it returns a mixture of `O_`
@@ -779,7 +820,7 @@ int rb_io_mode(VALUE io);
* @post `enc2_p` is the specified external encoding.
* @post `fmode_p` is the specified set of `FMODE_` modes.
*/
-int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, int *fmode_p);
+int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **enc2_p, enum rb_io_mode *fmode_p);
/**
* This function can be seen as an extended version of
@@ -848,7 +889,7 @@ int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding **
* ) -> void
* ```
*/
-void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, int *fmode_p, rb_io_enc_t *convconfig_p);
+void rb_io_extract_modeenc(VALUE *vmode_p, VALUE *vperm_p, VALUE opthash, int *oflags_p, enum rb_io_mode *fmode_p, rb_io_enc_t *convconfig_p);
/* :TODO: can this function be __attribute__((warn_unused_result)) or not? */
/**
@@ -963,6 +1004,9 @@ VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout);
* }
* ```
*
+ * On timeout, ::RUBY_Qfalse is returned. Unless you are specifically handling
+ * the timeouts, you should typically raise ::rb_eIOTimeoutError in this case.
+ *
* @param[in] error System errno.
* @param[in] io An IO object to wait.
* @param[in] events An integer set of interests.
@@ -971,19 +1015,19 @@ VALUE rb_io_wait(VALUE io, VALUE events, VALUE timeout);
* @exception rb_eRangeError `timeout` is out of range.
* @exception rb_eSystemCallError `select(2)` failed for some reason.
* @retval RUBY_Qfalse Operation timed out.
+ * @retval RUBY_Qnil Operation failed for some other reason (errno).
* @retval Otherwise Actual events reached.
*
- * @internal
- *
- * This function to return ::RUBY_Qfalse on timeout could be unintended. It
- * seems timeout feature has some rough edge.
*/
VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout);
/**
* Blocks until the passed IO is ready for reading, if that makes sense for the
- * passed errno. This is a special case of rb_io_maybe_wait() that only
- * concerns for reading.
+ * passed errno. This is a special case of rb_io_maybe_wait() that is
+ * only concerned with reading and handles the timeout.
+ *
+ * If you do not want the default timeout handling, consider using
+ * ::rb_io_maybe_wait directly.
*
* @param[in] error System errno.
* @param[in] io An IO object to wait.
@@ -991,15 +1035,18 @@ VALUE rb_io_maybe_wait(int error, VALUE io, VALUE events, VALUE timeout);
* @exception rb_eIOError `io` is not open.
* @exception rb_eRangeError `timeout` is out of range.
* @exception rb_eSystemCallError `select(2)` failed for some reason.
- * @retval 0 Operation timed out.
+ * @exception rb_eIOTimeoutError The wait operation timed out.
* @retval Otherwise Always returns ::RUBY_IO_READABLE.
*/
int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout);
/**
* Blocks until the passed IO is ready for writing, if that makes sense for the
- * passed errno. This is a special case of rb_io_maybe_wait() that only
- * concernsfor writing.
+ * passed errno. This is a special case of rb_io_maybe_wait() that is
+ * only concerned with writing, and handles the timeout.
+ *
+ * If you do not want the default timeout handling, consider using
+ * ::rb_io_maybe_wait directly.
*
* @param[in] error System errno.
* @param[in] io An IO object to wait.
@@ -1007,7 +1054,7 @@ int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout);
* @exception rb_eIOError `io` is not open.
* @exception rb_eRangeError `timeout` is out of range.
* @exception rb_eSystemCallError `select(2)` failed for some reason.
- * @retval 0 Operation timed out.
+ * @exception rb_eIOTimeoutError The wait operation timed out.
* @retval Otherwise Always returns ::RUBY_IO_WRITABLE.
*/
int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout);
@@ -1066,6 +1113,18 @@ int rb_io_read_pending(rb_io_t *fptr);
*/
VALUE rb_stat_new(const struct stat *st);
+#if RUBY_USE_STATX
+/**
+ * Constructs an instance of ::rb_cStat from the passed information.
+ *
+ * @param[in] st A stat.
+ * @return Allocated new instance of ::rb_cStat.
+ */
+VALUE rb_statx_new(const rb_io_stat_data *st);
+#else
+# define rb_statx_new rb_stat_new
+#endif
+
/* gc.c */
RBIMPL_SYMBOL_EXPORT_END()
diff --git a/include/ruby/io/buffer.h b/include/ruby/io/buffer.h
index f2ab8f1195..e4d98bf051 100644
--- a/include/ruby/io/buffer.h
+++ b/include/ruby/io/buffer.h
@@ -23,10 +23,18 @@ RBIMPL_SYMBOL_EXPORT_BEGIN()
#define RUBY_IO_BUFFER_VERSION 2
+// The `IO::Buffer` class.
RUBY_EXTERN VALUE rb_cIOBuffer;
+
+// The operating system page size.
RUBY_EXTERN size_t RUBY_IO_BUFFER_PAGE_SIZE;
+
+// The default buffer size, usually a (small) multiple of the page size.
+// Can be overridden by the RUBY_IO_BUFFER_DEFAULT_SIZE environment variable.
RUBY_EXTERN size_t RUBY_IO_BUFFER_DEFAULT_SIZE;
+// Represents the internal state of the buffer.
+// More than one flag can be set at a time.
enum rb_io_buffer_flags {
// The memory in the buffer is owned by someone else.
// More specifically, it means that someone else owns the buffer and we shouldn't try to resize it.
@@ -49,21 +57,22 @@ enum rb_io_buffer_flags {
RB_IO_BUFFER_PRIVATE = 64,
// The buffer is read-only and cannot be modified.
- RB_IO_BUFFER_READONLY = 128
+ RB_IO_BUFFER_READONLY = 128,
+
+ // The buffer is backed by a file.
+ RB_IO_BUFFER_FILE = 256,
};
+// Represents the endian of the data types.
enum rb_io_buffer_endian {
+ // The least significant units are put first.
RB_IO_BUFFER_LITTLE_ENDIAN = 4,
RB_IO_BUFFER_BIG_ENDIAN = 8,
-#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
- RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_LITTLE_ENDIAN,
-#elif defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#if defined(WORDS_BIGENDIAN)
RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN,
-#elif defined(REG_DWORD) && REG_DWORD == REG_DWORD_LITTLE_ENDIAN
+#else
RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_LITTLE_ENDIAN,
-#elif defined(REG_DWORD) && REG_DWORD == REG_DWORD_BIG_ENDIAN
- RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN,
#endif
RB_IO_BUFFER_NETWORK_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN
@@ -79,7 +88,10 @@ int rb_io_buffer_try_unlock(VALUE self);
VALUE rb_io_buffer_free(VALUE self);
VALUE rb_io_buffer_free_locked(VALUE self);
-int rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size);
+// Access the internal buffer and flags. Validates the pointers.
+// The points may not remain valid if the source buffer is manipulated.
+// Consider using rb_io_buffer_lock if needed.
+enum rb_io_buffer_flags rb_io_buffer_get_bytes(VALUE self, void **base, size_t *size);
void rb_io_buffer_get_bytes_for_reading(VALUE self, const void **base, size_t *size);
void rb_io_buffer_get_bytes_for_writing(VALUE self, void **base, size_t *size);
diff --git a/include/ruby/memory_view.h b/include/ruby/memory_view.h
index 1ddca2d46f..42309d5afc 100644
--- a/include/ruby/memory_view.h
+++ b/include/ruby/memory_view.h
@@ -47,10 +47,10 @@ typedef struct {
char format;
/** :FIXME: what is a "native" size is unclear. */
- unsigned native_size_p: 1;
+ bool native_size_p;
/** Endian of the component */
- unsigned little_endian_p: 1;
+ bool little_endian_p;
/** The component's offset. */
size_t offset;
diff --git a/include/ruby/onigmo.h b/include/ruby/onigmo.h
index d233336316..9dcddee829 100644
--- a/include/ruby/onigmo.h
+++ b/include/ruby/onigmo.h
@@ -4,8 +4,8 @@
onigmo.h - Onigmo (Oniguruma-mod) (regular expression library)
**********************************************************************/
/*-
- * Copyright (c) 2002-2009 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
- * Copyright (c) 2011-2017 K.Takata <kentkt AT csc DOT jp>
+ * Copyright (c) 2002-2016 K.Kosako <sndgk393 AT ybb DOT ne DOT jp>
+ * Copyright (c) 2011-2019 K.Takata <kentkt AT csc DOT jp>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -38,8 +38,8 @@ extern "C" {
#endif
#define ONIGMO_VERSION_MAJOR 6
-#define ONIGMO_VERSION_MINOR 1
-#define ONIGMO_VERSION_TEENY 3
+#define ONIGMO_VERSION_MINOR 2
+#define ONIGMO_VERSION_TEENY 0
#ifndef ONIG_EXTERN
# ifdef RUBY_EXTERN
@@ -636,6 +636,7 @@ ONIG_EXTERN const OnigSyntaxType* OnigDefaultSyntax;
#define ONIGERR_PARSE_DEPTH_LIMIT_OVER -16
#define ONIGERR_DEFAULT_ENCODING_IS_NOT_SET -21
#define ONIGERR_SPECIFIED_ENCODING_CANT_CONVERT_TO_WIDE_CHAR -22
+#define ONIGERR_TIMEOUT -23
/* general error */
#define ONIGERR_INVALID_ARGUMENT -30
/* syntax error */
@@ -788,8 +789,8 @@ typedef struct re_pattern_buffer {
unsigned char *exact;
unsigned char *exact_end;
unsigned char map[ONIG_CHAR_TABLE_SIZE]; /* used as BM skip or char-map */
- int *int_map; /* BM skip for exact_len > 255 */
- int *int_map_backward; /* BM skip for backward search */
+ int *reserved1;
+ int *reserved2;
OnigDistance dmin; /* min-distance of exact or map */
OnigDistance dmax; /* max-distance of exact or map */
diff --git a/include/ruby/ractor.h b/include/ruby/ractor.h
index 7811616f6d..8cfca21621 100644
--- a/include/ruby/ractor.h
+++ b/include/ruby/ractor.h
@@ -217,7 +217,7 @@ VALUE rb_ractor_make_shareable(VALUE obj);
*
* @param[in] obj Arbitrary ruby object to duplicate.
* @exception rb_eRactorError Ractors cannot share `obj` by nature.
- * @return A deep copy of `obj` which is sharable among Ractors.
+ * @return A deep copy of `obj` which is shareable among Ractors.
*/
VALUE rb_ractor_make_shareable_copy(VALUE obj);
@@ -261,4 +261,18 @@ rb_ractor_shareable_p(VALUE obj)
}
}
+// TODO: optimize on interpreter core
+#ifndef RB_OBJ_SET_SHAREABLE
+VALUE rb_obj_set_shareable(VALUE obj); // ractor.c
+#define RB_OBJ_SET_SHAREABLE(obj) rb_obj_set_shareable(obj)
+#endif
+
+static inline VALUE
+RB_OBJ_SET_FROZEN_SHAREABLE(VALUE obj)
+{
+ RB_OBJ_FREEZE(obj);
+ RB_OBJ_SET_SHAREABLE(obj);
+ return obj;
+}
+
#endif /* RUBY_RACTOR_H */
diff --git a/include/ruby/random.h b/include/ruby/random.h
index 39bdb6f3e3..740be6bdad 100644
--- a/include/ruby/random.h
+++ b/include/ruby/random.h
@@ -11,7 +11,7 @@
*
* This is a set of APIs to roll your own subclass of ::rb_cRandom. An
* illustrative example of such PRNG can be found at
- * `ext/-test-/ramdom/loop.c`.
+ * `ext/-test-/random/loop.c`.
*/
#include "ruby/ruby.h"
@@ -332,7 +332,9 @@ RBIMPL_ATTR_PURE_UNLESS_DEBUG()
static inline const rb_random_interface_t *
rb_rand_if(VALUE obj)
{
+ RBIMPL_ASSERT_OR_ASSUME(RB_TYPE_P(obj, T_DATA));
RBIMPL_ASSERT_OR_ASSUME(RTYPEDDATA_P(obj));
+ RUBY_ASSERT(rb_typeddata_is_kind_of(obj, &rb_random_data_type));
const struct rb_data_type_struct *t = RTYPEDDATA_TYPE(obj);
const void *ret = t->data;
return RBIMPL_CAST((const rb_random_interface_t *)ret);
diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h
index eb9a7e4d0f..ca794bcaeb 100644
--- a/include/ruby/ruby.h
+++ b/include/ruby/ruby.h
@@ -97,8 +97,10 @@ VALUE rb_get_path(VALUE obj);
VALUE rb_get_path_no_checksafe(VALUE);
/**
- * @deprecated This macro is an alias of #FilePathValue now. The part that did
- * "String" was deleted. It remains here because of no harm.
+ * This macro actually does the same thing as #FilePathValue now. The "String"
+ * part indicates that this is for when a string is treated like a pathname,
+ * rather than the actual pathname on the file systems. For examples:
+ * `Dir.fnmatch?`, `File.join`, `File.basename`, etc.
*/
#define FilePathStringValue(v) ((v) = rb_get_path(v))
@@ -270,6 +272,124 @@ RBIMPL_ATTR_FORMAT(RBIMPL_PRINTF_FORMAT, 3, 0)
*/
int ruby_vsnprintf(char *str, size_t n, char const *fmt, va_list ap);
+#include <errno.h>
+
+/**
+ * @name Errno handling routines for userland threads
+ * @note POSIX chapter 2 section 3 states that for each thread of a process,
+ * the value of `errno` shall not be affected by function calls or
+ * assignments to `errno` by other threads.
+ *
+ * Soooo this `#define errno` below seems like a noob mistake at first sight.
+ * If you look at its actual implementation, the functions are just adding one
+ * level of indirection. It doesn't make any sense sorry? But yes! @ko1 told
+ * @shyouhei that this is inevitable.
+ *
+ * The ultimate reason is because Ruby now has N:M threads implemented.
+ * Threads of that sort change their context in user land. A function can be
+ * "transferred" between threads in middle of their executions. Let us for
+ * instance consider:
+ *
+ * ```cxx
+ * void foo()
+ * {
+ * auto i = errno;
+ * close(0);
+ * errno = i;
+ * }
+ * ```
+ *
+ * This function (if ran under our Ractor) could change its running thread at
+ * the `close` function. But the two `errno` invocations are different! Look
+ * how the source code above is compiled by clang 17 with `-O3` flag @ Linux:
+ *
+ * ```
+ * foo(int): # @foo(int)
+ * push rbp
+ * push r14
+ * push rbx
+ * mov ebx, edi
+ * call __errno_location@PLT
+ * mov r14, rax
+ * mov ebp, dword ptr [rax]
+ * mov edi, ebx
+ * call close@PLT
+ * mov dword ptr [r14], ebp
+ * pop rbx
+ * pop r14
+ * pop rbp
+ * ret
+ * ```
+ *
+ * Notice how `__errno_location@PLT` is `call`-ed only once. The compiler
+ * assumes that the location of `errno` does not change during a function call.
+ * Sadly this is no longer true for us. The `close@PLT` now changes threads,
+ * which should also change where `errno` is stored.
+ *
+ * With the `#define errno` below the compilation result changes to this:
+ *
+ * ```
+ * foo(int): # @foo(int)
+ * push rbp
+ * push rbx
+ * push rax
+ * mov ebx, edi
+ * call rb_errno_ptr()@PLT
+ * mov ebp, dword ptr [rax]
+ * mov edi, ebx
+ * call close@PLT
+ * call rb_errno_ptr()@PLT
+ * mov dword ptr [rax], ebp
+ * add rsp, 8
+ * pop rbx
+ * pop rbp
+ * ret
+ * ```
+ *
+ * Which fixes the problem.
+ */
+
+/**
+ * Identical to system `errno`.
+ *
+ * @return The last set `errno` number.
+ */
+int rb_errno(void);
+
+/**
+ * Set the errno.
+ *
+ * @param err New `errno`.
+ * @post `errno` is now set to `err`.
+ */
+void rb_errno_set(int err);
+
+/**
+ * The location of `errno`
+ *
+ * @return The (thread-specific) location of `errno`.
+ */
+int *rb_errno_ptr(void);
+
+/**
+ * Not sure if it is necessary for extension libraries but this is where the
+ * "bare" errno is located.
+ *
+ * @return The location of `errno`.
+ */
+static inline int *
+rb_orig_errno_ptr(void)
+{
+ return &errno;
+}
+
+#define rb_orig_errno errno /**< System-provided original `errno`. */
+#undef errno
+#define errno (*rb_errno_ptr()) /**< Ractor-aware version of `errno`. */
+
+/** @} */
+
+
/** @cond INTERNAL_MACRO */
#if RBIMPL_HAS_WARNING("-Wgnu-zero-variadic-macro-arguments")
# /* Skip it; clang -pedantic doesn't like the following */
@@ -306,6 +426,21 @@ __extension__({ \
# include "ruby/backward.h"
#endif
+#ifndef RUBY__ASAN_DEFAULT_OPTIONS
+# define RUBY__ASAN_DEFAULT_OPTIONS
+#endif
+
+#define RUBY_GLOBAL_SETUP \
+ RUBY__ASAN_DEFAULT_OPTIONS \
+ /* RUBY_GLOBAL_SETUP end */
+
+#if defined(__wasm__) && !defined(__EMSCRIPTEN__)
+int rb_wasm_rt_start(int (*)(int, char **), int, char **);
+# define ruby_start_main rb_wasm_rt_start
+#else
+# define ruby_start_main(main, argc, argv) main(argc, argv)
+#endif
+
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RUBY_RUBY_H */
diff --git a/include/ruby/st.h b/include/ruby/st.h
index ba69c066c9..f35ab43603 100644
--- a/include/ruby/st.h
+++ b/include/ruby/st.h
@@ -104,8 +104,6 @@ st_table *rb_st_init_table(const struct st_hash_type *);
#define st_init_table rb_st_init_table
st_table *rb_st_init_table_with_size(const struct st_hash_type *, st_index_t);
#define st_init_table_with_size rb_st_init_table_with_size
-st_table *rb_st_init_existing_table_with_size(st_table *tab, const struct st_hash_type *type, st_index_t size);
-#define st_init_existing_table_with_size rb_st_init_existing_table_with_size
st_table *rb_st_init_numtable(void);
#define st_init_numtable rb_st_init_numtable
st_table *rb_st_init_numtable_with_size(st_index_t);
@@ -162,8 +160,6 @@ void rb_st_cleanup_safe(st_table *, st_data_t);
#define st_cleanup_safe rb_st_cleanup_safe
void rb_st_clear(st_table *);
#define st_clear rb_st_clear
-st_table *rb_st_replace(st_table *new_tab, st_table *old_tab);
-#define st_replace rb_st_replace
st_table *rb_st_copy(st_table *);
#define st_copy rb_st_copy
CONSTFUNC(int rb_st_numcmp(st_data_t, st_data_t));
diff --git a/include/ruby/thread.h b/include/ruby/thread.h
index 0b5b1ca0f3..2fa01229e2 100644
--- a/include/ruby/thread.h
+++ b/include/ruby/thread.h
@@ -59,6 +59,19 @@
*/
#define RB_NOGVL_UBF_ASYNC_SAFE (0x2)
+/**
+ * Passing this flag to rb_nogvl() indicates that the passed function
+ * is safe to offload to a background thread or work pool. In other words, the
+ * function is safe to run using a fiber scheduler's `blocking_operation_wait`.
+ * hook.
+ *
+ * If your function depends on thread-local storage, or thread-specific data
+ * operations/data structures, you should not set this flag, as
+ * these operations may behave differently (or fail) when run in a different
+ * thread/context (e.g. unlocking a mutex).
+ */
+#define RB_NOGVL_OFFLOAD_SAFE (0x4)
+
/** @} */
RBIMPL_SYMBOL_EXPORT_BEGIN()
@@ -190,14 +203,59 @@ void *rb_nogvl(void *(*func)(void *), void *data1,
*/
#define RUBY_CALL_WO_GVL_FLAG_SKIP_CHECK_INTS_
-#define RUBY_INTERNAL_THREAD_EVENT_STARTED 1 << 0 /** thread started */
+/**
+ * Declare the current Ruby thread should acquire a dedicated
+ * native thread on M:N thread scheduler.
+ *
+ * If a C extension (or a library which the extension relies on) should
+ * keep to run on a native thread (e.g. using thread-local-storage),
+ * this function allocates a dedicated native thread for the thread.
+ *
+ * @return `false` if the thread already running on a dedicated native
+ * thread. Otherwise `true`.
+ */
+bool rb_thread_lock_native_thread(void);
+
+/**
+ * Triggered when a new thread is started.
+ *
+ * @note The callback will be called *without* the GVL held.
+ */
+#define RUBY_INTERNAL_THREAD_EVENT_STARTED 1 << 0
+
+/**
+* Triggered when a thread attempt to acquire the GVL.
+*
+* @note The callback will be called *without* the GVL held.
+*/
#define RUBY_INTERNAL_THREAD_EVENT_READY 1 << 1 /** acquiring GVL */
+
+/**
+ * Triggered when a thread successfully acquired the GVL.
+ *
+ * @note The callback will be called *with* the GVL held.
+ */
#define RUBY_INTERNAL_THREAD_EVENT_RESUMED 1 << 2 /** acquired GVL */
+
+/**
+ * Triggered when a thread released the GVL.
+ *
+ * @note The callback will be called *without* the GVL held.
+ */
#define RUBY_INTERNAL_THREAD_EVENT_SUSPENDED 1 << 3 /** released GVL */
+
+/**
+ * Triggered when a thread exits.
+ *
+ * @note The callback will be called *without* the GVL held.
+ */
#define RUBY_INTERNAL_THREAD_EVENT_EXITED 1 << 4 /** thread terminated */
+
#define RUBY_INTERNAL_THREAD_EVENT_MASK 0xff /** All Thread events */
-typedef void rb_internal_thread_event_data_t; // for future extension.
+typedef struct rb_internal_thread_event_data {
+ VALUE thread;
+} rb_internal_thread_event_data_t;
typedef void (*rb_internal_thread_event_callback)(rb_event_flag_t event,
const rb_internal_thread_event_data_t *event_data,
@@ -211,7 +269,12 @@ typedef struct rb_internal_thread_event_hook rb_internal_thread_event_hook_t;
* @param[in] events A set of events that `func` should run.
* @param[in] data Passed as-is to `func`.
* @return An opaque pointer to the hook, to unregister it later.
- * @note This functionality is a noop on Windows.
+ * @note This functionality is a noop on Windows and WebAssembly.
+ * @note The callback will be called without the GVL held, except for the
+ * RESUMED event.
+ * @note Callbacks are not guaranteed to be executed on the native threads
+ * that corresponds to the Ruby thread. To identify which Ruby thread
+ * the event refers to, you must use `event_data->thread`.
* @warning This function MUST not be called from a thread event callback.
*/
rb_internal_thread_event_hook_t *rb_internal_thread_add_event_hook(
@@ -223,13 +286,60 @@ rb_internal_thread_event_hook_t *rb_internal_thread_add_event_hook(
* Unregister the passed hook.
*
* @param[in] hook. The hook to unregister.
- * @return Wether the hook was found and unregistered.
- * @note This functionality is a noop on Windows.
+ * @return Whether the hook was found and unregistered.
+ * @note This functionality is a noop on Windows and WebAssembly.
* @warning This function MUST not be called from a thread event callback.
*/
bool rb_internal_thread_remove_event_hook(
rb_internal_thread_event_hook_t * hook);
+
+typedef int rb_internal_thread_specific_key_t;
+#define RB_INTERNAL_THREAD_SPECIFIC_KEY_MAX 8
+/**
+ * Create a key to store thread specific data.
+ *
+ * These APIs are designed for tools using
+ * rb_internal_thread_event_hook APIs.
+ *
+ * Note that only `RB_INTERNAL_THREAD_SPECIFIC_KEY_MAX` keys
+ * can be created. raises `ThreadError` if exceeded.
+ *
+ * Usage:
+ * // at initialize time:
+ * int tool_key; // gvar
+ * Init_tool() {
+ * tool_key = rb_internal_thread_specific_key_create();
+ * }
+ *
+ * // at any timing:
+ * rb_internal_thread_specific_set(thread, tool_key, per_thread_data);
+ * ...
+ * per_thread_data = rb_internal_thread_specific_get(thread, tool_key);
+ */
+rb_internal_thread_specific_key_t rb_internal_thread_specific_key_create(void);
+
+/**
+ * Get thread and tool specific data.
+ *
+ * This function is async signal safe and thread safe.
+ */
+void *rb_internal_thread_specific_get(VALUE thread_val, rb_internal_thread_specific_key_t key);
+
+/**
+ * Set thread and tool specific data.
+ *
+ * This function is async signal safe and thread safe.
+ */
+void rb_internal_thread_specific_set(VALUE thread_val, rb_internal_thread_specific_key_t key, void *data);
+
+/**
+ * Whether the current thread is holding the GVL.
+ *
+ * @return true if the current thread is holding the GVL, false otherwise.
+ */
+int ruby_thread_has_gvl_p(void);
+
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RUBY_THREAD_H */
diff --git a/include/ruby/util.h b/include/ruby/util.h
index ee11bc940a..12e69c4b80 100644
--- a/include/ruby/util.h
+++ b/include/ruby/util.h
@@ -33,7 +33,9 @@
RBIMPL_SYMBOL_EXPORT_BEGIN()
-/** an approximation of ceil(n * log10(2)), up to 65536 at least */
+/** an approximation of ceil(n * log10(2)), up to 1,048,576 (1<<20)
+ * without overflow within 32-bit calculation
+ */
#define DECIMAL_SIZE_OF_BITS(n) (((n) * 3010 + 9998) / 9999)
/** an approximation of decimal representation size for n-bytes */
diff --git a/include/ruby/version.h b/include/ruby/version.h
index 08c0aadb07..5bb381cea2 100644
--- a/include/ruby/version.h
+++ b/include/ruby/version.h
@@ -61,13 +61,13 @@
* doesn't mean a total rewrite. Practically when it comes to API versioning,
* major and minor version changes are equally catastrophic.
*/
-#define RUBY_API_VERSION_MAJOR 3
+#define RUBY_API_VERSION_MAJOR 4
/**
* Minor version. As of writing this version changes annually. Greater
* version doesn't mean "better"; they just mean years passed.
*/
-#define RUBY_API_VERSION_MINOR 3
+#define RUBY_API_VERSION_MINOR 1
/**
* Teeny version. This digit is kind of reserved these days. Kept 0 for the
diff --git a/include/ruby/vm.h b/include/ruby/vm.h
index 3458c28be7..8779780952 100644
--- a/include/ruby/vm.h
+++ b/include/ruby/vm.h
@@ -49,6 +49,13 @@ int ruby_vm_destruct(ruby_vm_t *vm);
*/
void ruby_vm_at_exit(void(*func)(ruby_vm_t *));
+/**
+ * Returns whether the Ruby VM will free all memory at shutdown.
+ *
+ * @return true if free-at-exit is enabled, false otherwise.
+ */
+bool ruby_free_at_exit_p(void);
+
RBIMPL_SYMBOL_EXPORT_END()
#endif /* RUBY_VM_H */
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index dfb56f4182..ae11a61481 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -30,14 +30,10 @@ extern "C++" { /* template without extern "C++" */
#if !defined(_WIN64) && !defined(WIN32)
#define WIN32
#endif
-#if defined(_MSC_VER) && _MSC_VER <= 1200
-#include <windows.h>
-#endif
#include <winsock2.h>
#include <ws2tcpip.h>
-#if !defined(_MSC_VER) || _MSC_VER >= 1400
+#include <mswsock.h>
#include <iphlpapi.h>
-#endif
#if defined(__cplusplus) && defined(_MSC_VER)
}
#endif
@@ -58,13 +54,7 @@ extern "C++" { /* template without extern "C++" */
#include <direct.h>
#include <process.h>
#include <time.h>
-#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200
-extern "C++" { /* template without extern "C++" */
-#endif
#include <math.h>
-#if defined(__cplusplus) && defined(_MSC_VER) && _MSC_VER == 1200
-}
-#endif
#include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -125,8 +115,30 @@ typedef unsigned int uintptr_t;
#define O_SHARE_DELETE 0x20000000 /* for rb_w32_open(), rb_w32_wopen() */
typedef int clockid_t;
-#define CLOCK_REALTIME 0
-#define CLOCK_MONOTONIC 1
+
+/*
+ * Since we use our versions in win32/win32.c, not to depend on yet
+ * another DLL, prefix our versions not to conflict with inline
+ * versions provided in time.h.
+ */
+#define clock_gettime rb_w32_clock_gettime
+#define clock_getres rb_w32_clock_getres
+
+#ifndef CLOCK_REALTIME
+# define CLOCK_REALTIME 0
+#endif
+#ifndef CLOCK_MONOTONIC
+# define CLOCK_MONOTONIC 1
+#endif
+#ifndef CLOCK_PROCESS_CPUTIME_ID
+# define CLOCK_PROCESS_CPUTIME_ID 2
+#endif
+#ifndef CLOCK_THREAD_CPUTIME_ID
+# define CLOCK_THREAD_CPUTIME_ID 3
+#endif
+#ifndef CLOCK_REALTIME_COARSE
+# define CLOCK_REALTIME_COARSE 4
+#endif
#undef utime
#undef lseek
@@ -250,7 +262,6 @@ struct ifaddrs {
#endif
extern void rb_w32_sysinit(int *, char ***);
-extern DWORD rb_w32_osid(void);
extern int flock(int fd, int oper);
extern int rb_w32_io_cancelable_p(int);
extern int rb_w32_is_socket(int);
@@ -294,7 +305,11 @@ extern void rb_w32_free_environ(char **);
extern int rb_w32_map_errno(DWORD);
extern const char *WSAAPI rb_w32_inet_ntop(int,const void *,char *,size_t);
extern int WSAAPI rb_w32_inet_pton(int,const char *,void *);
-extern DWORD rb_w32_osver(void);
+
+RBIMPL_ATTR_DEPRECATED(("as Windows 9x is not supported already"))
+static inline DWORD rb_w32_osid(void) {return VER_PLATFORM_WIN32_NT;}
+RBIMPL_ATTR_DEPRECATED(("by Windows Version Helper APIs"))
+extern DWORD rb_w32_osver(void);
extern int rb_w32_uchown(const char *, int, int);
extern int rb_w32_ulink(const char *, const char *);
@@ -330,7 +345,7 @@ extern int rb_w32_dup2(int, int);
#include <float.h>
-#if defined _MSC_VER && _MSC_VER >= 1800 && defined INFINITY
+#if defined _MSC_VER && defined INFINITY
#pragma warning(push)
#pragma warning(disable:4756)
static inline float
@@ -413,11 +428,6 @@ extern int rb_w32_utruncate(const char *path, rb_off_t length);
#define HAVE_TRUNCATE 1
#define truncate rb_w32_utruncate
-#if defined(_MSC_VER) && _MSC_VER >= 1400 && _MSC_VER < 1800
-#define strtoll _strtoi64
-#define strtoull _strtoui64
-#endif
-
/*
* stubs
*/