diff options
Diffstat (limited to 'include/ruby')
56 files changed, 1181 insertions, 638 deletions
diff --git a/include/ruby/assert.h b/include/ruby/assert.h index c9f2c3fbef..0c052363bc 100644 --- a/include/ruby/assert.h +++ b/include/ruby/assert.h @@ -103,7 +103,7 @@ # /* keep NDEBUG undefined */ #elif (RBIMPL_NDEBUG == 0) && (RBIMPL_RUBY_DEBUG == 0) -# /* The (*1) situation in avobe diagram. */ +# /* The (*1) situation in above diagram. */ # define RUBY_DEBUG 0 # define RUBY_NDEBUG 1 # define NDEBUG diff --git a/include/ruby/backward.h b/include/ruby/backward.h index e12f98ac47..f804c2c36e 100644 --- a/include/ruby/backward.h +++ b/include/ruby/backward.h @@ -13,59 +13,13 @@ #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")) -/* eval.c */ -RBIMPL_ATTR_DEPRECATED_SINCE(2.2) void rb_disable_super(); -RBIMPL_ATTR_DEPRECATED_SINCE(2.2) void rb_enable_super(); - -/* hash.c */ -RBIMPL_ATTR_DEPRECATED_SINCE(2.2) void rb_hash_iter_lev(); -RBIMPL_ATTR_DEPRECATED_SINCE(2.2) void rb_hash_ifnone(); - -/* string.c */ -RBIMPL_ATTR_DEPRECATED_SINCE(2.2) void rb_str_associate(); -RBIMPL_ATTR_DEPRECATED_SINCE(2.2) void rb_str_associated(); - -/* variable.c */ -RBIMPL_ATTR_DEPRECATED_SINCE(2.5) void rb_autoload(); - -/* eval.c */ -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.6) void rb_frozen_class_p(); -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.7) void rb_exec_end_proc(); - -/* error.c */ -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.3) void rb_compile_error(); -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.3) void rb_compile_error_with_enc(); -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.3) void rb_compile_error_append(); - -/* gc.c */ -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.7) void rb_gc_call_finalizer_at_exit(); - -/* signal.c */ -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.7) void rb_trap_exit(); - -/* struct.c */ -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.4) void rb_struct_ptr(); - -/* thread.c */ -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.7) void rb_clear_trace_func(); - -/* variable.c */ -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.7) void rb_generic_ivar_table(); -RBIMPL_ATTR_DEPRECATED_INTERNAL(2.6) NORETURN(VALUE rb_mod_const_missing(VALUE, VALUE)); +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) -/* for source code backward compatibility */ -RBIMPL_ATTR_DEPRECATED_SINCE(2.4) -static inline int -ruby_show_copyright_to_die(int exitcode) -{ - ruby_show_copyright(); - return exitcode; -} -#define ruby_show_copyright() /* defer EXIT_SUCCESS */ \ - (exit(ruby_show_copyright_to_die(EXIT_SUCCESS))) +# error RUBY_SHOW_COPYRIGHT_TO_DIE is deprecated #endif #endif /* RUBY_RUBY_BACKWARD_H */ diff --git a/include/ruby/backward/2/assume.h b/include/ruby/backward/2/assume.h index 265421df79..d148710127 100644 --- a/include/ruby/backward/2/assume.h +++ b/include/ruby/backward/2/assume.h @@ -24,8 +24,6 @@ #include "ruby/internal/assume.h" #include "ruby/internal/has/builtin.h" -#undef ASSUME /* Kill config.h definition */ -#undef UNREACHABLE /* Kill config.h definition */ #define ASSUME RBIMPL_ASSUME /**< @old{RBIMPL_ASSUME} */ #define UNREACHABLE RBIMPL_UNREACHABLE() /**< @old{RBIMPL_UNREACHABLE} */ #define UNREACHABLE_RETURN RBIMPL_UNREACHABLE_RETURN /**< @old{RBIMPL_UNREACHABLE_RETURN} */ diff --git a/include/ruby/debug.h b/include/ruby/debug.h index c88da9c43d..f95acdb17e 100644 --- a/include/ruby/debug.h +++ b/include/ruby/debug.h @@ -207,6 +207,17 @@ typedef VALUE (*rb_debug_inspector_func_t)(const rb_debug_inspector_t *dc, void VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data); /** + * Queries the backtrace object of the context. This is as if you call + * `caller_locations` at the point of debugger. + * + * @param[in] dc A debug context. + * @return An array of `Thread::Backtrace::Location` which represents the + * current point of execution at `dc`. + + */ +VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc); + +/** * Queries the current receiver of the passed context's upper frame. * * @param[in] dc A debug context. @@ -250,15 +261,27 @@ VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index); /** - * Queries the backtrace object of the context. This is as if you call - * `caller_locations` at the point of debugger. + * Queries the depth of the passed context's upper frame. * - * @param[in] dc A debug context. - * @return An array of `Thread::Backtrace::Location` which represents the - * current point of execution at `dc`. + * Note that the depth is not same as the frame index because debug_inspector + * skips some special frames but the depth counts all frames. + * + * @param[in] dc A debug context. + * @param[in] index Index of the frame from top to bottom. + * @exception rb_eArgError `index` out of range. + * @retval The depth at `index`-th frame in Integer. + */ +VALUE rb_debug_inspector_frame_depth(const rb_debug_inspector_t *dc, long index); + +// A macro to recognize `rb_debug_inspector_frame_depth()` is available or not +#define RB_DEBUG_INSPECTOR_FRAME_DEPTH(dc, index) rb_debug_inspector_frame_depth(dc, index) +/** + * Return current frmae depth. + * + * @retval The depth of the current frame in Integer. */ -VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc); +VALUE rb_debug_inspector_current_depth(void); /** @} */ diff --git a/include/ruby/fiber/scheduler.h b/include/ruby/fiber/scheduler.h index 093b936475..250b39b6df 100644 --- a/include/ruby/fiber/scheduler.h +++ b/include/ruby/fiber/scheduler.h @@ -11,18 +11,74 @@ */ #include "ruby/internal/config.h" +#include <errno.h> + #ifdef STDC_HEADERS #include <stddef.h> /* size_t */ #endif #include "ruby/ruby.h" #include "ruby/internal/dllexport.h" +#include "ruby/internal/arithmetic.h" RBIMPL_SYMBOL_EXPORT_BEGIN() +#define RUBY_FIBER_SCHEDULER_VERSION 2 + struct timeval; /** + * Wrap a `ssize_t` and `int errno` into a single `VALUE`. This interface should + * be used to safely capture results from system calls like `read` and `write`. + * + * You should use `rb_fiber_scheduler_io_result_apply` to unpack the result of + * this value and update `int errno`. + * + * You should not directly try to interpret the result value as it is considered + * an opaque representation. However, the general representation is an integer + * in the range of `[-int errno, size_t size]`. Linux generally restricts the + * result of system calls like `read` and `write` to `<= 2^31` which means this + * will typically fit within a single FIXNUM. + * + * @param[in] result The result of the system call. + * @param[in] error The value of `errno`. + * @return A `VALUE` which contains the result and/or errno. + */ +static inline VALUE +rb_fiber_scheduler_io_result(ssize_t result, int error) +{ + if (result == -1) { + return RB_INT2NUM(-error); + } + else { + return RB_SIZE2NUM(result); + } +} + +/** + * Apply an io result to the local thread, returning the value of the original + * system call that created it and updating `int errno`. + * + * You should not directly try to interpret the result value as it is considered + * an opaque representation. + * + * @param[in] result The `VALUE` which contains an errno and/or result size. + * @post Updates `int errno` with the value if negative. + * @return The original result of the system call. + */ +static inline ssize_t +rb_fiber_scheduler_io_result_apply(VALUE result) +{ + if (RB_FIXNUM_P(result) && RB_NUM2INT(result) < 0) { + errno = -RB_NUM2INT(result); + return -1; + } + else { + return RB_NUM2SIZE(result); + } +} + +/** * Queries the current scheduler of the current thread that is calling this * function. * @@ -90,7 +146,7 @@ VALUE rb_fiber_scheduler_make_timeout(struct timeval *timeout); VALUE rb_fiber_scheduler_close(VALUE scheduler); /** - * Nonblocking `sleep`. Depending on scheduler implementation, this for + * Non-blocking `sleep`. Depending on scheduler implementation, this for * instance switches to another fiber etc. * * @param[in] scheduler Target scheduler. @@ -118,7 +174,7 @@ int rb_fiber_scheduler_supports_process_wait(VALUE scheduler); #endif /** - * Nonblocking `waitpid`. Depending on scheduler implementation, this for + * Non-blocking `waitpid`. Depending on scheduler implementation, this for * instance switches to another fiber etc. * * @param[in] scheduler Target scheduler. @@ -129,7 +185,7 @@ int rb_fiber_scheduler_supports_process_wait(VALUE scheduler); VALUE rb_fiber_scheduler_process_wait(VALUE scheduler, rb_pid_t pid, int flags); /** - * Nonblocking wait for the passed "blocker", which is for instance + * Non-blocking wait for the passed "blocker", which is for instance * `Thread.join` or `Mutex.lock`. Depending on scheduler implementation, this * for instance switches to another fiber etc. * @@ -151,11 +207,11 @@ VALUE rb_fiber_scheduler_block(VALUE scheduler, VALUE blocker, VALUE timeout); VALUE rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber); /** - * Nonblocking version of rb_io_wait(). Depending on scheduler implementation, - * this for instance switches to another fiber etc. + * Non-blocking version of rb_io_wait(). Depending on scheduler + * implementation, this for instance switches to another fiber etc. * * The "events" here is a Ruby level integer, which is an OR-ed value of - * `IO::READABLE`, `IO::WRITable`, and `IO::PRIORITY`. + * `IO::READABLE`, `IO::WRITABLE`, and `IO::PRIORITY`. * * @param[in] scheduler Target scheduler. * @param[in] io An io object to wait. @@ -166,7 +222,7 @@ VALUE rb_fiber_scheduler_unblock(VALUE scheduler, VALUE blocker, VALUE fiber); VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE timeout); /** - * Nonblocking wait until the passed IO is ready for reading. This is a + * Non-blocking wait until the passed IO is ready for reading. This is a * special case of rb_fiber_scheduler_io_wait(), where the interest is * `IO::READABLE` and timeout is never. * @@ -177,7 +233,7 @@ VALUE rb_fiber_scheduler_io_wait(VALUE scheduler, VALUE io, VALUE events, VALUE VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io); /** - * Nonblocking wait until the passed IO is ready for writing. This is a + * Non-blocking wait until the passed IO is ready for writing. This is a * special case of rb_fiber_scheduler_io_wait(), where the interest is * `IO::WRITABLE` and timeout is never. * @@ -188,33 +244,117 @@ VALUE rb_fiber_scheduler_io_wait_readable(VALUE scheduler, VALUE io); VALUE rb_fiber_scheduler_io_wait_writable(VALUE scheduler, VALUE io); /** - * Nonblocking read from the passed IO. + * Non-blocking version of `IO.select`. + * + * It's possible that this will be emulated using a thread, so you should not + * rely on it for high performance. + * + * @param[in] scheduler Target scheduler. + * @param[in] readables An array of readable objects. + * @param[in] writables An array of writable objects. + * @param[in] exceptables An array of objects that might encounter exceptional conditions. + * @param[in] timeout Numeric timeout or nil. + * @return What `scheduler.io_select` returns, normally a 3-tuple of arrays of ready objects. + */ +VALUE rb_fiber_scheduler_io_select(VALUE scheduler, VALUE readables, VALUE writables, VALUE exceptables, VALUE timeout); + +/** + * Non-blocking version of `IO.select`, `argv` variant. + */ +VALUE rb_fiber_scheduler_io_selectv(VALUE scheduler, int argc, VALUE *argv); + +/** + * Non-blocking read from the passed IO. * * @param[in] scheduler Target scheduler. * @param[out] io An io object to read from. * @param[out] buffer Return buffer. - * @param[in] offset Offset inside of `buffer`. * @param[in] length Requested number of bytes to read. + * @param[in] offset The offset in the buffer to read to. + * @retval RUBY_Qundef `scheduler` doesn't have `#io_read`. + * @return otherwise What `scheduler.io_read` returns `[-errno, size]`. + */ +VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset); + +/** + * Non-blocking write to the passed IO. + * + * @param[in] scheduler Target scheduler. + * @param[out] io An io object to write to. + * @param[in] buffer What to write. + * @param[in] length Number of bytes to write. + * @param[in] offset The offset in the buffer to write from. + * @retval RUBY_Qundef `scheduler` doesn't have `#io_write`. + * @return otherwise What `scheduler.io_write` returns `[-errno, size]`. + */ +VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t length, size_t offset); + +/** + * Non-blocking read from the passed IO at the specified offset. + * + * @param[in] scheduler Target scheduler. + * @param[out] io An io object to read from. + * @param[in] from The offset in the given IO to read the data from. + * @param[out] buffer The buffer to read the data to. + * @param[in] length Requested number of bytes to read. + * @param[in] offset The offset in the buffer to read to. * @retval RUBY_Qundef `scheduler` doesn't have `#io_read`. * @return otherwise What `scheduler.io_read` returns. */ -VALUE rb_fiber_scheduler_io_read(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length); +VALUE rb_fiber_scheduler_io_pread(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset); /** - * Nonblocking write to the passed IO. + * Non-blocking write to the passed IO at the specified offset. + * + * @param[in] scheduler Target scheduler. + * @param[out] io An io object to write to. + * @param[in] from The offset in the given IO to write the data to. + * @param[in] buffer The buffer to write the data from. + * @param[in] length Number of bytes to write. + * @param[in] offset The offset in the buffer to write from. + * @retval RUBY_Qundef `scheduler` doesn't have `#io_write`. + * @return otherwise What `scheduler.io_write` returns. + */ +VALUE rb_fiber_scheduler_io_pwrite(VALUE scheduler, VALUE io, rb_off_t from, VALUE buffer, size_t length, size_t offset); + +/** + * Non-blocking read from the passed IO using a native buffer. + * + * @param[in] scheduler Target scheduler. + * @param[out] io An io object to read from. + * @param[out] buffer Return buffer. + * @param[in] size Size of the return buffer. + * @param[in] length Requested number of bytes to read. + * @retval RUBY_Qundef `scheduler` doesn't have `#io_read`. + * @return otherwise What `scheduler.io_read` returns. + */ +VALUE rb_fiber_scheduler_io_read_memory(VALUE scheduler, VALUE io, void *buffer, size_t size, size_t length); + +/** + * Non-blocking write to the passed IO using a native buffer. * * @param[in] scheduler Target scheduler. * @param[out] io An io object to write to. * @param[in] buffer What to write. - * @param[in] offset Offset inside of `buffer`. + * @param[in] size Size of the buffer. * @param[in] length Number of bytes to write. * @retval RUBY_Qundef `scheduler` doesn't have `#io_write`. * @return otherwise What `scheduler.io_write` returns. */ -VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_t offset, size_t length); +VALUE rb_fiber_scheduler_io_write_memory(VALUE scheduler, VALUE io, const void *buffer, size_t size, size_t length); + +/** + * Non-blocking close the given IO. + * + * @param[in] scheduler Target scheduler. + * @param[in] io An io object to close. + * @retval RUBY_Qundef `scheduler` doesn't have `#io_close`. + * @return otherwise What `scheduler.io_close` returns. + */ +VALUE rb_fiber_scheduler_io_close(VALUE scheduler, VALUE io); /** - * Nonblocking DNS lookup. + * Non-blocking DNS lookup. * * @param[in] scheduler Target scheduler. * @param[in] hostname A host name to query. @@ -223,6 +363,12 @@ VALUE rb_fiber_scheduler_io_write(VALUE scheduler, VALUE io, VALUE buffer, size_ */ VALUE rb_fiber_scheduler_address_resolve(VALUE scheduler, VALUE hostname); +/** + * Create and schedule a non-blocking fiber. + * + */ +VALUE rb_fiber_scheduler_fiber(VALUE scheduler, int argc, VALUE *argv, int kw_splat); + RBIMPL_SYMBOL_EXPORT_END() #endif /* RUBY_FIBER_SCHEDULER_H */ diff --git a/include/ruby/internal/abi.h b/include/ruby/internal/abi.h new file mode 100644 index 0000000000..44111a0055 --- /dev/null +++ b/include/ruby/internal/abi.h @@ -0,0 +1,58 @@ +#ifndef RUBY_ABI_H +#define RUBY_ABI_H + +#ifdef RUBY_ABI_VERSION /* should match the definition in config.h */ + +/* This number represents Ruby's ABI version. + * + * In development Ruby, it should be bumped every time an ABI incompatible + * change is introduced. This will force other developers to rebuild extension + * gems. + * + * The following cases are considered as ABI incompatible changes: + * - Changing any data structures. + * - Changing macros or inline functions causing a change in behavior. + * - Deprecating or removing function declarations. + * + * The following cases are NOT considered as ABI incompatible changes: + * - Any changes that does not involve the header files in the `include` + * directory. + * - Adding macros, inline functions, or function declarations. + * - Backwards compatible refactors. + * - Editing comments. + * + * In released versions of Ruby, this number is not defined since teeny + * versions of Ruby should guarantee ABI compatibility. + */ +#define RUBY_ABI_VERSION 3 + +/* Windows does not support weak symbols so ruby_abi_version will not exist + * in the shared library. */ +#if defined(HAVE_FUNC_WEAK) && !defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__) +# define RUBY_DLN_CHECK_ABI +#endif +#endif /* RUBY_ABI_VERSION */ + +#ifdef RUBY_DLN_CHECK_ABI + +# ifdef __cplusplus +extern "C" { +# endif + +RUBY_FUNC_EXPORTED unsigned long long __attribute__((weak)) +ruby_abi_version(void) +{ +# ifdef RUBY_ABI_VERSION + return RUBY_ABI_VERSION; +# else + return 0; +# endif +} + +# ifdef __cplusplus +} +# endif + +#endif + +#endif diff --git a/include/ruby/internal/anyargs.h b/include/ruby/internal/anyargs.h index 9d8d16fdab..e3e1b6166d 100644 --- a/include/ruby/internal/anyargs.h +++ b/include/ruby/internal/anyargs.h @@ -239,15 +239,16 @@ # define RBIMPL_ANYARGS_DISPATCH_rb_define_method_13(n) RBIMPL_ANYARGS_DISPATCH((n) == 13, rb_define_method_13, RBIMPL_ANYARGS_DISPATCH_rb_define_method_12(n)) # define RBIMPL_ANYARGS_DISPATCH_rb_define_method_14(n) RBIMPL_ANYARGS_DISPATCH((n) == 14, rb_define_method_14, RBIMPL_ANYARGS_DISPATCH_rb_define_method_13(n)) # define RBIMPL_ANYARGS_DISPATCH_rb_define_method_15(n) RBIMPL_ANYARGS_DISPATCH((n) == 15, rb_define_method_15, RBIMPL_ANYARGS_DISPATCH_rb_define_method_14(n)) -# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_singleton_method_m3, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_15(n)) -# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_protected_method_m3, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_15(n)) -# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_private_method_m3, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_15(n)) -# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_module_function_m3, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_15(n)) -# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_global_function_m3, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_15(n)) -# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_method_id_m3, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_15(n)) -# define RBIMPL_ANYARGS_DISPATCH_rb_define_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_method_m3, RBIMPL_ANYARGS_DISPATCH_rb_define_method_15(n)) +# define RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_singleton_method_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_singleton_method_15(n)) +# define RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_protected_method_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_protected_method_15(n)) +# define RBIMPL_ANYARGS_DISPATCH_rb_define_private_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_private_method_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_private_method_15(n)) +# define RBIMPL_ANYARGS_DISPATCH_rb_define_module_function(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_module_function_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_module_function_15(n)) +# define RBIMPL_ANYARGS_DISPATCH_rb_define_global_function(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_global_function_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_global_function_15(n)) +# define RBIMPL_ANYARGS_DISPATCH_rb_define_method_id(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_method_id_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_method_id_15(n)) +# define RBIMPL_ANYARGS_DISPATCH_rb_define_method(n, f) RBIMPL_ANYARGS_DISPATCH(RBIMPL_CFUNC_IS_rb_f_notimplement(f), rb_define_method_notimpl, RBIMPL_ANYARGS_DISPATCH_rb_define_method_15(n)) # define RBIMPL_ANYARGS_ATTRSET(sym) RBIMPL_ATTR_MAYBE_UNUSED() RBIMPL_ATTR_NONNULL(()) RBIMPL_ATTR_WEAKREF(sym) # define RBIMPL_ANYARGS_DECL(sym, ...) \ +RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _notimpl(__VA_ARGS__, VALUE(*)(int, const VALUE *, VALUE, VALUE), int); \ RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _m3(__VA_ARGS__, VALUE(*)(ANYARGS), int); \ RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _m2(__VA_ARGS__, VALUE(*)(VALUE, VALUE), int); \ RBIMPL_ANYARGS_ATTRSET(sym) static void sym ## _m1(__VA_ARGS__, VALUE(*)(int, union { VALUE *x; const VALUE *y; } __attribute__((__transparent_union__)), VALUE), int); \ diff --git a/include/ruby/internal/arithmetic.h b/include/ruby/internal/arithmetic.h index 3f7840c384..7ebb4a86f1 100644 --- a/include/ruby/internal/arithmetic.h +++ b/include/ruby/internal/arithmetic.h @@ -18,7 +18,8 @@ * 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 Conversion between C's arithmtic types and Ruby's numeric types. + * @brief Conversion between C's arithmetic types and Ruby's numeric + * types. */ #include "ruby/internal/arithmetic/char.h" #include "ruby/internal/arithmetic/double.h" diff --git a/include/ruby/internal/arithmetic/long.h b/include/ruby/internal/arithmetic/long.h index 792f7be179..6b8fd8ffc3 100644 --- a/include/ruby/internal/arithmetic/long.h +++ b/include/ruby/internal/arithmetic/long.h @@ -115,7 +115,7 @@ 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 k = 2 * j + RUBY_FIXNUM_FLAG; + const unsigned long k = (j << 1) + RUBY_FIXNUM_FLAG; const long l = k; const SIGNED_VALUE m = l; /* Sign extend */ const VALUE n = m; diff --git a/include/ruby/internal/assume.h b/include/ruby/internal/assume.h index 65d34d4ac8..4c183e8af9 100644 --- a/include/ruby/internal/assume.h +++ b/include/ruby/internal/assume.h @@ -32,10 +32,7 @@ #include "ruby/internal/warning_push.h" /** @cond INTERNAL_MACRO */ -#if RBIMPL_COMPILER_SINCE(MSVC, 13, 10, 0) -# define RBIMPL_HAVE___ASSUME - -#elif RBIMPL_COMPILER_SINCE(Intel, 13, 0, 0) +#if defined(HAVE___ASSUME) # define RBIMPL_HAVE___ASSUME #endif /** @endcond */ diff --git a/include/ruby/internal/attr/nodiscard.h b/include/ruby/internal/attr/nodiscard.h index 087192a7a8..c3ae118942 100644 --- a/include/ruby/internal/attr/nodiscard.h +++ b/include/ruby/internal/attr/nodiscard.h @@ -26,7 +26,7 @@ /** * Wraps (or simulates) `[[nodiscard]]`. In C++ (at least since C++20) a - * nodiscard attribute can have a message why the result shall not be ignoed. + * nodiscard attribute can have a message why the result shall not be ignored. * However GCC attribute and SAL annotation cannot take them. */ #if RBIMPL_HAS_CPP_ATTRIBUTE(nodiscard) diff --git a/include/ruby/internal/config.h b/include/ruby/internal/config.h index b6134c6165..aa63376d7c 100644 --- a/include/ruby/internal/config.h +++ b/include/ruby/internal/config.h @@ -113,6 +113,8 @@ # define UNALIGNED_WORD_ACCESS 1 #elif defined(__powerpc64__) # define UNALIGNED_WORD_ACCESS 1 +#elif defined(__POWERPC__) // __POWERPC__ is defined for ppc and ppc64 on Darwin +# define UNALIGNED_WORD_ACCESS 1 #elif defined(__aarch64__) # define UNALIGNED_WORD_ACCESS 1 #elif defined(__mc68020__) @@ -146,4 +148,8 @@ # undef RBIMPL_TEST3 #endif /* HAVE_VA_ARGS_MACRO */ +#ifndef USE_RVARGC +# define USE_RVARGC 1 +#endif + #endif /* RBIMPL_CONFIG_H */ diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h index 9f1d0509ea..c3bb40be25 100644 --- a/include/ruby/internal/core/rarray.h +++ b/include/ruby/internal/core/rarray.h @@ -130,7 +130,13 @@ enum ruby_rarray_flags { * 3rd parties must not be aware that there even is more than one way to * store array elements. It was a bad idea to expose this to them. */ +#if USE_RVARGC + RARRAY_EMBED_LEN_MASK = RUBY_FL_USER9 | RUBY_FL_USER8 | RUBY_FL_USER7 | RUBY_FL_USER6 | + RUBY_FL_USER5 | RUBY_FL_USER4 | RUBY_FL_USER3 +#else RARRAY_EMBED_LEN_MASK = RUBY_FL_USER4 | RUBY_FL_USER3 +#endif + #if USE_TRANSIENT_HEAP , @@ -156,10 +162,14 @@ enum ruby_rarray_flags { */ enum ruby_rarray_consts { /** Where ::RARRAY_EMBED_LEN_MASK resides. */ - RARRAY_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 3, + RARRAY_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 3 + +#if !USE_RVARGC + , /** Max possible number elements that can be embedded. */ RARRAY_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE) +#endif }; /** Ruby's array. */ @@ -218,7 +228,16 @@ struct RArray { * to store its elements. In this case the length is encoded into the * flags. */ +#if USE_RVARGC + /* This is a length 1 array because: + * 1. GCC has a bug that does not optimize C flexible array members + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452) + * 2. Zero length arrays are not supported by all compilers + */ + const VALUE ary[1]; +#else const VALUE ary[RARRAY_EMBED_LEN_MAX]; +#endif } as; }; @@ -469,14 +488,6 @@ rb_array_ptr_use_end(VALUE a, * This is an implementation detail of #RARRAY_PTR_USE. People do not use it * directly. */ -#define RARRAY_PTR_USE_START(a) rb_array_ptr_use_start(a, 0) - -/** - * @private - * - * This is an implementation detail of #RARRAY_PTR_USE. People do not use it - * directly. - */ #define RARRAY_PTR_USE_END(a) rb_array_ptr_use_end(a, 0) /** @@ -508,22 +519,6 @@ rb_array_ptr_use_end(VALUE a, RBIMPL_RARRAY_STMT(0, ary, ptr_name, expr) /** - * @private - * - * This is an implementation detail of #RARRAY_PTR_USE_TRANSIENT. People do - * not use it directly. - */ -#define RARRAY_PTR_USE_START_TRANSIENT(a) rb_array_ptr_use_start(a, 1) - -/** - * @private - * - * This is an implementation detail of #RARRAY_PTR_USE_TRANSIENT. People do - * not use it directly. - */ -#define RARRAY_PTR_USE_END_TRANSIENT(a) rb_array_ptr_use_end(a, 1) - -/** * Identical to #RARRAY_PTR_USE, except the pointer can be a transient one. * * @param ary An object of ::RArray. diff --git a/include/ruby/internal/core/rclass.h b/include/ruby/internal/core/rclass.h index 13a33a28bd..b0b6bfc80c 100644 --- a/include/ruby/internal/core/rclass.h +++ b/include/ruby/internal/core/rclass.h @@ -26,9 +26,7 @@ #include "ruby/internal/cast.h" /** @cond INTERNAL_MACRO */ -#define RMODULE_IS_OVERLAID RMODULE_IS_OVERLAID #define RMODULE_IS_REFINEMENT RMODULE_IS_REFINEMENT -#define RMODULE_INCLUDED_INTO_REFINEMENT RMODULE_INCLUDED_INTO_REFINEMENT /** @endcond */ /** @@ -55,57 +53,12 @@ * Why is it here, given RClass itself is not? */ enum ruby_rmodule_flags { - - /** - * This flag has something to do with refinements... I guess? It is set on - * occasions for modules that are refined by refinements, but it seems - * ... nobody cares about such things? Not sure but this flag could - * perhaps be a write-only information. - */ - RMODULE_IS_OVERLAID = RUBY_FL_USER2, - /** * This flag has something to do with refinements. A module created using * 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, - - /** - * This flag has something to do with refinements. This is set when a - * (non-refinement) module is included into another module, which is a - * refinement. This amends the way `super` searches for a super method. - * - * ```ruby - * class Foo - * def foo - * "Foo" - * end - * end - * - * module Bar - * def foo - * "[#{super}]" # this - * end - * end - * - * module Baz - * refine Foo do - * include Bar - * def foo - * "<#{super}>" - * end - * end - * end - * - * using Baz - * Foo.new.foo # => "[<Foo>]" - * ``` - * - * The `super` marked with "this" comment shall look for overlaid - * `Foo#foo`, which is not the ordinal method lookup direction. - */ - RMODULE_INCLUDED_INTO_REFINEMENT = RUBY_FL_USER4 + RMODULE_IS_REFINEMENT = RUBY_FL_USER3 }; 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 f6656b6546..43ab3c01e7 100644 --- a/include/ruby/internal/core/rdata.h +++ b/include/ruby/internal/core/rdata.h @@ -369,30 +369,6 @@ rb_data_object_alloc(VALUE klass, void *data, RUBY_DATA_FUNC dmark, RUBY_DATA_FU return rb_data_object_wrap(klass, data, dmark, dfree); } -RBIMPL_ATTR_DEPRECATED(("by: rb_cObject. Will be removed in 3.1.")) -RBIMPL_ATTR_PURE() -/** - * @private - * - * @deprecated There once was a variable called rb_cData, which no longer - * exists today. This function is a function because we want - * warnings for the usages. - */ -static inline VALUE -rb_cData(void) -{ - return rb_cObject; -} - -/** - * @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. - */ -#define rb_cData rb_cData() - /** @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 f2028063a6..b1c2e1b0a9 100644 --- a/include/ruby/internal/core/robject.h +++ b/include/ruby/internal/core/robject.h @@ -37,16 +37,15 @@ /** * Convenient casting macro. * - * @param obj An object, which is in fact an ::RRegexp. - * @return The passed object casted to ::RRegexp. + * @param obj An object, which is in fact an ::RObject. + * @return The passed object casted to ::RObject. */ #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_NUMIV ROBJECT_NUMIV +#define ROBJECT_IV_CAPACITY ROBJECT_IV_CAPACITY #define ROBJECT_IVPTR ROBJECT_IVPTR -#define ROBJECT_IV_INDEX_TBL ROBJECT_IV_INDEX_TBL /** @endcond */ /** @@ -75,6 +74,7 @@ enum ruby_robject_flags { ROBJECT_EMBED = RUBY_FL_USER1 }; +#if !USE_RVARGC /** * This is an enum because GDB wants it (rather than a macro). People need not * bother. @@ -83,6 +83,7 @@ enum ruby_robject_consts { /** Max possible number of instance variables that can be embedded. */ ROBJECT_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE) }; +#endif struct st_table; @@ -103,13 +104,6 @@ struct RObject { * this pattern. */ struct { - - /** - * Number of instance variables. This is per object; objects might - * differ in this field even if they have the identical classes. - */ - uint32_t numiv; - /** Pointer to a C array that holds instance variables. */ VALUE *ivptr; @@ -121,38 +115,35 @@ struct RObject { * * This is a shortcut for `RCLASS_IV_INDEX_TBL(rb_obj_class(obj))`. */ - struct st_table *iv_index_tbl; + struct rb_id_table *iv_index_tbl; } heap; - /** - * Embedded instance variables. When an object is small enough, it +#if USE_RVARGC + /* Embedded instance variables. When an object is small enough, it * uses this area to store the instance variables. + * + * This is a length 1 array because: + * 1. GCC has a bug that does not optimize C flexible array members + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452) + * 2. Zero length arrays are not supported by all compilers */ + VALUE ary[1]; +#else + /** + * Embedded instance variables. When an object is small enough, it + * uses this area to store the instance variables. + */ VALUE ary[ROBJECT_EMBED_LEN_MAX]; +#endif } as; }; -RBIMPL_ATTR_PURE_UNLESS_DEBUG() -RBIMPL_ATTR_ARTIFICIAL() -/** - * Queries the number of instance variables. - * - * @param[in] obj Object in question. - * @return Its number of instance variables. - * @pre `obj` must be an instance of ::RObject. - */ -static inline uint32_t -ROBJECT_NUMIV(VALUE obj) -{ - RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT); - - if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) { - return ROBJECT_EMBED_LEN_MAX; - } - else { - return ROBJECT(obj)->as.heap.numiv; - } -} +/* Offsets for YJIT */ +#ifndef __cplusplus +static const int32_t ROBJECT_OFFSET_AS_HEAP_IVPTR = offsetof(struct RObject, as.heap.ivptr); +static const int32_t ROBJECT_OFFSET_AS_HEAP_IV_INDEX_TBL = offsetof(struct RObject, as.heap.iv_index_tbl); +static const int32_t ROBJECT_OFFSET_AS_ARY = offsetof(struct RObject, as.ary); +#endif RBIMPL_ATTR_PURE_UNLESS_DEBUG() RBIMPL_ATTR_ARTIFICIAL() diff --git a/include/ruby/internal/core/rstring.h b/include/ruby/internal/core/rstring.h index d16a57b1c4..e394ab7dca 100644 --- a/include/ruby/internal/core/rstring.h +++ b/include/ruby/internal/core/rstring.h @@ -42,9 +42,11 @@ /** @cond INTERNAL_MACRO */ #define RSTRING_NOEMBED RSTRING_NOEMBED +#if !USE_RVARGC #define RSTRING_EMBED_LEN_MASK RSTRING_EMBED_LEN_MASK #define RSTRING_EMBED_LEN_SHIFT RSTRING_EMBED_LEN_SHIFT #define RSTRING_EMBED_LEN_MAX RSTRING_EMBED_LEN_MAX +#endif #define RSTRING_FSTR RSTRING_FSTR #define RSTRING_EMBED_LEN RSTRING_EMBED_LEN #define RSTRING_LEN RSTRING_LEN @@ -160,6 +162,7 @@ enum ruby_rstring_flags { */ RSTRING_NOEMBED = RUBY_FL_USER1, +#if !USE_RVARGC /** * When a string employs embedded strategy (see ::RSTRING_NOEMBED), these * bits are used to store the number of bytes actually filled into @@ -172,6 +175,7 @@ enum ruby_rstring_flags { */ RSTRING_EMBED_LEN_MASK = RUBY_FL_USER2 | RUBY_FL_USER3 | RUBY_FL_USER4 | RUBY_FL_USER5 | RUBY_FL_USER6, +#endif /* Actually, string encodings are also encoded into the flags, using * remaining bits.*/ @@ -198,6 +202,7 @@ enum ruby_rstring_flags { RSTRING_FSTR = RUBY_FL_USER17 }; +#if !USE_RVARGC /** * This is an enum because GDB wants it (rather than a macro). People need not * bother. @@ -209,6 +214,7 @@ enum ruby_rstring_consts { /** Max possible number of characters that can be embedded. */ RSTRING_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(char) - 1 }; +#endif /** * Ruby's String. A string in ruby conceptually has these information: @@ -271,14 +277,27 @@ struct RString { } aux; } heap; - /** - * Embedded contents. When a string is short enough, it uses this area - * to store the contents themselves. This was impractical in the 20th - * century, but these days 64 bit machines can typically hold 48 bytes - * here. Could be sufficiently large. In this case the length is - * encoded into the flags. - */ - char ary[RSTRING_EMBED_LEN_MAX + 1]; + /** Embedded contents. */ + struct { +#if USE_RVARGC + long len; + /* This is a length 1 array because: + * 1. GCC has a bug that does not optimize C flexible array members + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102452) + * 2. Zero length arrays are not supported by all compilers + */ + char ary[1]; +#else + /** + * When a string is short enough, it uses this area to store the + * contents themselves. This was impractical in the 20th century, + * but these days 64 bit machines can typically hold 24 bytes here. + * Could be sufficiently large. In this case the length is encoded + * into the flags. + */ + char ary[RSTRING_EMBED_LEN_MAX + 1]; +#endif + } embed; } as; }; @@ -406,10 +425,15 @@ RSTRING_EMBED_LEN(VALUE str) RBIMPL_ASSERT_TYPE(str, RUBY_T_STRING); RBIMPL_ASSERT_OR_ASSUME(! RB_FL_ANY_RAW(str, RSTRING_NOEMBED)); +#if USE_RVARGC + long f = RSTRING(str)->as.embed.len; + return f; +#else VALUE f = RBASIC(str)->flags; f &= RSTRING_EMBED_LEN_MASK; f >>= RSTRING_EMBED_LEN_SHIFT; return RBIMPL_CAST((long)f); +#endif } RBIMPL_WARNING_PUSH() @@ -440,7 +464,7 @@ rbimpl_rstring_getmem(VALUE str) /* Expecting compilers to optimize this on-stack struct away. */ struct RString retval; retval.as.heap.len = RSTRING_EMBED_LEN(str); - retval.as.heap.ptr = RSTRING(str)->as.ary; + retval.as.heap.ptr = RSTRING(str)->as.embed.ary; return retval; } } diff --git a/include/ruby/internal/encoding/ctype.h b/include/ruby/internal/encoding/ctype.h index 64aaf0a990..05c314aeb3 100644 --- a/include/ruby/internal/encoding/ctype.h +++ b/include/ruby/internal/encoding/ctype.h @@ -36,8 +36,8 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() * @param[in] p Pointer to a possibly-middle of a character. * @param[in] end End of the string. * @param[in] enc Encoding. - * @retval 0 It isn't. - * @retval otherwise It is. + * @retval false It isn't. + * @retval true It is. */ static inline bool rb_enc_is_newline(const char *p, const char *e, rb_encoding *enc) @@ -53,11 +53,11 @@ rb_enc_is_newline(const char *p, const char *e, rb_encoding *enc) * encoding. The "character type" here is a set of macros defined in onigmo.h, * like `ONIGENC_CTYPE_PUNCT`. * - * @param[in] c An `OnigCodePoint` value. - * @param[in] t An `OnigCtype` value. - * @param[in] enc A `rb_encoding*` value. - * @retval 1 `c` is of `t` in `enc`. - * @retval 0 Otherwise. + * @param[in] c An `OnigCodePoint` value. + * @param[in] t An `OnigCtype` value. + * @param[in] enc A `rb_encoding*` value. + * @retval true `c` is of `t` in `enc`. + * @retval false Otherwise. */ static inline bool rb_enc_isctype(OnigCodePoint c, OnigCtype t, rb_encoding *enc) @@ -68,10 +68,10 @@ rb_enc_isctype(OnigCodePoint c, OnigCtype t, rb_encoding *enc) /** * Identical to rb_isascii(), except it additionally takes an encoding. * - * @param[in] c A code point. - * @param[in] enc An encoding. - * @retval 0 `c` is out of range of ASCII character set in `enc`. - * @retval 1 Otherwise. + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval false `c` is out of range of ASCII character set in `enc`. + * @retval true Otherwise. * * @internal * @@ -87,10 +87,10 @@ rb_enc_isascii(OnigCodePoint c, rb_encoding *enc) /** * Identical to rb_isalpha(), except it additionally takes an encoding. * - * @param[in] c A code point. - * @param[in] enc An encoding. - * @retval 1 `enc` classifies `c` as "ALPHA". - * @retval 0 Otherwise. + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval true `enc` classifies `c` as "ALPHA". + * @retval false Otherwise. */ static inline bool rb_enc_isalpha(OnigCodePoint c, rb_encoding *enc) @@ -101,10 +101,10 @@ rb_enc_isalpha(OnigCodePoint c, rb_encoding *enc) /** * Identical to rb_islower(), except it additionally takes an encoding. * - * @param[in] c A code point. - * @param[in] enc An encoding. - * @retval 1 `enc` classifies `c` as "LOWER". - * @retval 0 Otherwise. + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval true `enc` classifies `c` as "LOWER". + * @retval false Otherwise. */ static inline bool rb_enc_islower(OnigCodePoint c, rb_encoding *enc) @@ -115,10 +115,10 @@ rb_enc_islower(OnigCodePoint c, rb_encoding *enc) /** * Identical to rb_isupper(), except it additionally takes an encoding. * - * @param[in] c A code point. - * @param[in] enc An encoding. - * @retval 1 `enc` classifies `c` as "UPPER". - * @retval 0 Otherwise. + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval true `enc` classifies `c` as "UPPER". + * @retval false Otherwise. */ static inline bool rb_enc_isupper(OnigCodePoint c, rb_encoding *enc) @@ -127,12 +127,26 @@ rb_enc_isupper(OnigCodePoint c, rb_encoding *enc) } /** + * Identical to rb_iscntrl(), except it additionally takes an encoding. + * + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval true `enc` classifies `c` as "CNTRL". + * @retval false Otherwise. + */ +static inline bool +rb_enc_iscntrl(OnigCodePoint c, rb_encoding *enc) +{ + return ONIGENC_IS_CODE_CNTRL(enc, c); +} + +/** * Identical to rb_ispunct(), except it additionally takes an encoding. * - * @param[in] c A code point. - * @param[in] enc An encoding. - * @retval 1 `enc` classifies `c` as "PUNCT". - * @retval 0 Otherwise. + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval true `enc` classifies `c` as "PUNCT". + * @retval false Otherwise. */ static inline bool rb_enc_ispunct(OnigCodePoint c, rb_encoding *enc) @@ -143,10 +157,10 @@ rb_enc_ispunct(OnigCodePoint c, rb_encoding *enc) /** * Identical to rb_isalnum(), except it additionally takes an encoding. * - * @param[in] c A code point. - * @param[in] enc An encoding. - * @retval 1 `enc` classifies `c` as "ANUM". - * @retval 0 Otherwise. + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval true `enc` classifies `c` as "ANUM". + * @retval false Otherwise. */ static inline bool rb_enc_isalnum(OnigCodePoint c, rb_encoding *enc) @@ -157,10 +171,10 @@ rb_enc_isalnum(OnigCodePoint c, rb_encoding *enc) /** * Identical to rb_isprint(), except it additionally takes an encoding. * - * @param[in] c A code point. - * @param[in] enc An encoding. - * @retval 1 `enc` classifies `c` as "PRINT". - * @retval 0 Otherwise. + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval true `enc` classifies `c` as "PRINT". + * @retval false Otherwise. */ static inline bool rb_enc_isprint(OnigCodePoint c, rb_encoding *enc) @@ -171,10 +185,10 @@ rb_enc_isprint(OnigCodePoint c, rb_encoding *enc) /** * Identical to rb_isspace(), except it additionally takes an encoding. * - * @param[in] c A code point. - * @param[in] enc An encoding. - * @retval 1 `enc` classifies `c` as "PRINT". - * @retval 0 Otherwise. + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval true `enc` classifies `c` as "PRINT". + * @retval false Otherwise. */ static inline bool rb_enc_isspace(OnigCodePoint c, rb_encoding *enc) @@ -185,10 +199,10 @@ rb_enc_isspace(OnigCodePoint c, rb_encoding *enc) /** * Identical to rb_isdigit(), except it additionally takes an encoding. * - * @param[in] c A code point. - * @param[in] enc An encoding. - * @retval 1 `enc` classifies `c` as "DIGIT". - * @retval 0 Otherwise. + * @param[in] c A code point. + * @param[in] enc An encoding. + * @retval true `enc` classifies `c` as "DIGIT". + * @retval false Otherwise. */ static inline bool rb_enc_isdigit(OnigCodePoint c, rb_encoding *enc) @@ -235,6 +249,7 @@ RBIMPL_SYMBOL_EXPORT_END() #define rb_enc_isdigit rb_enc_isdigit #define rb_enc_islower rb_enc_islower #define rb_enc_isprint rb_enc_isprint +#define rb_enc_iscntrl rb_enc_iscntrl #define rb_enc_ispunct rb_enc_ispunct #define rb_enc_isspace rb_enc_isspace #define rb_enc_isupper rb_enc_isupper diff --git a/include/ruby/internal/encoding/encoding.h b/include/ruby/internal/encoding/encoding.h index 33f7f27fc1..4748ca806b 100644 --- a/include/ruby/internal/encoding/encoding.h +++ b/include/ruby/internal/encoding/encoding.h @@ -65,16 +65,16 @@ enum ruby_encoding_consts { #define ENCODING_INLINE_MAX RUBY_ENCODING_INLINE_MAX /**< @old{RUBY_ENCODING_INLINE_MAX} */ #define ENCODING_SHIFT RUBY_ENCODING_SHIFT /**< @old{RUBY_ENCODING_SHIFT} */ -#define ENCODING_MASK RUBY_ENCODING_MASK /**< @old{RUBY_ENCODING_SHIFT} */ +#define ENCODING_MASK RUBY_ENCODING_MASK /**< @old{RUBY_ENCODING_MASK} */ /** * Destructively assigns the passed encoding to the passed object. The object * must be capable of having inline encoding. Using this macro needs deep * understanding of bit level object binary layout. * - * @param[out] obj Target object to modify. - * @param[in] i Encoding in encindex format. - * @post `obj`'s encoding is `i`. + * @param[out] obj Target object to modify. + * @param[in] ecindex Encoding in encindex format. + * @post `obj`'s encoding is `encindex`. */ static inline void RB_ENCODING_SET_INLINED(VALUE obj, int encindex) @@ -375,8 +375,8 @@ rb_encoding *rb_enc_check(VALUE str1,VALUE str2); VALUE rb_enc_associate_index(VALUE obj, int encindex); /** - * Identical to rb_enc_associate(), except it takes an encoding itself instead - * of its index. + * Identical to rb_enc_associate_index(), except it takes an encoding itself + * instead of its index. * * @param[out] obj Object in question. * @param[in] enc An encoding. @@ -626,10 +626,10 @@ int rb_enc_codelen(int code, rb_encoding *enc); /** * Identical to rb_enc_codelen(), except it returns 0 for invalid code points. * - * @param[in] code Code point in question. - * @param[in] enc Encoding to convert the code into a byte sequence. - * @retval 0 `code` is invalid. - * @return otherwise Number of bytes used for `enc` to encode `code`. + * @param[in] c Code point in question. + * @param[in] enc Encoding to convert `c` into a byte sequence. + * @retval 0 `c` is invalid. + * @return otherwise Number of bytes needed for `enc` to encode `c`. */ static inline int rb_enc_code_to_mbclen(int c, rb_encoding *enc) @@ -643,10 +643,12 @@ rb_enc_code_to_mbclen(int c, rb_encoding *enc) * Identical to rb_enc_uint_chr(), except it writes back to the passed buffer * instead of allocating one. * - * @param[in] c Code point. - * @param[out] buf Return buffer. - * @param[in] enc Target encoding scheme. - * @post `c` is encoded according to `enc`, then written to `buf`. + * @param[in] c Code point. + * @param[out] buf Return buffer. + * @param[in] enc Target encoding scheme. + * @retval <= 0 `c` is invalid in `enc`. + * @return otherwise Number of bytes written to `buf`. + * @post `c` is encoded according to `enc`, then written to `buf`. * * @internal * diff --git a/include/ruby/internal/encoding/string.h b/include/ruby/internal/encoding/string.h index f8ce809199..6ed7ca1c90 100644 --- a/include/ruby/internal/encoding/string.h +++ b/include/ruby/internal/encoding/string.h @@ -190,7 +190,7 @@ VALUE rb_enc_str_buf_cat(VALUE str, const char *ptr, long len, rb_encoding *enc) * In other languages, APIs like this one could be seen as the primitive * routines where encodings' "encode" feature are implemented. However in case * of Ruby this is not the primitive one. We directly manipulate encoded - * strings. Encoding conversion routines transocde an encoded string directly + * strings. Encoding conversion routines transcode an encoded string directly * to another one; not via a code point array. */ VALUE rb_enc_uint_chr(unsigned int code, rb_encoding *enc); diff --git a/include/ruby/internal/encoding/transcode.h b/include/ruby/internal/encoding/transcode.h index 60c96a41c9..7f26d2eae9 100644 --- a/include/ruby/internal/encoding/transcode.h +++ b/include/ruby/internal/encoding/transcode.h @@ -476,16 +476,16 @@ enum ruby_econv_flag_type { RUBY_ECONV_UNDEF_HEX_CHARREF = 0x00000030, /** Decorators are there. */ - RUBY_ECONV_DECORATOR_MASK = 0x0000ff00, + RUBY_ECONV_DECORATOR_MASK = 0x0001ff00, /** Newline converters are there. */ - RUBY_ECONV_NEWLINE_DECORATOR_MASK = 0x00003f00, + RUBY_ECONV_NEWLINE_DECORATOR_MASK = 0x00007f00, /** (Unclear; seems unused). */ RUBY_ECONV_NEWLINE_DECORATOR_READ_MASK = 0x00000f00, /** (Unclear; seems unused). */ - RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK = 0x00003000, + RUBY_ECONV_NEWLINE_DECORATOR_WRITE_MASK = 0x00007000, /** Universal newline mode. */ RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR = 0x00000100, @@ -496,11 +496,14 @@ enum ruby_econv_flag_type { /** CRLF to CR conversion shall happen. */ RUBY_ECONV_CR_NEWLINE_DECORATOR = 0x00002000, + /** CRLF to LF conversion shall happen. */ + RUBY_ECONV_LF_NEWLINE_DECORATOR = 0x00004000, + /** Texts shall be XML-escaped. */ - RUBY_ECONV_XML_TEXT_DECORATOR = 0x00004000, + RUBY_ECONV_XML_TEXT_DECORATOR = 0x00008000, /** Texts shall be AttrValue escaped */ - RUBY_ECONV_XML_ATTR_CONTENT_DECORATOR = 0x00008000, + RUBY_ECONV_XML_ATTR_CONTENT_DECORATOR = 0x00010000, /** (Unclear; seems unused). */ RUBY_ECONV_STATEFUL_DECORATOR_MASK = 0x00f00000, @@ -529,6 +532,7 @@ enum ruby_econv_flag_type { #define ECONV_UNIVERSAL_NEWLINE_DECORATOR RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR /**< @old{RUBY_ECONV_UNIVERSAL_NEWLINE_DECORATOR} */ #define ECONV_CRLF_NEWLINE_DECORATOR RUBY_ECONV_CRLF_NEWLINE_DECORATOR /**< @old{RUBY_ECONV_CRLF_NEWLINE_DECORATOR} */ #define ECONV_CR_NEWLINE_DECORATOR RUBY_ECONV_CR_NEWLINE_DECORATOR /**< @old{RUBY_ECONV_CR_NEWLINE_DECORATOR} */ +#define ECONV_LF_NEWLINE_DECORATOR RUBY_ECONV_LF_NEWLINE_DECORATOR /**< @old{RUBY_ECONV_LF_NEWLINE_DECORATOR} */ #define ECONV_XML_TEXT_DECORATOR RUBY_ECONV_XML_TEXT_DECORATOR /**< @old{RUBY_ECONV_XML_TEXT_DECORATOR} */ #define ECONV_XML_ATTR_CONTENT_DECORATOR RUBY_ECONV_XML_ATTR_CONTENT_DECORATOR /**< @old{RUBY_ECONV_XML_ATTR_CONTENT_DECORATOR} */ #define ECONV_STATEFUL_DECORATOR_MASK RUBY_ECONV_STATEFUL_DECORATOR_MASK /**< @old{RUBY_ECONV_STATEFUL_DECORATOR_MASK} */ @@ -543,10 +547,10 @@ enum ruby_econv_flag_type { */ /** Indicates the input is a part of much larger one. */ - RUBY_ECONV_PARTIAL_INPUT = 0x00010000, + RUBY_ECONV_PARTIAL_INPUT = 0x00020000, /** Instructs the converter to stop after output. */ - RUBY_ECONV_AFTER_OUTPUT = 0x00020000, + RUBY_ECONV_AFTER_OUTPUT = 0x00040000, #define ECONV_PARTIAL_INPUT RUBY_ECONV_PARTIAL_INPUT /**< @old{RUBY_ECONV_PARTIAL_INPUT} */ #define ECONV_AFTER_OUTPUT RUBY_ECONV_AFTER_OUTPUT /**< @old{RUBY_ECONV_AFTER_OUTPUT} */ diff --git a/include/ruby/internal/eval.h b/include/ruby/internal/eval.h index 34a53849da..5bcbb97746 100644 --- a/include/ruby/internal/eval.h +++ b/include/ruby/internal/eval.h @@ -28,10 +28,12 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() RBIMPL_ATTR_NONNULL(()) /** - * Evaluates the given string in an isolated binding. + * Evaluates the given string. * - * Here "isolated" means that the binding does not inherit any other - * bindings. This behaves same as the binding for required libraries. + * In case it is called from within a C-backended method, the evaluation is + * done under the current binding. However there can be no method. On such + * situation this function evaluates in an isolated binding, like `require` + * runs in a separate one. * * `__FILE__` will be `"(eval)"`, and `__LINE__` starts from 1 in the * evaluation. @@ -39,6 +41,31 @@ RBIMPL_ATTR_NONNULL(()) * @param[in] str Ruby code to evaluate. * @exception rb_eException Raises an exception on error. * @return The evaluated result. + * + * @internal + * + * @shyouhei's old tale about the birth and growth of this function: + * + * At the beginning, there was no rb_eval_string(). @shyouhei heard that + * @shugo, author of Apache httpd's mod_ruby module, requested @matz for this + * API. He wanted a way so that mod_ruby can evaluate ruby scripts one by one, + * separately, in each different contexts. So this function was made. It was + * designed to be a global interpreter entry point like ruby_run_node(). + * + * The way it is implemented however allows extension libraries (not just + * programs like Apache httpd) to call this function. Because its name says + * nothing about the initial design, people started to think of it as an + * orthodox way to call ruby level `eval` method from their extension + * libraries. Even our `extension.rdoc` has had a description of this function + * basically according to this understanding. + * + * The old (mod_ruby like) usage still works. But over time, usages of this + * function from extension libraries got popular, while mod_ruby faded out; is + * no longer maintained now. Devs decided to actively support both. This + * function now auto-detects how it is called, and switches how it works + * depending on it. + * + * @see https://bugs.ruby-lang.org/issues/18780 */ VALUE rb_eval_string(const char *str); diff --git a/include/ruby/internal/fl_type.h b/include/ruby/internal/fl_type.h index 47f054256b..7383426b23 100644 --- a/include/ruby/internal/fl_type.h +++ b/include/ruby/internal/fl_type.h @@ -183,7 +183,7 @@ RB_GNUC_EXTENSION * @note About the `FL_USER` terminology: the "user" here does not necessarily * mean only you. For instance struct ::RString instances use these * bits to cache their encodings etc. Devs discussed about this topic, - * reached their concensus that ::RUBY_T_DATA is the only valid data + * reached their consensus that ::RUBY_T_DATA is the only valid data * structure that can use these bits; other data structures including * ::RUBY_T_OBJECT use these bits for their own purpose. See also * https://bugs.ruby-lang.org/issues/18059 @@ -451,12 +451,6 @@ enum { RBIMPL_SYMBOL_EXPORT_BEGIN() /** - * @deprecated Does nothing. This method is deprecated and will be removed in - * Ruby 3.2. - */ -void rb_obj_infect(VALUE victim, VALUE carrier); - -/** * This is an implementation detail of #RB_OBJ_FREEZE(). People don't use it * directly. * @@ -947,21 +941,8 @@ RB_OBJ_FREEZE_RAW(VALUE obj) RB_FL_SET_RAW(obj, RUBY_FL_FREEZE); } -/** - * Prevents further modifications to the given object. ::rb_eFrozenError shall - * be raised if modification is attempted. - * - * @param[out] x Object in question. - */ -static inline void -rb_obj_freeze_inline(VALUE x) -{ - if (RB_FL_ABLE(x)) { - RB_OBJ_FREEZE_RAW(x); - if (RBASIC_CLASS(x) && !(RBASIC(x)->flags & RUBY_FL_SINGLETON)) { - rb_freeze_singleton_class(x); - } - } -} +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/has/builtin.h b/include/ruby/internal/has/builtin.h index 957aff8375..243ba2a34c 100644 --- a/include/ruby/internal/has/builtin.h +++ b/include/ruby/internal/has/builtin.h @@ -53,8 +53,10 @@ # define RBIMPL_HAS_BUILTIN___builtin_assume 0 # /* See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=52624 for bswap16. */ # define RBIMPL_HAS_BUILTIN___builtin_bswap16 RBIMPL_COMPILER_SINCE(GCC, 4, 8, 0) +#ifndef __OpenBSD__ # define RBIMPL_HAS_BUILTIN___builtin_bswap32 RBIMPL_COMPILER_SINCE(GCC, 3, 6, 0) # define RBIMPL_HAS_BUILTIN___builtin_bswap64 RBIMPL_COMPILER_SINCE(GCC, 3, 6, 0) +#endif # define RBIMPL_HAS_BUILTIN___builtin_clz RBIMPL_COMPILER_SINCE(GCC, 3, 6, 0) # define RBIMPL_HAS_BUILTIN___builtin_clzl RBIMPL_COMPILER_SINCE(GCC, 3, 6, 0) # define RBIMPL_HAS_BUILTIN___builtin_clzll RBIMPL_COMPILER_SINCE(GCC, 3, 6, 0) @@ -76,10 +78,6 @@ # define RBIMPL_HAS_BUILTIN___builtin_unreachable RBIMPL_COMPILER_SINCE(GCC, 4, 5, 0) # /* Note that "0, 0, 0" might be inaccurate. */ -#elif RBIMPL_COMPILER_IS(MSVC) -# /* MSVC has UNREACHABLE, but that is not __builtin_unreachable. */ -# define RBIMPL_HAS_BUILTIN(_) 0 - #else # /* Take config.h definition when available */ # define RBIMPL_HAS_BUILTIN(_) ((RBIMPL_HAS_BUILTIN_ ## _)+0) @@ -109,7 +107,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 -# if defined(UNREACHABLE) +# if defined(HAVE___BUILTIN_UNREACHABLE) # define RBIMPL_HAS_BUILTIN___builtin_unreachable 1 # else # define RBIMPL_HAS_BUILTIN___builtin_unreachable 0 diff --git a/include/ruby/internal/intern/array.h b/include/ruby/internal/intern/array.h index 17964bf810..2262c6f0c6 100644 --- a/include/ruby/internal/intern/array.h +++ b/include/ruby/internal/intern/array.h @@ -107,14 +107,14 @@ VALUE rb_ary_new_from_args(long n, ...); VALUE rb_ary_new_from_values(long n, const VALUE *elts); /** - * Allocates a "temporary" array. This is a hidden empty array. Handy on - * occasions. + * Allocates a hidden (no class) empty array. * * @param[in] capa Designed capacity of the array. * @return A hidden, empty array. * @see rb_obj_hide() */ -VALUE rb_ary_tmp_new(long capa); +VALUE rb_ary_hidden_new(long capa); +#define rb_ary_tmp_new rb_ary_hidden_new /** * Destroys the given array for no reason. diff --git a/include/ruby/internal/intern/class.h b/include/ruby/internal/intern/class.h index 60baf98472..0fb2d001bc 100644 --- a/include/ruby/internal/intern/class.h +++ b/include/ruby/internal/intern/class.h @@ -158,7 +158,7 @@ VALUE rb_mod_included_modules(VALUE mod); VALUE rb_mod_include_p(VALUE child, VALUE parent); /** - * Queries the module's ancestors. This routine gathers classes and modules + * Queries the module's ancestors. This routine gathers classes and modules * that the passed module either inherits, includes, or prepends, then * recursively applies that routine again and again to the collected entries * until the list doesn't grow up. @@ -175,6 +175,44 @@ VALUE rb_mod_include_p(VALUE child, VALUE parent); VALUE rb_mod_ancestors(VALUE mod); /** + * Queries the class's descendants. This routine gathers classes that are + * subclasses of the given class (or subclasses of those subclasses, etc.), + * returning an array of classes that have the given class as an ancestor. + * The returned array does not include the given class or singleton classes. + * + * @param[in] klass A class. + * @return An array of classes where `klass` is an ancestor. + * + * @internal + */ +VALUE rb_class_descendants(VALUE klass); + +/** + * Queries the class's direct descendants. This routine gathers classes that are + * direct subclasses of the given class, + * returning an array of classes that have the given class as a superclass. + * The returned array does not include singleton classes. + * + * @param[in] klass A class. + * @return An array of classes where `klass` is the `superclass`. + * + * @internal + */ +VALUE rb_class_subclasses(VALUE klass); + + +/** + * Returns the attached object for a singleton class. + * If the given class is not a singleton class, raises a TypeError. + * + * @param[in] klass A class. + * @return The object which has the singleton class `klass`. + * + * @internal + */ +VALUE rb_class_attached_object(VALUE klass); + +/** * Generates an array of symbols, which are the list of method names defined in * the passed class. * diff --git a/include/ruby/internal/intern/cont.h b/include/ruby/internal/intern/cont.h index 37493009f5..32647f48aa 100644 --- a/include/ruby/internal/intern/cont.h +++ b/include/ruby/internal/intern/cont.h @@ -39,6 +39,28 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() VALUE rb_fiber_new(rb_block_call_func_t func, VALUE callback_obj); /** + * Creates a Fiber instance from a C-backended block with the specified + * storage. + * + * If the given storage is Qundef or Qtrue, this function is equivalent to + * rb_fiber_new() which inherits storage from the current fiber. + * + * Specifying Qtrue is experimental and may be changed in the future. + * + * If the given storage is Qnil, this function will lazy initialize the + * internal storage which starts of empty (without any inheritance). + * + * Otherwise, the given storage is used as the internal storage. + * + * @param[in] func A function, to become the fiber's body. + * @param[in] callback_obj Passed as-is to `func`. + * @param[in] storage The way to set up the storage for the fiber. + * @return An allocated new instance of rb_cFiber, which is ready to be + * "resume"d. + */ +VALUE rb_fiber_new_storage(rb_block_call_func_t func, VALUE callback_obj, VALUE storage); + +/** * Queries the fiber which is calling this function. Any ruby execution * context has its fiber, either explicitly or implicitly. * diff --git a/include/ruby/internal/intern/error.h b/include/ruby/internal/intern/error.h index 37d3b8592b..9c153cbac5 100644 --- a/include/ruby/internal/intern/error.h +++ b/include/ruby/internal/intern/error.h @@ -38,8 +38,6 @@ #define rb_exc_new3 rb_exc_new_str /**< @old{rb_exc_new_str} */ /** @cond INTERNAL_MACRO */ -#define rb_check_trusted rb_check_trusted -#define rb_check_trusted_inline rb_check_trusted #define rb_check_arity rb_check_arity /** @endcond */ @@ -204,12 +202,6 @@ RBIMPL_ATTR_NORETURN() void rb_error_frozen_object(VALUE what); /** - * @deprecated Does nothing. This method is deprecated and will be removed in - * Ruby 3.2. - */ -void rb_error_untrusted(VALUE); - -/** * Queries if the passed object is frozen. * * @param[in] obj Target object to test frozen-ness. @@ -219,12 +211,6 @@ void rb_error_untrusted(VALUE); void rb_check_frozen(VALUE obj); /** - * @deprecated Does nothing. This method is deprecated and will be removed in - * Ruby 3.2. - */ -void rb_check_trusted(VALUE); - -/** * Ensures that the passed object can be `initialize_copy` relationship. When * you implement your own one you would better call this at the right beginning * of your implementation. diff --git a/include/ruby/internal/intern/file.h b/include/ruby/internal/intern/file.h index 8e98ba08f8..79820fdc61 100644 --- a/include/ruby/internal/intern/file.h +++ b/include/ruby/internal/intern/file.h @@ -187,6 +187,27 @@ RBIMPL_ATTR_PURE() */ int rb_is_absolute_path(const char *path); +/** + * Queries the file size of the given file. Because this function calls + * `fstat(2)` internally, it is a failure to pass a closed file to this + * function. + * + * This function flushes the passed file's buffer if any. Can take time. + * + * @param[in] file A file object. + * @exception rb_eFrozenError `file` is frozen. + * @exception rb_eIOError `file` is closed. + * @exception rb_eSystemCallError Permission denied etc. + * @exception rb_eNoMethodError The given non-file object doesn't respond + * to `#size`. + * @return The size of the passed file. + * @note Passing a non-regular file such as a UNIX domain socket to this + * function is not a failure. But the return value is + * unpredictable. POSIX's `<sys/stat.h>` states that "the use of + * this field is unspecified" then. + */ +rb_off_t rb_file_size(VALUE file); + RBIMPL_SYMBOL_EXPORT_END() #endif /* RBIMPL_INTERN_FILE_H */ diff --git a/include/ruby/internal/intern/gc.h b/include/ruby/internal/intern/gc.h index 1617a7cef6..2ee1d257db 100644 --- a/include/ruby/internal/intern/gc.h +++ b/include/ruby/internal/intern/gc.h @@ -26,7 +26,7 @@ # include <stddef.h> /* size_t */ #endif -#if HAVE_SYS_TYPES_H +#ifdef HAVE_SYS_TYPES_H # include <sys/types.h> /* ssize_t */ #endif @@ -71,7 +71,7 @@ RBIMPL_ATTR_NONNULL((1)) * addressable. * @param[out] start Pointer to an array of objects. * @param[out] end Pointer that terminates the array of objects. - * @post Objects from `start` to `end`, both inclusive, are marked. + * @post Objects from `start` (included) to `end` (excluded) are marked. * * @internal * @@ -208,7 +208,9 @@ VALUE rb_gc_location(VALUE obj); * @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); /** @@ -249,7 +251,7 @@ void rb_gc(void); * * @internal * - * But isn't it easier for you to call super, and let `Object#intialize_copy` + * But isn't it easier for you to call super, and let `Object#initialize_copy` * call this function instead? */ void rb_gc_copy_finalizer(VALUE dst, VALUE src); diff --git a/include/ruby/internal/intern/hash.h b/include/ruby/internal/intern/hash.h index 9d2ce8279a..af8dfd5d8f 100644 --- a/include/ruby/internal/intern/hash.h +++ b/include/ruby/internal/intern/hash.h @@ -107,6 +107,17 @@ VALUE rb_hash(VALUE obj); VALUE rb_hash_new(void); /** + * Identical to rb_hash_new(), except it additionally specifies how many keys + * it is expected to contain. This way you can create a hash that is large enough + * for your need. For large hashes it means it won't need to be reallocated and + * rehashed as much, improving performance. + * + * @param[in] capa Designed capacity of the hash. + * @return An empty Hash, whose capacity is `capa`. + */ +VALUE rb_hash_new_capa(long capa); + +/** * Duplicates a hash. * * @param[in] hash An instance of ::rb_cHash. @@ -288,15 +299,6 @@ int rb_path_check(const char *path); /* hash.c */ /** - * @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. - * - * @return 0 always. - */ -int rb_env_path_tainted(void); - -/** * Destructively removes every environment variables of the running process. * * @return The `ENV` object. diff --git a/include/ruby/internal/intern/object.h b/include/ruby/internal/intern/object.h index 6bb4ccb2fe..b9ffa57c06 100644 --- a/include/ruby/internal/intern/object.h +++ b/include/ruby/internal/intern/object.h @@ -92,8 +92,8 @@ VALUE rb_class_new_instance_kw(int argc, const VALUE *argv, VALUE klass, int kw_ * * @param[in] lhs Comparison left hand side. * @param[in] rhs Comparison right hand side. - * @retval RUBY_Qtrue They are equal. - * @retval RUBY_Qfalse Otherwise. + * @retval non-zero They are equal. + * @retval 0 Otherwise. * @note This function actually calls `lhs.eql?(rhs)` so you cannot * implement your class' `#eql?` method using it. */ @@ -202,74 +202,6 @@ VALUE rb_obj_dup(VALUE obj); */ VALUE rb_obj_init_copy(VALUE src, VALUE dst); -RBIMPL_ATTR_DEPRECATED_EXT(("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 Verbatim `obj`. - */ -VALUE rb_obj_taint(VALUE obj); - -RBIMPL_ATTR_PURE() -RBIMPL_ATTR_DEPRECATED_EXT(("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 Always returns ::RUBY_Qfalse. - */ -VALUE rb_obj_tainted(VALUE obj); - -RBIMPL_ATTR_DEPRECATED_EXT(("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 Verbatim `obj`. - */ -VALUE rb_obj_untaint(VALUE obj); - -RBIMPL_ATTR_DEPRECATED_EXT(("trustedness 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 Verbatim `obj`. - */ -VALUE rb_obj_untrust(VALUE obj); - -RBIMPL_ATTR_PURE() -RBIMPL_ATTR_DEPRECATED_EXT(("trustedness 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 Always returns ::RUBY_Qfalse. - */ -VALUE rb_obj_untrusted(VALUE obj); - -RBIMPL_ATTR_DEPRECATED_EXT(("trustedness 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 Verbatim `obj`. - */ -VALUE rb_obj_trust(VALUE obj); - /** * Just calls rb_obj_freeze_inline() inside. Does this make any sens to * extension libraries? diff --git a/include/ruby/internal/intern/select/largesize.h b/include/ruby/internal/intern/select/largesize.h index d156f62034..d65f088c06 100644 --- a/include/ruby/internal/intern/select/largesize.h +++ b/include/ruby/internal/intern/select/largesize.h @@ -35,9 +35,6 @@ * `select(2)` documents how to allocate fd_set dynamically. * http://www.openbsd.org/cgi-bin/man.cgi?query=select&manpath=OpenBSD+4.4 * - * - HP-UX documents how to allocate fd_set dynamically. - * http://docs.hp.com/en/B2355-60105/select.2.html - * * - Solaris 8 has `select_large_fdset` * * - Mac OS X 10.7 (Lion) diff --git a/include/ruby/internal/intern/select/posix.h b/include/ruby/internal/intern/select/posix.h index bfde159890..0a9b0b2e51 100644 --- a/include/ruby/internal/intern/select/posix.h +++ b/include/ruby/internal/intern/select/posix.h @@ -95,11 +95,10 @@ RBIMPL_ATTR_NOALIAS() * * @param[out] dst Target fdset. * @param[in] src Source fdset. - * @param[in] n Unused parameter. * @post `dst` is a copy of `src`. */ static inline void -rb_fd_dup(rb_fdset_t *dst, const fd_set *src, int n) +rb_fd_dup(rb_fdset_t *dst, const fd_set *src) { *dst = *src; } @@ -137,7 +136,7 @@ rb_fd_max(const rb_fdset_t *f) } /** @cond INTERNAL_MACRO */ -/* :FIXME: What are these? They don't exist for shibling implementations. */ +/* :FIXME: What are these? They don't exist for sibling implementations. */ #define rb_fd_init_copy(d, s) (*(d) = *(s)) #define rb_fd_term(f) ((void)(f)) /** @endcond */ diff --git a/include/ruby/internal/intern/string.h b/include/ruby/internal/intern/string.h index 0e2e6d6af7..3083125e56 100644 --- a/include/ruby/internal/intern/string.h +++ b/include/ruby/internal/intern/string.h @@ -62,13 +62,13 @@ RBIMPL_SYMBOL_EXPORT_BEGIN() */ VALUE rb_str_new(const char *ptr, long len); -RBIMPL_ATTR_NONNULL(()) /** * Identical to rb_str_new(), except it assumes the passed pointer is a pointer * to a C string. * * @param[in] ptr A C string. * @exception rb_eNoMemError Failed to allocate memory. + * @exception rb_eArgError `ptr` is a null pointer. * @return An instance of ::rb_cString, of "binary" encoding, whose * contents are verbatim copy of `ptr`. * @pre `ptr` must not be a null pointer. @@ -122,37 +122,6 @@ VALUE rb_str_new_frozen(VALUE str); */ VALUE rb_str_new_with_class(VALUE obj, const char *ptr, long len); -RBIMPL_ATTR_NONNULL(()) -/** - * @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] ptr A C string. - * @exception rb_eNoMemError Failed to allocate memory. - * @return An instance of ::rb_cString, of "binary" encoding, whose - * contents are verbatim copy of `ptr`. - * @pre `ptr` must not be a null pointer. - */ -VALUE rb_tainted_str_new_cstr(const char *ptr); - -/** - * @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] ptr A memory region of `len` bytes length. - * @param[in] len Length of `ptr`, in bytes, not including the - * terminating NUL character. - * @exception rb_eNoMemError Failed to allocate `len+1` bytes. - * @exception rb_eArgError `len` is negative. - * @return An instance of ::rb_cString, of `len` bytes length, of - * "binary" encoding, whose contents are verbatim copy of `ptr`. - * @pre At least `len` bytes of continuous memory region shall be - * accessible via `ptr`. - */ -VALUE rb_tainted_str_new(const char *ptr, long len); - /** * Identical to rb_str_new(), except it generates a string of "default * external" encoding. @@ -333,7 +302,6 @@ VALUE rb_str_tmp_new(long len); */ VALUE rb_usascii_str_new(const char *ptr, long len); -RBIMPL_ATTR_NONNULL(()) /** * Identical to rb_str_new_cstr(), except it generates a string of "US ASCII" * encoding. It can also be seen as a routine Identical to @@ -342,6 +310,7 @@ RBIMPL_ATTR_NONNULL(()) * * @param[in] ptr A C string. * @exception rb_eNoMemError Failed to allocate memory. + * @exception rb_eArgError `ptr` is a null pointer. * @return An instance of ::rb_cString, of "US ASCII" encoding, whose * contents are verbatim copy of `ptr`. * @pre `ptr` must not be a null pointer. @@ -361,7 +330,6 @@ VALUE rb_usascii_str_new_cstr(const char *ptr); */ VALUE rb_utf8_str_new(const char *ptr, long len); -RBIMPL_ATTR_NONNULL(()) /** * Identical to rb_str_new_cstr(), except it generates a string of "UTF-8" * encoding. It can also be seen as a routine Identical to @@ -370,6 +338,7 @@ RBIMPL_ATTR_NONNULL(()) * * @param[in] ptr A C string. * @exception rb_eNoMemError Failed to allocate memory. + * @exception rb_eArgError `ptr` is a null pointer. * @return An instance of ::rb_cString, of "UTF-8" encoding, whose contents * are verbatim copy of `ptr`. * @pre `ptr` must not be a null pointer. @@ -553,7 +522,6 @@ VALUE rb_str_buf_append(VALUE dst, VALUE src); /** @alias{rb_str_cat} */ VALUE rb_str_buf_cat(VALUE, const char*, long); -RBIMPL_ATTR_NONNULL(()) /** @alias{rb_str_cat_cstr} */ VALUE rb_str_buf_cat2(VALUE, const char*); @@ -874,7 +842,6 @@ VALUE rb_str_resize(VALUE str, long len); */ VALUE rb_str_cat(VALUE dst, const char *src, long srclen); -RBIMPL_ATTR_NONNULL(()) /** * Identical to rb_str_cat(), except it assumes the passed pointer is a pointer * to a C string. @@ -882,6 +849,7 @@ RBIMPL_ATTR_NONNULL(()) * @param[out] dst Destination object. * @param[in] src Contents to append. * @exception rb_eArgError Result string too big. + * @exception rb_eArgError `src` is a null pointer. * @return The passed `dst`. * @pre `dst` must not be any arbitrary objects except ::RString. * @pre `src` must not be a null pointer. @@ -889,7 +857,6 @@ RBIMPL_ATTR_NONNULL(()) */ VALUE rb_str_cat_cstr(VALUE dst, const char *src); -RBIMPL_ATTR_NONNULL(()) /** @alias{rb_str_cat_cstr} */ VALUE rb_str_cat2(VALUE, const char*); @@ -1153,7 +1120,6 @@ VALUE rb_str_inspect(VALUE str); */ VALUE rb_str_dump(VALUE str); -RBIMPL_ATTR_NONNULL(()) /** * Divides the given string based on the given delimiter. This is the * 1-argument 0-block version of `String#split`. @@ -1161,6 +1127,7 @@ RBIMPL_ATTR_NONNULL(()) * @param[in] str Object in question to split. * @param[in] delim Delimiter, in C string. * @exception rb_eTypeError `str` has no implicit conversion to String. + * @exception rb_eArgError `delim` is a null pointer. * @return An array of strings, which are substrings of the passed `str`. * If `delim` is an empty C string (i.e. `""`), `str` is split into * each characters. If `delim` is a C string whose sole content is @@ -1400,22 +1367,6 @@ rbimpl_str_new_cstr(const char *str) return rb_str_new_static(str, len); } -RBIMPL_ATTR_DEPRECATED(("taintedness turned out to be a wrong idea.")) -/** - * @private - * - * This is an implementation detail. Don't bother. - * - * @param[in] str A C string literal. - * @return Corresponding Ruby string. - */ -static inline VALUE -rbimpl_tainted_str_new_cstr(const char *str) -{ - long len = rbimpl_strlen(str); - return rb_tainted_str_new(str, len); -} - RBIMPL_ATTR_NONNULL(()) /** * @private @@ -1602,22 +1553,6 @@ rbimpl_exc_new_cstr(VALUE exc, const char *str) rb_utf8_str_new) ((str), (len))) /** - * @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. - * - * @param[in] str A C string. - * @exception rb_eNoMemError Failed to allocate memory. - * @return An instance of ::rb_cString, of "binary" encoding, whose - * contents are verbatim copy of `str`. - * @pre `str` must not be a null pointer. - */ -#define rb_tainted_str_new_cstr(str) \ - ((RBIMPL_CONSTANT_P(str) ? \ - rbimpl_tainted_str_new_cstr : \ - rb_tainted_str_new_cstr) (str)) - -/** * Identical to #rb_str_new_cstr, except it generates a string of "US ASCII" * encoding. It can also be seen as a routine Identical to * #rb_usascii_str_new, except it assumes the passed pointer is a pointer to a @@ -1741,7 +1676,6 @@ rbimpl_exc_new_cstr(VALUE exc, const char *str) #define rb_str_new3 rb_str_new_shared /**< @old{rb_str_new_shared} */ #define rb_str_new4 rb_str_new_frozen /**< @old{rb_str_new_frozen} */ #define rb_str_new5 rb_str_new_with_class /**< @old{rb_str_new_with_class} */ -#define rb_tainted_str_new2 rb_tainted_str_new_cstr /**< @old{rb_tainted_str_new_cstr} */ #define rb_str_buf_new2 rb_str_buf_new_cstr /**< @old{rb_str_buf_new_cstr} */ #define rb_usascii_str_new2 rb_usascii_str_new_cstr /**< @old{rb_usascii_str_new_cstr} */ #define rb_str_buf_cat rb_str_cat /**< @alias{rb_str_cat} */ diff --git a/include/ruby/internal/intern/thread.h b/include/ruby/internal/intern/thread.h index 294e552fe9..716375acd7 100644 --- a/include/ruby/internal/intern/thread.h +++ b/include/ruby/internal/intern/thread.h @@ -46,7 +46,7 @@ void rb_thread_schedule(void); * * @param[in] fd A file descriptor. * @exception rb_eIOError Closed stream. - * @exception rb_eSystemCalleError Situations like EBADF. + * @exception rb_eSystemCallError Situations like EBADF. */ int rb_thread_wait_fd(int fd); @@ -56,7 +56,7 @@ int rb_thread_wait_fd(int fd); * * @param[in] fd A file descriptor. * @exception rb_eIOError Closed stream. - * @exception rb_eSystemCalleError Situations like EBADF. + * @exception rb_eSystemCallError Situations like EBADF. */ int rb_thread_fd_writable(int fd); diff --git a/include/ruby/internal/intern/vm.h b/include/ruby/internal/intern/vm.h index 562d30a6fe..76af796b54 100644 --- a/include/ruby/internal/intern/vm.h +++ b/include/ruby/internal/intern/vm.h @@ -247,21 +247,17 @@ void rb_undef_alloc_func(VALUE klass); * * @internal * - * Who cares? @shyouhei fins no practical usage of the return value. Maybe we + * Who cares? @shyouhei finds no practical usage of the return value. Maybe we * need KonMari. */ rb_alloc_func_t rb_get_alloc_func(VALUE klass); /** - * Clears the constant cache. Extension libraries should not bother such - * things. Just forget about this API (or even, the presence of constant - * cache). - * - * @internal - * - * Completely no idea why this function is defined in vm_method.c. + * Clears the inline constant caches associated with a particular ID. Extension + * libraries should not bother with such things. Just forget about this API (or + * even, the presence of constant caches). */ -void rb_clear_constant_cache(void); +void rb_clear_constant_cache_for_id(ID id); /** * Resembles `alias`. diff --git a/include/ruby/internal/memory.h b/include/ruby/internal/memory.h index aa3464465d..6884db195d 100644 --- a/include/ruby/internal/memory.h +++ b/include/ruby/internal/memory.h @@ -287,12 +287,12 @@ typedef uint128_t DSIZE_T; RBIMPL_CAST((type *)alloca(rbimpl_size_mul_or_raise(sizeof(type), (n)))) /** - * Identical to #RB_ALLOCV_N(), except it implicitly assumes the type of array - * is ::VALUE. + * Identical to #RB_ALLOCV_N(), except that it allocates a number of bytes and + * returns a void* . * * @param v A variable to hold the just-in-case opaque Ruby object. * @param n Size of allocation, in bytes. - * @return An array of `n` bytes of ::VALUE. + * @return A void pointer to `n` bytes storage. * @note `n` may be evaluated twice. */ #define RB_ALLOCV(v, n) \ @@ -363,7 +363,7 @@ typedef uint128_t DSIZE_T; * @return `p1`. * @post First `n` elements of `p2` are copied into `p1`. */ -#define MEMCPY(p1,p2,type,n) memcpy((p1), (p2), rbimpl_size_mul_or_raise(sizeof(type), (n))) +#define MEMCPY(p1,p2,type,n) ruby_nonempty_memcpy((p1), (p2), rbimpl_size_mul_or_raise(sizeof(type), (n))) /** * Handy macro to call memmove. @@ -644,7 +644,6 @@ rb_alloc_tmp_buffer2(volatile VALUE *store, long count, size_t elsize) return rb_alloc_tmp_buffer_with_count(store, total_size, cnt); } -#if ! defined(__MINGW32__) && ! defined(__DOXYGEN__) RBIMPL_SYMBOL_EXPORT_BEGIN() RBIMPL_ATTR_NOALIAS() RBIMPL_ATTR_NONNULL((1)) @@ -663,8 +662,5 @@ ruby_nonempty_memcpy(void *dest, const void *src, size_t n) } } RBIMPL_SYMBOL_EXPORT_END() -#undef memcpy -#define memcpy ruby_nonempty_memcpy -#endif #endif /* RBIMPL_MEMORY_H */ diff --git a/include/ruby/internal/scan_args.h b/include/ruby/internal/scan_args.h index cf5b18f77d..1ed2bf6368 100644 --- a/include/ruby/internal/scan_args.h +++ b/include/ruby/internal/scan_args.h @@ -100,7 +100,7 @@ RBIMPL_ATTR_NONNULL((2, 3)) * param-arg-spec := pre-arg-spec [post-arg-spec] / post-arg-spec / * pre-opt-post-arg-spec * pre-arg-spec := num-of-leading-mandatory-args - [num-of-optional-args] + * [num-of-optional-args] * post-arg-spec := sym-for-variable-length-args * [num-of-trailing-mandatory-args] * pre-opt-post-arg-spec := num-of-leading-mandatory-args num-of-optional-args diff --git a/include/ruby/internal/special_consts.h b/include/ruby/internal/special_consts.h index 38934e4da3..dc0a6b41d6 100644 --- a/include/ruby/internal/special_consts.h +++ b/include/ruby/internal/special_consts.h @@ -76,6 +76,8 @@ #define RB_SPECIAL_CONST_P RB_SPECIAL_CONST_P #define RB_STATIC_SYM_P RB_STATIC_SYM_P #define RB_TEST RB_TEST +#define RB_UNDEF_P RB_UNDEF_P +#define RB_NIL_OR_UNDEF_P RB_NIL_OR_UNDEF_P /** @endcond */ /** special constants - i.e. non-zero and non-fixnum constants */ @@ -94,9 +96,9 @@ ruby_special_consts { RUBY_SYMBOL_FLAG, /**< Flag to denote a static symbol. */ #elif USE_FLONUM RUBY_Qfalse = 0x00, /* ...0000 0000 */ + RUBY_Qnil = 0x04, /* ...0000 0100 */ RUBY_Qtrue = 0x14, /* ...0001 0100 */ - RUBY_Qnil = 0x08, /* ...0000 1000 */ - RUBY_Qundef = 0x34, /* ...0011 0100 */ + RUBY_Qundef = 0x24, /* ...0010 0100 */ RUBY_IMMEDIATE_MASK = 0x07, /* ...0000 0111 */ RUBY_FIXNUM_FLAG = 0x01, /* ...xxxx xxx1 */ RUBY_FLONUM_MASK = 0x03, /* ...0000 0011 */ @@ -104,14 +106,14 @@ ruby_special_consts { RUBY_SYMBOL_FLAG = 0x0c, /* ...xxxx 1100 */ #else RUBY_Qfalse = 0x00, /* ...0000 0000 */ - RUBY_Qtrue = 0x02, /* ...0000 0010 */ - RUBY_Qnil = 0x04, /* ...0000 0100 */ - RUBY_Qundef = 0x06, /* ...0000 0110 */ + RUBY_Qnil = 0x02, /* ...0000 0010 */ + RUBY_Qtrue = 0x06, /* ...0000 0110 */ + RUBY_Qundef = 0x0a, /* ...0000 1010 */ RUBY_IMMEDIATE_MASK = 0x03, /* ...0000 0011 */ RUBY_FIXNUM_FLAG = 0x01, /* ...xxxx xxx1 */ RUBY_FLONUM_MASK = 0x00, /* any values ANDed with FLONUM_MASK cannot be FLONUM_FLAG */ RUBY_FLONUM_FLAG = 0x02, /* ...0000 0010 */ - RUBY_SYMBOL_FLAG = 0x0e, /* ...0000 1110 */ + RUBY_SYMBOL_FLAG = 0x0e, /* ...xxxx 1110 */ #endif RUBY_SPECIAL_SHIFT = 8 /**< Least significant 8 bits are reserved. */ @@ -136,12 +138,21 @@ static inline bool RB_TEST(VALUE obj) { /* + * if USE_FLONUM * Qfalse: ....0000 0000 - * Qnil: ....0000 1000 - * ~Qnil: ....1111 0111 + * Qnil: ....0000 0100 + * ~Qnil: ....1111 1011 * v ....xxxx xxxx * ---------------------------- - * RTEST(v) ....xxxx 0xxx + * RTEST(v) ....xxxx x0xx + * + * if ! USE_FLONUM + * Qfalse: ....0000 0000 + * Qnil: ....0000 0010 + * ~Qnil: ....1111 1101 + * v ....xxxx xxxx + * ---------------------------- + * RTEST(v) ....xxxx xx0x * * RTEST(v) can be 0 if and only if (v == Qfalse || v == Qnil). */ @@ -168,6 +179,62 @@ RBIMPL_ATTR_CONST() RBIMPL_ATTR_CONSTEXPR(CXX11) RBIMPL_ATTR_ARTIFICIAL() /** + * Checks if the given object is undef. + * + * @param[in] obj An arbitrary ruby object. + * @retval true `obj` is ::RUBY_Qundef. + * @retval false Anything else. + */ +static inline bool +RB_UNDEF_P(VALUE obj) +{ + return obj == RUBY_Qundef; +} + +RBIMPL_ATTR_CONST() +RBIMPL_ATTR_CONSTEXPR(CXX14) +RBIMPL_ATTR_ARTIFICIAL() +/** + * Checks if the given object is nil or undef. Can be used to see if + * a keyword argument is not given or given `nil`. + * + * @param[in] obj An arbitrary ruby object. + * @retval true `obj` is ::RUBY_Qnil or ::RUBY_Qundef. + * @retval false Anything else. + */ +static inline bool +RB_NIL_OR_UNDEF_P(VALUE obj) +{ + /* + * if USE_FLONUM + * Qundef: ....0010 0100 + * Qnil: ....0000 0100 + * mask: ....1101 1111 + * common_bits: ....0000 0100 + * --------------------------------- + * Qnil & mask ....0000 0100 + * Qundef & mask ....0000 0100 + * + * if ! USE_FLONUM + * Qundef: ....0000 1010 + * Qnil: ....0000 0010 + * mask: ....1111 0111 + * common_bits: ....0000 0010 + * ---------------------------- + * Qnil & mask ....0000 0010 + * Qundef & mask ....0000 0010 + * + * NIL_OR_UNDEF_P(v) can be true only when v is Qundef or Qnil. + */ + const VALUE mask = ~(RUBY_Qundef ^ RUBY_Qnil); + const VALUE common_bits = RUBY_Qundef & RUBY_Qnil; + return (obj & mask) == common_bits; +} + +RBIMPL_ATTR_CONST() +RBIMPL_ATTR_CONSTEXPR(CXX11) +RBIMPL_ATTR_ARTIFICIAL() +/** * Checks if the given object is a so-called Fixnum. * * @param[in] obj An arbitrary ruby object. @@ -259,7 +326,7 @@ RBIMPL_ATTR_ARTIFICIAL() static inline bool RB_SPECIAL_CONST_P(VALUE obj) { - return RB_IMMEDIATE_P(obj) || ! RB_TEST(obj); + return RB_IMMEDIATE_P(obj) || obj == RUBY_Qfalse; } RBIMPL_ATTR_CONST() diff --git a/include/ruby/internal/stdbool.h b/include/ruby/internal/stdbool.h index b15321cb00..1ca61136ba 100644 --- a/include/ruby/internal/stdbool.h +++ b/include/ruby/internal/stdbool.h @@ -39,7 +39,7 @@ # /* Take stdbool.h definition. */ # include <stdbool.h> -#else +#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 diff --git a/include/ruby/internal/variable.h b/include/ruby/internal/variable.h index 1f84b92db0..c017ffe3f7 100644 --- a/include/ruby/internal/variable.h +++ b/include/ruby/internal/variable.h @@ -147,7 +147,7 @@ RBIMPL_ATTR_NONNULL(()) * init_Foo(void) * { * foo = rb_eval_string("..."); - * rb_define_global_variable("$foo", &foo); + * rb_define_variable("$foo", &foo); * } * ``` * diff --git a/include/ruby/io.h b/include/ruby/io.h index c117087d6a..88029b1bb9 100644 --- a/include/ruby/io.h +++ b/include/ruby/io.h @@ -35,7 +35,11 @@ # undef revents # endif # define RB_WAITFD_IN POLLIN -# define RB_WAITFD_PRI POLLPRI +# if defined(POLLPRI) +# define RB_WAITFD_PRI POLLPRI +# else +# define RB_WAITFD_PRI 0 +# endif # define RB_WAITFD_OUT POLLOUT #else # define RB_WAITFD_IN 0x001 @@ -51,12 +55,23 @@ #include "ruby/internal/value.h" #include "ruby/backward/2/attributes.h" /* PACKED_STRUCT_UNALIGNED */ +// IO#wait, IO#wait_readable, IO#wait_writable, IO#wait_priority are defined by this implementation. +#define RUBY_IO_WAIT_METHODS + +// Used as the default timeout argument to `rb_io_wait` to use the `IO#timeout` value. +#define RUBY_IO_TIMEOUT_DEFAULT Qnil + RBIMPL_SYMBOL_EXPORT_BEGIN() struct stat; struct timeval; /** + * Indicates that a timeout has occurred while performing an IO operation. + */ +RUBY_EXTERN VALUE rb_eIOTimeoutError; + +/** * Type of events that an IO can wait. * * @internal @@ -91,6 +106,34 @@ PACKED_STRUCT_UNALIGNED(struct rb_io_buffer_t { /** @alias{rb_io_buffer_t} */ typedef struct rb_io_buffer_t rb_io_buffer_t; +/** Decomposed encoding flags (e.g. `"enc:enc2""`). */ +/* + * enc enc2 read action write action + * NULL NULL force_encoding(default_external) write the byte sequence of str + * e1 NULL force_encoding(e1) convert str.encoding to e1 + * e1 e2 convert from e2 to e1 convert str.encoding to e2 + */ +struct rb_io_enc_t { + /** Internal encoding. */ + rb_encoding *enc; + /** External encoding. */ + rb_encoding *enc2; + /** + * Flags. + * + * @see enum ::ruby_econv_flag_type + */ + int ecflags; + /** + * Flags as Ruby hash. + * + * @internal + * + * This is set. But used from nowhere maybe? + */ + VALUE ecopts; +}; + /** Ruby's IO, metadata and buffers. */ typedef struct rb_io_t { @@ -134,36 +177,7 @@ typedef struct rb_io_t { */ VALUE tied_io_for_writing; - /** Decomposed encoding flags (e.g. `"enc:enc2""`). */ - /* - * enc enc2 read action write action - * NULL NULL force_encoding(default_external) write the byte sequence of str - * e1 NULL force_encoding(e1) convert str.encoding to e1 - * e1 e2 convert from e2 to e1 convert str.encoding to e2 - */ - struct rb_io_enc_t { - /** Internal encoding. */ - rb_encoding *enc; - - /** External encoding. */ - rb_encoding *enc2; - - /** - * Flags. - * - * @see enum ::ruby_econv_flag_type - */ - int ecflags; - - /** - * Flags as Ruby hash. - * - * @internal - * - * This is set. But used from nowhere maybe? - */ - VALUE ecopts; - } encs; /**< Decomposed encoding flags. */ + struct rb_io_enc_t encs; /**< Decomposed encoding flags. */ /** Encoding converter used when reading from this IO. */ rb_econv_t *readconv; @@ -208,6 +222,11 @@ typedef struct rb_io_t { * This of course doesn't help inter-process IO interleaves, though. */ VALUE write_lock; + + /** + * The timeout associated with this IO when performing blocking operations. + */ + VALUE timeout; } rb_io_t; /** @alias{rb_io_enc_t} */ @@ -470,7 +489,7 @@ int rb_io_modestr_fmode(const char *modestr); /** * Identical to rb_io_modestr_fmode(), except it returns a mixture of `O_` - * flags. This for instnce returns `O_WRONLY | O_TRUNC | O_CREAT | O_EXCL` for + * flags. This for instance returns `O_WRONLY | O_TRUNC | O_CREAT | O_EXCL` for * `"wx"`. * * @param[in] modestr File mode, in C's string. @@ -648,10 +667,23 @@ VALUE rb_io_get_write_io(VALUE io); VALUE rb_io_set_write_io(VALUE io, VALUE w); /** - * Sets an IO to a "nonblock mode". This amends the way an IO operates so that - * instead of waiting for rooms for read/write, it returns errors. In case of - * multiplexed IO situations it can be vital for IO operations not to block. - * This is the key API to achieve that property. + * Instructs the OS to put its internal file structure into "nonblocking mode". + * This is an in-Kernel concept. Reading from/writing to that file using C + * function calls would return -1 with errno set. However when it comes to a + * ruby program, we hide that error behind our `IO#read` method. Ruby level + * `IO#read` blocks regardless of this flag. If you want to avoid blocking, + * you should consider using methods like `IO#readpartial`. + * + * ```ruby + * require 'io/nonblock' + * STDIN.nonblock = true + * STDIN.gets # blocks. + * ``` + * + * As of writing there is a room of this API in Fiber schedulers. A Fiber + * scheduler could be written in a way its behaviour depends on this property. + * You need an in-depth understanding of how schedulers work to properly + * leverage this, though. * * @note Note however that nonblocking-ness propagates across process * boundaries. You must really carefully watch your step when turning @@ -671,6 +703,15 @@ VALUE rb_io_set_write_io(VALUE io, VALUE w); void rb_io_set_nonblock(rb_io_t *fptr); /** + * Returns an integer representing the numeric file descriptor for + * <em>io</em>. + * + * @param[in] io An IO. + * @retval int A file descriptor. + */ +int rb_io_descriptor(VALUE io); + +/** * This function breaks down the option hash that `IO#initialize` takes into * components. This is an implementation detail of rb_io_extract_modeenc() * today. People prefer that API instead. @@ -735,8 +776,8 @@ int rb_io_extract_encoding_option(VALUE opt, rb_encoding **enc_p, rb_encoding ** * class File * def initialize: ( * (String | int) path, - * ?(Strig | int) fmode, - * ?(Strig | int) perm, + * ?(String | int) fmode, + * ?(String | int) perm, * ?mode: (String | int), * ?flags: int, * ?external_encoding: (Encoding | String), @@ -817,13 +858,37 @@ int rb_io_wait_writable(int fd); int rb_wait_for_single_fd(int fd, int events, struct timeval *tv); /** + * Get the timeout associated with the specified io object. + * + * @param[in] io An IO object. + * @retval RUBY_Qnil There is no associated timeout. + * @retval Otherwise The timeout value. + */ +VALUE rb_io_timeout(VALUE io); + +/** + * Set the timeout associated with the specified io object. This timeout is + * used as a best effort timeout to prevent operations from blocking forever. + * + * @param[in] io An IO object. + * @param[in] timeout A timeout value. Must respond to #to_f. + * @ + */ +VALUE rb_io_set_timeout(VALUE io, VALUE timeout); + +/** * Blocks until the passed IO is ready for the passed events. The "events" * here is a Ruby level integer, which is an OR-ed value of `IO::READABLE`, * `IO::WRITable`, and `IO::PRIORITY`. * + * If timeout is `Qnil`, it will use the default timeout as given by + * `rb_io_timeout(io)`. + * * @param[in] io An IO object to wait. * @param[in] events See above. * @param[in] timeout Time, or numeric seconds since UNIX epoch. + * If Qnil, use the default timeout. If Qfalse + * or Qundef, wait forever. * @exception rb_eIOError `io` is not open. * @exception rb_eRangeError `timeout` is out of range. * @exception rb_eSystemCallError `select(2)` failed for some reason. @@ -875,13 +940,8 @@ 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. - * @exception rb_eTypeError Operation timed out. - * @return Always returns ::RUBY_IO_READABLE. - * - * @internal - * - * Because rb_io_maybe_wait() returns ::RUBY_Qfalse on timeout, this function - * fails to convert that value to `int`, and raises ::rb_eTypeError. + * @retval 0 Operation timed out. + * @retval Otherwise Always returns ::RUBY_IO_READABLE. */ int rb_io_maybe_wait_readable(int error, VALUE io, VALUE timeout); @@ -896,13 +956,8 @@ 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. - * @exception rb_eTypeError Operation timed out. - * @return Always returns ::RUBY_IO_WRITABLE. - * - * @internal - * - * Because rb_io_maybe_wait() returns ::RUBY_Qfalse on timeout, this function - * fails to convert that value to `int`, and raises ::rb_eTypeError. + * @retval 0 Operation timed out. + * @retval Otherwise Always returns ::RUBY_IO_WRITABLE. */ int rb_io_maybe_wait_writable(int error, VALUE io, VALUE timeout); diff --git a/include/ruby/io/buffer.h b/include/ruby/io/buffer.h new file mode 100644 index 0000000000..e4b855d8e7 --- /dev/null +++ b/include/ruby/io/buffer.h @@ -0,0 +1,92 @@ +#ifndef RUBY_IO_BUFFER_H +#define RUBY_IO_BUFFER_H +/** + * @file + * @author Samuel Williams + * @date Fri 2 Jul 2021 16:29:01 NZST + * @copyright Copyright (C) 2021 Samuel Williams + * @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. + */ + +#pragma once + +#include "ruby/ruby.h" +#include "ruby/internal/config.h" + +RBIMPL_SYMBOL_EXPORT_BEGIN() + +// WARNING: This entire interface is experimental and may change in the future! +#define RB_IO_BUFFER_EXPERIMENTAL 1 + +#define RUBY_IO_BUFFER_VERSION 2 + +RUBY_EXTERN VALUE rb_cIOBuffer; +RUBY_EXTERN size_t RUBY_IO_BUFFER_PAGE_SIZE; +RUBY_EXTERN size_t RUBY_IO_BUFFER_DEFAULT_SIZE; + +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. + RB_IO_BUFFER_EXTERNAL = 1, + // The memory in the buffer is allocated internally. + RB_IO_BUFFER_INTERNAL = 2, + // The memory in the buffer is mapped. + // A non-private mapping is marked as external. + RB_IO_BUFFER_MAPPED = 4, + + // A mapped buffer that is also shared. + RB_IO_BUFFER_SHARED = 8, + + // The buffer is locked and cannot be resized. + // More specifically, it means we can't change the base address or size. + // A buffer is typically locked before a system call that uses the data. + RB_IO_BUFFER_LOCKED = 32, + + // The buffer mapping is private and will not impact other processes or the underlying file. + RB_IO_BUFFER_PRIVATE = 64, + + // The buffer is read-only and cannot be modified. + RB_IO_BUFFER_READONLY = 128 +}; + +enum rb_io_buffer_endian { + RB_IO_BUFFER_LITTLE_ENDIAN = 4, + RB_IO_BUFFER_BIG_ENDIAN = 8, + +#if defined(WORDS_BIGENDIAN) + RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN, +#else + RB_IO_BUFFER_HOST_ENDIAN = RB_IO_BUFFER_LITTLE_ENDIAN, +#endif + + RB_IO_BUFFER_NETWORK_ENDIAN = RB_IO_BUFFER_BIG_ENDIAN +}; + +VALUE rb_io_buffer_new(void *base, size_t size, enum rb_io_buffer_flags flags); +VALUE rb_io_buffer_map(VALUE io, size_t size, rb_off_t offset, enum rb_io_buffer_flags flags); + +VALUE rb_io_buffer_lock(VALUE self); +VALUE rb_io_buffer_unlock(VALUE self); +int rb_io_buffer_try_unlock(VALUE self); +VALUE rb_io_buffer_free(VALUE self); + +int 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); + +VALUE rb_io_buffer_transfer(VALUE self); +void rb_io_buffer_resize(VALUE self, size_t size); +void rb_io_buffer_clear(VALUE self, uint8_t value, size_t offset, size_t length); + +// The length is the minimum required length. +VALUE rb_io_buffer_read(VALUE self, VALUE io, size_t length, size_t offset); +VALUE rb_io_buffer_pread(VALUE self, VALUE io, rb_off_t from, size_t length, size_t offset); +VALUE rb_io_buffer_write(VALUE self, VALUE io, size_t length, size_t offset); +VALUE rb_io_buffer_pwrite(VALUE self, VALUE io, rb_off_t from, size_t length, size_t offset); + +RBIMPL_SYMBOL_EXPORT_END() + +#endif /* RUBY_IO_BUFFER_H */ diff --git a/include/ruby/memory_view.h b/include/ruby/memory_view.h index bac49e363e..1ddca2d46f 100644 --- a/include/ruby/memory_view.h +++ b/include/ruby/memory_view.h @@ -16,7 +16,7 @@ # include <stddef.h> /* size_t */ #endif -#if HAVE_SYS_TYPES_H +#ifdef HAVE_SYS_TYPES_H # include <sys/types.h> /* ssize_t */ #endif @@ -146,8 +146,11 @@ typedef struct { * Or, NULL when this memory view exposes a flat array. */ const ssize_t *sub_offsets; - /** the private data for managing this exported memory */ + /** The private data for managing this exported memory */ void *private_data; + + /** DO NOT TOUCH THIS: The memory view entry for the internal use */ + const struct rb_memory_view_entry *_memory_view_entry; } rb_memory_view_t; /** Type of function of ::rb_memory_view_entry_t::get_func. */ @@ -160,9 +163,10 @@ typedef bool (* rb_memory_view_release_func_t)(VALUE obj, rb_memory_view_t *view typedef bool (* rb_memory_view_available_p_func_t)(VALUE obj); /** Operations applied to a specific kind of a memory view. */ -typedef struct { - - /** Exports a memory view from a Ruby object. */ +typedef struct rb_memory_view_entry { + /** + * Exports a memory view from a Ruby object. + */ rb_memory_view_get_func_t get_func; /** diff --git a/include/ruby/missing.h b/include/ruby/missing.h index 1e97e294f1..aea6c9088d 100644 --- a/include/ruby/missing.h +++ b/include/ruby/missing.h @@ -33,6 +33,18 @@ # include <sys/time.h> #endif +#ifdef HAVE_SYS_STAT_H +# include <sys/stat.h> +#endif + +#ifdef HAVE_UNISTD_H +# include <unistd.h> +#endif + +#ifdef HAVE_STDIO_H +# include <stdio.h> +#endif + #ifdef HAVE_IEEEFP_H # include <ieeefp.h> #endif @@ -224,6 +236,107 @@ RUBY_EXTERN void setproctitle(const char *fmt, ...); RUBY_EXTERN void explicit_bzero(void *b, size_t len); #endif +#ifndef HAVE_TZSET +RUBY_EXTERN void tzset(void); +#endif + +#ifndef HAVE_POSIX_MADVISE +RUBY_EXTERN int posix_madvise(void *, size_t, int); +#endif + +#ifndef HAVE_GETEUID +RUBY_EXTERN rb_uid_t geteuid(void); +#endif + +#ifndef HAVE_GETUID +RUBY_EXTERN rb_uid_t getuid(void); +#endif + +#ifndef HAVE_GETEGID +RUBY_EXTERN rb_gid_t getegid(void); +#endif + +#ifndef HAVE_GETGID +RUBY_EXTERN rb_gid_t getgid(void); +#endif + +#ifndef HAVE_GETLOGIN +RUBY_EXTERN char *getlogin(void); +#endif + +#ifndef HAVE_GETPPID +RUBY_EXTERN rb_pid_t getppid(void); +#endif + +#ifndef HAVE_UMASK +RUBY_EXTERN rb_mode_t umask(rb_mode_t); +#endif + +#ifndef HAVE_CHMOD +RUBY_EXTERN int chmod(const char *, rb_mode_t); +#endif + +#ifndef HAVE_CHOWN +RUBY_EXTERN int chown(const char *, rb_uid_t, rb_gid_t); +#endif + +#ifndef HAVE_PCLOSE +RUBY_EXTERN int pclose(FILE *); +#endif + +#ifndef HAVE_POPEN +RUBY_EXTERN FILE *popen(const char *, const char *); +#endif + +#ifndef HAVE_PIPE +RUBY_EXTERN int pipe(int [2]); +#endif + +#ifndef HAVE_DUP +RUBY_EXTERN int dup(int); +#endif + +#ifndef HAVE_DUP2 +RUBY_EXTERN int dup2(int, int); +#endif + +#ifndef HAVE_KILL +RUBY_EXTERN int kill(rb_pid_t, int); +#endif + +#ifndef HAVE_EXECL +RUBY_EXTERN int execl(const char *, const char *, ...); +#endif + +#ifndef HAVE_EXECLE +RUBY_EXTERN int execle(const char *, const char *, ...); +#endif + +#ifndef HAVE_EXECV +RUBY_EXTERN int execv(const char *, char *const []); +#endif + +#ifndef HAVE_EXECVE +RUBY_EXTERN int execve(const char *, char *const [], char *const []); +#endif + +#ifndef HAVE_SHUTDOWN +RUBY_EXTERN int shutdown(int, int); +#endif + +#ifndef HAVE_SYSTEM +RUBY_EXTERN int system(const char *); +#endif + +#ifndef WNOHANG +# define WNOHANG 0 +#endif + +#ifndef HAVE_WAITPID +# define HAVE_WAITPID 1 +RUBY_EXTERN rb_pid_t waitpid(rb_pid_t, int *, int); +#endif + RBIMPL_SYMBOL_EXPORT_END() #endif /* RUBY_MISSING_H */ diff --git a/include/ruby/onigmo.h b/include/ruby/onigmo.h index 6187b37dc3..8d7c601703 100644 --- a/include/ruby/onigmo.h +++ b/include/ruby/onigmo.h @@ -356,9 +356,9 @@ int onigenc_ascii_only_case_map(OnigCaseFoldType* flagP, const OnigUChar** pp, c #define ONIGENC_PRECISE_MBC_ENC_LEN(enc,p,e) (enc)->precise_mbc_enc_len(p,e,enc) ONIG_EXTERN -int onigenc_mbclen_approximate(const OnigUChar* p,const OnigUChar* e, const struct OnigEncodingTypeST* enc); +int onigenc_mbclen(const OnigUChar* p,const OnigUChar* e, const struct OnigEncodingTypeST* enc); -#define ONIGENC_MBC_ENC_LEN(enc,p,e) onigenc_mbclen_approximate(p,e,enc) +#define ONIGENC_MBC_ENC_LEN(enc,p,e) onigenc_mbclen(p,e,enc) #define ONIGENC_MBC_MAXLEN(enc) ((enc)->max_enc_len) #define ONIGENC_MBC_MAXLEN_DIST(enc) ONIGENC_MBC_MAXLEN(enc) #define ONIGENC_MBC_MINLEN(enc) ((enc)->min_enc_len) @@ -744,6 +744,8 @@ typedef struct { typedef struct { int lower; int upper; + long base_num; + long inner_num; } OnigRepeatRange; typedef void (*OnigWarnFunc)(const char* s); @@ -793,6 +795,13 @@ typedef struct re_pattern_buffer { OnigDistance dmin; /* min-distance of exact or map */ OnigDistance dmax; /* max-distance of exact or map */ + /* rb_hrtime_t from hrtime.h */ +#ifdef MY_RUBY_BUILD_MAY_TIME_TRAVEL + int128_t timelimit; +#else + uint64_t timelimit; +#endif + /* regex_t link chain */ struct re_pattern_buffer* chain; /* escape compile-conflict */ } OnigRegexType; @@ -845,6 +854,8 @@ OnigPosition onig_search_gpos(OnigRegex, const OnigUChar* str, const OnigUChar* ONIG_EXTERN OnigPosition onig_match(OnigRegex, const OnigUChar* str, const OnigUChar* end, const OnigUChar* at, OnigRegion* region, OnigOptionType option); ONIG_EXTERN +int onig_check_linear_time(OnigRegex reg); +ONIG_EXTERN OnigRegion* onig_region_new(void); ONIG_EXTERN void onig_region_init(OnigRegion* region); diff --git a/include/ruby/ractor.h b/include/ruby/ractor.h index 687ddcadec..7811616f6d 100644 --- a/include/ruby/ractor.h +++ b/include/ruby/ractor.h @@ -145,7 +145,7 @@ bool rb_ractor_local_storage_value_lookup(rb_ractor_local_key_t key, VALUE *val) * Associates the passed value to the passed key. * * @param[in] key A ractor-local storage key. - * @param[in] val Arbitary ruby object. + * @param[in] val Arbitrary ruby object. * @post `val` corresponds to `key` in the current Ractor. */ void rb_ractor_local_storage_value_set(rb_ractor_local_key_t key, VALUE val); diff --git a/include/ruby/random.h b/include/ruby/random.h index 657b37f034..39bdb6f3e3 100644 --- a/include/ruby/random.h +++ b/include/ruby/random.h @@ -16,6 +16,26 @@ #include "ruby/ruby.h" +/* + * version + * 0: before versioning; deprecated + * 1: added version, flags and init_32bit function + */ +#define RUBY_RANDOM_INTERFACE_VERSION_MAJOR 1 +#define RUBY_RANDOM_INTERFACE_VERSION_MINOR 0 + +#define RUBY_RANDOM_PASTE_VERSION_SUFFIX(x, y, z) x##_##y##_##z +#define RUBY_RANDOM_WITH_VERSION_SUFFIX(name, major, minor) \ + RUBY_RANDOM_PASTE_VERSION_SUFFIX(name, major, minor) +#define rb_random_data_type \ + RUBY_RANDOM_WITH_VERSION_SUFFIX(rb_random_data_type, \ + RUBY_RANDOM_INTERFACE_VERSION_MAJOR, \ + RUBY_RANDOM_INTERFACE_VERSION_MINOR) +#define RUBY_RANDOM_INTERFACE_VERSION_INITIALIZER \ + {RUBY_RANDOM_INTERFACE_VERSION_MAJOR, RUBY_RANDOM_INTERFACE_VERSION_MINOR} +#define RUBY_RANDOM_INTERFACE_VERSION_MAJOR_MAX 0xff +#define RUBY_RANDOM_INTERFACE_VERSION_MINOR_MAX 0xff + RBIMPL_SYMBOL_EXPORT_BEGIN() /** @@ -48,6 +68,17 @@ typedef void rb_random_init_func(rb_random_t *rng, const uint32_t *buf, size_t l RBIMPL_ATTR_NONNULL(()) /** + * This is the type of functions called when your random object is initialised. + * Passed data is the seed integer. + * + * @param[out] rng Your random struct to fill in. + * @param[in] data Seed, single word. + * @post `rng` is initialised using the passed seeds. + */ +typedef void rb_random_init_int32_func(rb_random_t *rng, uint32_t data); + +RBIMPL_ATTR_NONNULL(()) +/** * This is the type of functions called from your object's `#rand` method. * * @param[out] rng Your random struct to extract an integer from. @@ -84,9 +115,24 @@ typedef struct { /** Number of bits of seed numbers. */ size_t default_seed_bits; - /** Initialiser function. */ + /** + * Major/minor versions of this interface + */ + struct { + uint8_t major, minor; + } version; + + /** + * Reserved flags + */ + uint16_t flags; + + /** Function to initialize from uint32_t array. */ rb_random_init_func *init; + /** Function to initialize from single uint32_t. */ + rb_random_init_int32_func *init_int32; + /** Function to obtain a random integer. */ rb_random_get_int32_func *get_int32; @@ -130,11 +176,12 @@ typedef struct { } rb_random_interface_t; /** - * This utility macro defines 3 functions named prefix_init, prefix_get_int32, - * prefix_get_bytes. + * This utility macro defines 4 functions named prefix_init, prefix_init_int32, + * prefix_get_int32, prefix_get_bytes. */ #define RB_RANDOM_INTERFACE_DECLARE(prefix) \ static void prefix##_init(rb_random_t *, const uint32_t *, size_t); \ + static void prefix##_init_int32(rb_random_t *, uint32_t); \ static unsigned int prefix##_get_int32(rb_random_t *); \ static void prefix##_get_bytes(rb_random_t *, void *, size_t) @@ -161,7 +208,9 @@ typedef struct { * ``` */ #define RB_RANDOM_INTERFACE_DEFINE(prefix) \ + RUBY_RANDOM_INTERFACE_VERSION_INITIALIZER, 0, \ prefix##_init, \ + prefix##_init_int32, \ prefix##_get_int32, \ prefix##_get_bytes @@ -173,6 +222,12 @@ typedef struct { RB_RANDOM_INTERFACE_DEFINE(prefix), \ prefix##_get_real +#define RB_RANDOM_DEFINE_INIT_INT32_FUNC(prefix) \ + static void prefix##_init_int32(rb_random_t *rnd, uint32_t data) \ + { \ + prefix##_init(rnd, &data, 1); \ + } + #if defined _WIN32 && !defined __CYGWIN__ typedef rb_data_type_t rb_random_data_type_t; # define RB_RANDOM_PARENT 0 @@ -189,7 +244,7 @@ typedef const rb_data_type_t rb_random_data_type_t; * 0, RB_RANDOM_INTERFACE_DEFINE(your), * }; * - * static inline constexpr your_prng = { + * static inline constexpr rb_random_data_type_t your_prng_type = { * "your PRNG", * { rb_random_mark, }, * RB_RANDOM_PARENT, // <<-- HERE diff --git a/include/ruby/ruby.h b/include/ruby/ruby.h index f35d13685c..444940ca3a 100644 --- a/include/ruby/ruby.h +++ b/include/ruby/ruby.h @@ -23,6 +23,7 @@ #include <stdarg.h> #include "defines.h" +#include "ruby/internal/abi.h" #include "ruby/internal/anyargs.h" #include "ruby/internal/arithmetic.h" #include "ruby/internal/core.h" @@ -107,7 +108,7 @@ VALUE rb_get_path_no_checksafe(VALUE); # define rb_varargs_argc_check_runtime(argc, vargc) \ (((argc) <= (vargc)) ? (argc) : \ (rb_fatal("argc(%d) exceeds actual arguments(%d)", \ - argc, vargc), 0)) + argc, vargc), 0)) # define rb_varargs_argc_valid_p(argc, vargc) \ ((argc) == 0 ? (vargc) <= 1 : /* [ruby-core:85266] [Bug #14425] */ \ (argc) == (vargc)) @@ -116,16 +117,16 @@ VALUE rb_get_path_no_checksafe(VALUE); ERRORFUNC((" argument length doesn't match"), int rb_varargs_bad_length(int,int)); # else # define rb_varargs_bad_length(argc, vargc) \ - ((argc)/rb_varargs_argc_valid_p(argc, vargc)) + ((argc)/rb_varargs_argc_valid_p(argc, vargc)) # endif # define rb_varargs_argc_check(argc, vargc) \ __builtin_choose_expr(__builtin_constant_p(argc), \ - (rb_varargs_argc_valid_p(argc, vargc) ? (argc) : \ - rb_varargs_bad_length(argc, vargc)), \ - rb_varargs_argc_check_runtime(argc, vargc)) + (rb_varargs_argc_valid_p(argc, vargc) ? (argc) : \ + rb_varargs_bad_length(argc, vargc)), \ + rb_varargs_argc_check_runtime(argc, vargc)) # else # define rb_varargs_argc_check(argc, vargc) \ - rb_varargs_argc_check_runtime(argc, vargc) + rb_varargs_argc_check_runtime(argc, vargc) # endif #endif /** @endcond */ @@ -276,24 +277,24 @@ int ruby_vsnprintf(char *str, size_t n, char const *fmt, va_list ap); #elif defined(__GNUC__) && defined(HAVE_VA_ARGS_MACRO) && defined(__OPTIMIZE__) # define rb_yield_values(argc, ...) \ __extension__({ \ - const int rb_yield_values_argc = (argc); \ - const VALUE rb_yield_values_args[] = {__VA_ARGS__}; \ - const int rb_yield_values_nargs = \ - (int)(sizeof(rb_yield_values_args) / sizeof(VALUE)); \ - rb_yield_values2( \ - rb_varargs_argc_check(rb_yield_values_argc, rb_yield_values_nargs), \ - rb_yield_values_nargs ? rb_yield_values_args : NULL); \ + const int rb_yield_values_argc = (argc); \ + const VALUE rb_yield_values_args[] = {__VA_ARGS__}; \ + const int rb_yield_values_nargs = \ + (int)(sizeof(rb_yield_values_args) / sizeof(VALUE)); \ + rb_yield_values2( \ + rb_varargs_argc_check(rb_yield_values_argc, rb_yield_values_nargs), \ + rb_yield_values_nargs ? rb_yield_values_args : NULL); \ }) # define rb_funcall(recv, mid, argc, ...) \ __extension__({ \ - const int rb_funcall_argc = (argc); \ - const VALUE rb_funcall_args[] = {__VA_ARGS__}; \ - const int rb_funcall_nargs = \ - (int)(sizeof(rb_funcall_args) / sizeof(VALUE)); \ + const int rb_funcall_argc = (argc); \ + const VALUE rb_funcall_args[] = {__VA_ARGS__}; \ + const int rb_funcall_nargs = \ + (int)(sizeof(rb_funcall_args) / sizeof(VALUE)); \ rb_funcallv(recv, mid, \ - rb_varargs_argc_check(rb_funcall_argc, rb_funcall_nargs), \ - rb_funcall_nargs ? rb_funcall_args : NULL); \ + rb_varargs_argc_check(rb_funcall_argc, rb_funcall_nargs), \ + rb_funcall_nargs ? rb_funcall_args : NULL); \ }) #endif /** @endcond */ diff --git a/include/ruby/st.h b/include/ruby/st.h index 1e4bb80686..f35ab43603 100644 --- a/include/ruby/st.h +++ b/include/ruby/st.h @@ -98,6 +98,8 @@ struct st_table { enum st_retval {ST_CONTINUE, ST_STOP, ST_DELETE, ST_CHECK, ST_REPLACE}; +size_t rb_st_table_size(const struct st_table *tbl); +#define st_table_size rb_st_table_size 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); diff --git a/include/ruby/thread.h b/include/ruby/thread.h index 18c792b386..0b5b1ca0f3 100644 --- a/include/ruby/thread.h +++ b/include/ruby/thread.h @@ -128,7 +128,7 @@ RBIMPL_ATTR_NONNULL((1)) * your code to see if it is actually worth releasing the GVL. */ void *rb_thread_call_without_gvl(void *(*func)(void *), void *data1, - rb_unblock_function_t *ubf, void *data2); + rb_unblock_function_t *ubf, void *data2); RBIMPL_ATTR_NONNULL((1)) /** @@ -152,7 +152,7 @@ RBIMPL_ATTR_NONNULL((1)) * @return What `func` returned, or 0 in case `func` did not return. */ void *rb_thread_call_without_gvl2(void *(*func)(void *), void *data1, - rb_unblock_function_t *ubf, void *data2); + rb_unblock_function_t *ubf, void *data2); /* * XXX: unstable/unapproved - out-of-tree code should NOT not depend @@ -190,6 +190,46 @@ 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 */ +#define RUBY_INTERNAL_THREAD_EVENT_READY 1 << 1 /** acquiring GVL */ +#define RUBY_INTERNAL_THREAD_EVENT_RESUMED 1 << 2 /** acquired GVL */ +#define RUBY_INTERNAL_THREAD_EVENT_SUSPENDED 1 << 3 /** released GVL */ +#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 void (*rb_internal_thread_event_callback)(rb_event_flag_t event, + const rb_internal_thread_event_data_t *event_data, + void *user_data); +typedef struct rb_internal_thread_event_hook rb_internal_thread_event_hook_t; + +/** + * Registers a thread event hook function. + * + * @param[in] func A callback. + * @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. + * @warning This function MUST not be called from a thread event callback. + */ +rb_internal_thread_event_hook_t *rb_internal_thread_add_event_hook( + rb_internal_thread_event_callback func, rb_event_flag_t events, + void *data); + + +/** + * 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. + * @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); + RBIMPL_SYMBOL_EXPORT_END() #endif /* RUBY_THREAD_H */ diff --git a/include/ruby/thread_native.h b/include/ruby/thread_native.h index 2945ff1e4d..c23b15e133 100644 --- a/include/ruby/thread_native.h +++ b/include/ruby/thread_native.h @@ -37,6 +37,12 @@ typedef pthread_t rb_nativethread_id_t; typedef pthread_mutex_t rb_nativethread_lock_t; typedef pthread_cond_t rb_nativethread_cond_t; +#elif defined(__wasi__) // no-thread platforms + +typedef struct rb_nativethread_id_t *rb_nativethread_id_t; +typedef struct rb_nativethread_lock_t *rb_nativethread_lock_t; +typedef struct rb_nativethread_cond_t *rb_nativethread_cond_t; + #elif defined(__DOXYGEN__) /** Opaque type that holds an ID of a native thread. */ diff --git a/include/ruby/util.h b/include/ruby/util.h index b2bc1a09f6..e8727a3200 100644 --- a/include/ruby/util.h +++ b/include/ruby/util.h @@ -19,7 +19,7 @@ # include <stddef.h> /* size_t */ #endif -#if HAVE_SYS_TYPES_H +#ifdef HAVE_SYS_TYPES_H # include <sys/types.h> /* ssize_t */ #endif @@ -124,7 +124,7 @@ unsigned long ruby_scan_hex(const char *str, size_t len, size_t *ret); # define ruby_qsort qsort_r #else void ruby_qsort(void *, const size_t, const size_t, - int (*)(const void *, const void *, void *), void *); + int (*)(const void *, const void *, void *), void *); #endif RBIMPL_ATTR_NONNULL((1)) diff --git a/include/ruby/version.h b/include/ruby/version.h index 104f78a0c6..18b3abc8d7 100644 --- a/include/ruby/version.h +++ b/include/ruby/version.h @@ -67,7 +67,7 @@ * 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 1 +#define RUBY_API_VERSION_MINOR 2 /** * Teeny version. This digit is kind of reserved these days. Kept 0 for the @@ -137,7 +137,8 @@ RUBY_EXTERN const int ruby_patchlevel; /** * This is what `ruby -v` prints to the standard error. Something like: - * `"ruby 2.5.9p229 (2021-04-05 revision 67829) [x86_64-linux]"` + * `"ruby 2.5.9p229 (2021-04-05 revision 67829) [x86_64-linux]"`. This doesn't + * include runtime options like a JIT being enabled. */ RUBY_EXTERN const char ruby_description[]; diff --git a/include/ruby/win32.h b/include/ruby/win32.h index c8ae599f2f..197eb8a802 100644 --- a/include/ruby/win32.h +++ b/include/ruby/win32.h @@ -19,11 +19,6 @@ RUBY_SYMBOL_EXPORT_BEGIN */ /* - * Definitions for NT port of Perl - */ - - -/* * Ok now we can include the normal include files. */ @@ -155,10 +150,14 @@ typedef int clockid_t; #define read(f, b, s) rb_w32_read(f, b, s) #define write(f, b, s) rb_w32_write(f, b, s) #define getpid() rb_w32_getpid() +#undef HAVE_GETPPID +#define HAVE_GETPPID 1 #define getppid() rb_w32_getppid() #define sleep(x) rb_w32_Sleep((x)*1000) #define Sleep(msec) (void)rb_w32_Sleep(msec) +#undef HAVE_EXECV +#define HAVE_EXECV 1 #undef execv #define execv(path,argv) rb_w32_uaspawn(P_OVERLAY,path,argv) #undef isatty @@ -191,7 +190,6 @@ struct stati128 { long st_ctimensec; }; -#define off_t __int64 #define stat stati128 #undef SIZEOF_STRUCT_STAT_ST_INO #define SIZEOF_STRUCT_STAT_ST_INO sizeof(unsigned __int64) @@ -299,7 +297,6 @@ extern DWORD rb_w32_osver(void); extern int rb_w32_uchown(const char *, int, int); extern int rb_w32_ulink(const char *, const char *); extern ssize_t rb_w32_ureadlink(const char *, char *, size_t); -extern ssize_t rb_w32_wreadlink(const WCHAR *, WCHAR *, size_t); extern int rb_w32_usymlink(const char *src, const char *link); extern int gettimeofday(struct timeval *, struct timezone *); extern int clock_gettime(clockid_t, struct timespec *); @@ -309,7 +306,9 @@ extern rb_pid_t wait(int *); extern rb_pid_t rb_w32_uspawn(int, const char *, const char*); extern rb_pid_t rb_w32_uaspawn(int, const char *, char *const *); extern rb_pid_t rb_w32_uaspawn_flags(int, const char *, char *const *, DWORD); -extern int kill(int, int); +#undef HAVE_KILL +#define HAVE_KILL 1 +extern int kill(rb_pid_t, int); extern int fcntl(int, int, ...); extern int rb_w32_set_nonblock(int); extern rb_pid_t rb_w32_getpid(void); @@ -388,6 +387,7 @@ scalb(double a, long b) #endif #define S_IFLNK 0xa000 +#define S_IFSOCK 0xc000 /* * define this so we can do inplace editing @@ -395,9 +395,9 @@ scalb(double a, long b) #define SUFFIX -extern int rb_w32_ftruncate(int fd, off_t length); -extern int rb_w32_truncate(const char *path, off_t length); -extern int rb_w32_utruncate(const char *path, off_t length); +extern int rb_w32_ftruncate(int fd, rb_off_t length); +extern int rb_w32_truncate(const char *path, rb_off_t length); +extern int rb_w32_utruncate(const char *path, rb_off_t length); #undef HAVE_FTRUNCATE #define HAVE_FTRUNCATE 1 @@ -647,6 +647,8 @@ extern char *rb_w32_strerror(int); #undef setsockopt #define setsockopt(s, v, n, o, l) rb_w32_setsockopt(s, v, n, o, l) +#undef HAVE_SHUTDOWN +#define HAVE_SHUTDOWN 1 #undef shutdown #define shutdown(s, h) rb_w32_shutdown(s, h) @@ -694,10 +696,10 @@ extern char *rb_w32_strerror(int); #endif struct tms { - long tms_utime; - long tms_stime; - long tms_cutime; - long tms_cstime; + long tms_utime; + long tms_stime; + long tms_cutime; + long tms_cstime; }; int rb_w32_times(struct tms *); @@ -714,7 +716,7 @@ int rb_w32_fclose(FILE*); int rb_w32_pipe(int[2]); ssize_t rb_w32_read(int, void *, size_t); ssize_t rb_w32_write(int, const void *, size_t); -off_t rb_w32_lseek(int, off_t, int); +rb_off_t rb_w32_lseek(int, rb_off_t, int); int rb_w32_uutime(const char *, const struct utimbuf *); int rb_w32_uutimes(const char *, const struct timeval *); int rb_w32_uutimensat(int /* must be AT_FDCWD */, const char *, const struct timespec *, int /* must be 0 */); @@ -796,6 +798,25 @@ double rb_w32_pow(double x, double y); #define pow rb_w32_pow #endif +// mmap tiny emulation +#define MAP_FAILED ((void *)-1) + +#define PROT_READ 0x01 +#define PROT_WRITE 0x02 +#define PROT_EXEC 0x04 + +#define MAP_PRIVATE 0x0002 +#define MAP_ANON 0x1000 +#define MAP_ANONYMOUS MAP_ANON + +extern void *rb_w32_mmap(void *, size_t, int, int, int, rb_off_t); +extern int rb_w32_munmap(void *, size_t); +extern int rb_w32_mprotect(void *, size_t, int); + +#define mmap(a, l, p, f, d, o) rb_w32_mmap(a, l, p, f, d, o) +#define munmap(a, l) rb_w32_munmap(a, l) +#define mprotect(a, l, prot) rb_w32_mprotect(a, l, prot) + #if defined(__cplusplus) #if 0 { /* satisfy cc-mode */ |
