summaryrefslogtreecommitdiff
path: root/include/ruby/internal/core
diff options
context:
space:
mode:
Diffstat (limited to 'include/ruby/internal/core')
-rw-r--r--include/ruby/internal/core/rarray.h225
-rw-r--r--include/ruby/internal/core/rbasic.h34
-rw-r--r--include/ruby/internal/core/rclass.h49
-rw-r--r--include/ruby/internal/core/rdata.h59
-rw-r--r--include/ruby/internal/core/rfile.h4
-rw-r--r--include/ruby/internal/core/rhash.h13
-rw-r--r--include/ruby/internal/core/rmatch.h14
-rw-r--r--include/ruby/internal/core/robject.h93
-rw-r--r--include/ruby/internal/core/rstring.h162
-rw-r--r--include/ruby/internal/core/rstruct.h12
-rw-r--r--include/ruby/internal/core/rtypeddata.h267
11 files changed, 315 insertions, 617 deletions
diff --git a/include/ruby/internal/core/rarray.h b/include/ruby/internal/core/rarray.h
index 9f1d0509ea..73cc0f5dd9 100644
--- a/include/ruby/internal/core/rarray.h
+++ b/include/ruby/internal/core/rarray.h
@@ -29,25 +29,13 @@
#include "ruby/internal/core/rbasic.h"
#include "ruby/internal/dllexport.h"
#include "ruby/internal/fl_type.h"
-#include "ruby/internal/rgengc.h"
+#include "ruby/internal/gc.h"
#include "ruby/internal/stdbool.h"
#include "ruby/internal/value.h"
#include "ruby/internal/value_type.h"
#include "ruby/assert.h"
/**
- * @private
- * @warning Do not touch this macro.
- * @warning It is an implementation detail.
- * @warning The value of this macro must match for ruby itself and all
- * extension libraries, otherwise serious memory corruption shall
- * occur.
- */
-#ifndef USE_TRANSIENT_HEAP
-# define USE_TRANSIENT_HEAP 1
-#endif
-
-/**
* Convenient casting macro.
*
* @param obj An object, which is in fact an ::RArray.
@@ -59,15 +47,9 @@
#define RARRAY_EMBED_LEN_MASK RARRAY_EMBED_LEN_MASK
#define RARRAY_EMBED_LEN_MAX RARRAY_EMBED_LEN_MAX
#define RARRAY_EMBED_LEN_SHIFT RARRAY_EMBED_LEN_SHIFT
-#if USE_TRANSIENT_HEAP
-# define RARRAY_TRANSIENT_FLAG RARRAY_TRANSIENT_FLAG
-#else
-# define RARRAY_TRANSIENT_FLAG 0
-#endif
/** @endcond */
#define RARRAY_LEN rb_array_len /**< @alias{rb_array_len} */
#define RARRAY_CONST_PTR rb_array_const_ptr /**< @alias{rb_array_const_ptr} */
-#define RARRAY_CONST_PTR_TRANSIENT rb_array_const_ptr_transient /**< @alias{rb_array_const_ptr_transient} */
/** @cond INTERNAL_MACRO */
#if defined(__fcc__) || defined(__fcc_version) || \
@@ -80,7 +62,6 @@
#define RARRAY_EMBED_LEN RARRAY_EMBED_LEN
#define RARRAY_LENINT RARRAY_LENINT
-#define RARRAY_TRANSIENT_P RARRAY_TRANSIENT_P
#define RARRAY_ASET RARRAY_ASET
#define RARRAY_PTR RARRAY_PTR
/** @endcond */
@@ -99,6 +80,8 @@
* here is at least incomplete.
*/
enum ruby_rarray_flags {
+ /* RUBY_FL_USER0 is for ELTS_SHARED */
+
/**
* This flag has something to do with memory footprint. If the array is
* "small" enough, ruby tries to be creative to abuse padding bits of
@@ -118,8 +101,6 @@ enum ruby_rarray_flags {
*/
RARRAY_EMBED_FLAG = RUBY_FL_USER1,
- /* RUBY_FL_USER2 is for ELTS_SHARED */
-
/**
* When an array employs embedded strategy (see ::RARRAY_EMBED_FLAG), these
* bits are used to store the number of elements actually filled into
@@ -130,24 +111,8 @@ 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.
*/
- RARRAY_EMBED_LEN_MASK = RUBY_FL_USER4 | RUBY_FL_USER3
-#if USE_TRANSIENT_HEAP
- ,
-
- /**
- * This flag has something to do with an array's "transiency". A transient
- * array is an array of young generation (of generational GC), who stores
- * its elements inside of dedicated memory pages called a transient heap.
- * Not every young generation share that storage scheme, but elder
- * generations must no join.
- *
- * @internal
- *
- * 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.
- */
- RARRAY_TRANSIENT_FLAG = RUBY_FL_USER13
-#endif
+ 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
};
/**
@@ -156,10 +121,7 @@ enum ruby_rarray_flags {
*/
enum ruby_rarray_consts {
/** Where ::RARRAY_EMBED_LEN_MASK resides. */
- RARRAY_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 3,
-
- /** Max possible number elements that can be embedded. */
- RARRAY_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE)
+ RARRAY_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 3
};
/** Ruby's array. */
@@ -218,7 +180,12 @@ struct RArray {
* to store its elements. In this case the length is encoded into the
* flags.
*/
- const VALUE ary[RARRAY_EMBED_LEN_MAX];
+ /* 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];
} as;
};
@@ -245,16 +212,6 @@ VALUE *rb_ary_ptr_use_start(VALUE ary);
*/
void rb_ary_ptr_use_end(VALUE a);
-#if USE_TRANSIENT_HEAP
-/**
- * Destructively converts an array of transient backend into ordinal one.
- *
- * @param[out] a An object of ::RArray.
- * @pre `a` must be a transient array.
- * @post `a` gets out of transient heap, destructively.
- */
-void rb_ary_detransient(VALUE a);
-#endif
RBIMPL_SYMBOL_EXPORT_END()
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
@@ -327,33 +284,6 @@ RARRAY_LENINT(VALUE ary)
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * Queries if the array is a transient array.
- *
- * @param[in] ary Array in question.
- * @retval true Yes it is.
- * @retval false No it isn't.
- * @pre `ary` must be an instance of ::RArray.
- *
- * @internal
- *
- * @shyouhei doesn't understand the benefit of this function called from
- * extension libraries.
- */
-static inline bool
-RARRAY_TRANSIENT_P(VALUE ary)
-{
- RBIMPL_ASSERT_TYPE(ary, RUBY_T_ARRAY);
-
-#if USE_TRANSIENT_HEAP
- return RB_FL_ANY_RAW(ary, RARRAY_TRANSIENT_FLAG);
-#else
- return false;
-#endif
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
/**
* @private
*
@@ -364,7 +294,7 @@ RBIMPL_ATTR_PURE_UNLESS_DEBUG()
* @return Its backend storage.
*/
static inline const VALUE *
-rb_array_const_ptr_transient(VALUE a)
+rb_array_const_ptr(VALUE a)
{
RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
@@ -376,110 +306,21 @@ rb_array_const_ptr_transient(VALUE a)
}
}
-#if ! USE_TRANSIENT_HEAP
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-#endif
-/**
- * @private
- *
- * This is an implementation detail of RARRAY_PTR(). People do not use it
- * directly.
- *
- * @param[in] a An object of ::RArray.
- * @return Its backend storage.
- * @post `a` is not a transient array.
- */
-static inline const VALUE *
-rb_array_const_ptr(VALUE a)
-{
- RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
-
-#if USE_TRANSIENT_HEAP
- if (RARRAY_TRANSIENT_P(a)) {
- rb_ary_detransient(a);
- }
-#endif
- return rb_array_const_ptr_transient(a);
-}
-
/**
* @private
*
* This is an implementation detail of #RARRAY_PTR_USE. People do not use it
* directly.
- *
- * @param[in] a An object of ::RArray.
- * @param[in] allow_transient Whether `a` can be transient or not.
- * @return Its backend storage.
- * @post `a` is not a transient array unless `allow_transient`.
- */
-static inline VALUE *
-rb_array_ptr_use_start(VALUE a,
- RBIMPL_ATTR_MAYBE_UNUSED()
- int allow_transient)
-{
- RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
-
-#if USE_TRANSIENT_HEAP
- if (!allow_transient) {
- if (RARRAY_TRANSIENT_P(a)) {
- rb_ary_detransient(a);
- }
- }
-#endif
-
- return rb_ary_ptr_use_start(a);
-}
-
-/**
- * @private
- *
- * This is an implementation detail of #RARRAY_PTR_USE. People do not use it
- * directly.
- *
- * @param[in] a An object of ::RArray.
- * @param[in] allow_transient Whether `a` can be transient or not.
*/
-static inline void
-rb_array_ptr_use_end(VALUE a,
- RBIMPL_ATTR_MAYBE_UNUSED()
- int allow_transient)
-{
- RBIMPL_ASSERT_TYPE(a, RUBY_T_ARRAY);
- rb_ary_ptr_use_end(a);
-}
-
-/**
- * @private
- *
- * This is an implementation detail of #RARRAY_PTR_USE. People do not use it
- * directly.
- */
-#define RBIMPL_RARRAY_STMT(flag, ary, var, expr) do { \
+#define RBIMPL_RARRAY_STMT(ary, var, expr) do { \
RBIMPL_ASSERT_TYPE((ary), RUBY_T_ARRAY); \
const VALUE rbimpl_ary = (ary); \
- VALUE *var = rb_array_ptr_use_start(rbimpl_ary, (flag)); \
+ VALUE *var = rb_ary_ptr_use_start(rbimpl_ary); \
expr; \
- rb_array_ptr_use_end(rbimpl_ary, (flag)); \
+ rb_ary_ptr_use_end(rbimpl_ary); \
} while (0)
/**
- * @private
- *
- * 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)
-
-/**
* Declares a section of code where raw pointers are used. In case you need to
* touch the raw C array instead of polite CAPIs, then that operation shall be
* wrapped using this macro.
@@ -505,37 +346,11 @@ rb_array_ptr_use_end(VALUE a,
* them use it... Maybe some transition path can be implemented later.
*/
#define RARRAY_PTR_USE(ary, ptr_name, expr) \
- 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.
- * @param ptr_name A variable name which points the C array in `expr`.
- * @param expr The expression that touches `ptr_name`.
- */
-#define RARRAY_PTR_USE_TRANSIENT(ary, ptr_name, expr) \
- RBIMPL_RARRAY_STMT(1, ary, ptr_name, expr)
+ RBIMPL_RARRAY_STMT(ary, ptr_name, expr)
/**
* Wild use of a C pointer. This function accesses the backend storage
- * directly. This is slower than #RARRAY_PTR_USE_TRANSIENT. It exercises
+ * directly. This is slower than #RARRAY_PTR_USE. It exercises
* extra manoeuvres to protect our generational GC. Use of this function is
* considered archaic. Use a modern way instead.
*
@@ -570,7 +385,7 @@ RARRAY_PTR(VALUE ary)
static inline void
RARRAY_ASET(VALUE ary, long i, VALUE v)
{
- RARRAY_PTR_USE_TRANSIENT(ary, ptr,
+ RARRAY_PTR_USE(ary, ptr,
RB_OBJ_WRITE(ary, &ptr[i], v));
}
@@ -585,6 +400,6 @@ RARRAY_ASET(VALUE ary, long i, VALUE v)
* remains as it is due to that. If we could warn such usages we can set a
* transition path, but currently no way is found to do so.
*/
-#define RARRAY_AREF(a, i) RARRAY_CONST_PTR_TRANSIENT(a)[i]
+#define RARRAY_AREF(a, i) RARRAY_CONST_PTR(a)[i]
#endif /* RBIMPL_RARRAY_H */
diff --git a/include/ruby/internal/core/rbasic.h b/include/ruby/internal/core/rbasic.h
index 4617f743a7..63cdff8e09 100644
--- a/include/ruby/internal/core/rbasic.h
+++ b/include/ruby/internal/core/rbasic.h
@@ -55,23 +55,27 @@ enum ruby_rvalue_flags {
RVALUE_EMBED_LEN_MAX = RBIMPL_RVALUE_EMBED_LEN_MAX
};
+#if (SIZEOF_VALUE < SIZEOF_UINT64_T)
+#define RBASIC_SHAPE_ID_FIELD 1
+#else
+#define RBASIC_SHAPE_ID_FIELD 0
+#endif
+
/**
- * Ruby's object's, base components. Every single ruby objects have them in
- * common.
+ * Ruby object's base components. All Ruby objects have them in common.
*/
struct
RUBY_ALIGNAS(SIZEOF_VALUE)
RBasic {
/**
- * Per-object flags. Each ruby objects have their own characteristics
- * apart from their classes. For instance whether an object is frozen or
- * not is not controlled by its class. This is where such properties are
- * stored.
+ * Per-object flags. Each Ruby object has its own characteristics apart
+ * from its class. For instance, whether an object is frozen or not is not
+ * controlled by its class. This is where such properties are stored.
*
* @see enum ::ruby_fl_type
*
- * @note This is ::VALUE rather than an enum for alignment purpose. Back
+ * @note This is ::VALUE rather than an enum for alignment purposes. Back
* in the 1990s there were no such thing like `_Alignas` in C.
*/
VALUE flags;
@@ -79,14 +83,18 @@ RBasic {
/**
* Class of an object. Every object has its class. Also, everything is an
* object in Ruby. This means classes are also objects. Classes have
- * their own classes, classes of classes have their classes, too ... and
- * it recursively continues forever.
+ * their own classes, classes of classes have their classes too, and it
+ * recursively continues forever.
*
- * Also note the `const` qualifier. In ruby an object cannot "change" its
+ * Also note the `const` qualifier. In Ruby, an object cannot "change" its
* class.
*/
const VALUE klass;
+#if RBASIC_SHAPE_ID_FIELD
+ VALUE shape_id;
+#endif
+
#ifdef __cplusplus
public:
RBIMPL_ATTR_CONSTEXPR(CXX11)
@@ -102,8 +110,14 @@ RBasic {
RBasic() :
flags(RBIMPL_VALUE_NULL),
klass(RBIMPL_VALUE_NULL)
+#if RBASIC_SHAPE_ID_FIELD
+ , shape_id(RBIMPL_VALUE_NULL)
+#endif
{
}
+# define RBASIC_INIT RBasic()
+#else
+# define RBASIC_INIT {RBIMPL_VALUE_NULL}
#endif
};
diff --git a/include/ruby/internal/core/rclass.h b/include/ruby/internal/core/rclass.h
index 13a33a28bd..6f78cc569b 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_USER1
};
struct RClass; /* Opaque, declared here for RCLASS() macro. */
diff --git a/include/ruby/internal/core/rdata.h b/include/ruby/internal/core/rdata.h
index f6656b6546..cee5e7b5ea 100644
--- a/include/ruby/internal/core/rdata.h
+++ b/include/ruby/internal/core/rdata.h
@@ -37,12 +37,8 @@
#include "ruby/defines.h"
/** @cond INTERNAL_MACRO */
-#ifdef RUBY_UNTYPED_DATA_WARNING
-# /* Take that. */
-#elif defined(RUBY_EXPORT)
-# define RUBY_UNTYPED_DATA_WARNING 1
-#else
-# define RUBY_UNTYPED_DATA_WARNING 0
+#ifndef RUBY_UNTYPED_DATA_WARNING
+#define RUBY_UNTYPED_DATA_WARNING 1
#endif
#define RBIMPL_DATA_FUNC(f) RBIMPL_CAST((void (*)(void *))(f))
@@ -146,7 +142,10 @@ struct RData {
*/
RUBY_DATA_FUNC dfree;
- /** Pointer to the actual C level struct that you want to wrap. */
+ /** Pointer to the actual C level struct that you want to wrap.
+ * This is after dmark and dfree to allow DATA_PTR to continue to work for
+ * both RData and non-embedded RTypedData.
+ */
void *data;
};
@@ -181,11 +180,6 @@ VALUE rb_data_object_wrap(VALUE klass, void *datap, RUBY_DATA_FUNC dmark, RUBY_D
*/
VALUE rb_data_object_zalloc(VALUE klass, size_t size, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree);
-/**
- * @private
- * Documented in include/ruby/internal/globals.h
- */
-RUBY_EXTERN VALUE rb_cObject;
RBIMPL_SYMBOL_EXPORT_END()
/**
@@ -331,15 +325,6 @@ rb_data_object_get_warning(VALUE obj)
return rb_data_object_get(obj);
}
-#if defined(HAVE_BUILTIN___BUILTIN_CHOOSE_EXPR_CONSTANT_P)
-# define rb_data_object_wrap_warning(klass, ptr, mark, free) \
- RB_GNUC_EXTENSION( \
- __builtin_choose_expr( \
- __builtin_constant_p(klass) && !(klass), \
- rb_data_object_wrap(klass, ptr, mark, free), \
- (rb_data_object_wrap_warning)(klass, ptr, mark, free)))
-#endif
-
/**
* This is an implementation detail of #Data_Make_Struct. People don't use it
* directly.
@@ -361,38 +346,6 @@ rb_data_object_make(VALUE klass, RUBY_DATA_FUNC mark_func, RUBY_DATA_FUNC free_f
return result;
}
-RBIMPL_ATTR_DEPRECATED(("by: rb_data_object_wrap"))
-/** @deprecated This function was renamed to rb_data_object_wrap(). */
-static inline VALUE
-rb_data_object_alloc(VALUE klass, void *data, RUBY_DATA_FUNC dmark, RUBY_DATA_FUNC dfree)
-{
- return rb_data_object_wrap(klass, data, dmark, dfree);
-}
-
-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/rfile.h b/include/ruby/internal/core/rfile.h
index f8dddde9e5..a0eb8cb833 100644
--- a/include/ruby/internal/core/rfile.h
+++ b/include/ruby/internal/core/rfile.h
@@ -25,7 +25,7 @@
/* rb_io_t is in ruby/io.h. The header file has historically not been included
* into ruby/ruby.h. We follow that tradition. */
-struct rb_io_t;
+struct rb_io;
/**
* Ruby's File and IO. Ruby's IO are not just file descriptors. They have
@@ -38,7 +38,7 @@ struct RFile {
struct RBasic basic;
/** IO's specific fields. */
- struct rb_io_t *fptr;
+ struct rb_io *fptr;
};
/**
diff --git a/include/ruby/internal/core/rhash.h b/include/ruby/internal/core/rhash.h
index 61d2c15d87..897c570794 100644
--- a/include/ruby/internal/core/rhash.h
+++ b/include/ruby/internal/core/rhash.h
@@ -54,19 +54,6 @@
*
* @internal
*
- * Declaration of rb_hash_iter_lev() is at include/ruby/backward.h.
- */
-#define RHASH_ITER_LEV(h) rb_hash_iter_lev(h)
-
-/**
- * @private
- *
- * @deprecated This macro once was a thing in the old days, but makes no sense
- * any longer today. Exists here for backwards compatibility
- * only. You can safely forget about it.
- *
- * @internal
- *
* Declaration of rb_hash_ifnone() is at include/ruby/backward.h.
*/
#define RHASH_IFNONE(h) rb_hash_ifnone(h)
diff --git a/include/ruby/internal/core/rmatch.h b/include/ruby/internal/core/rmatch.h
index 2d2fd897f5..a528c2999e 100644
--- a/include/ruby/internal/core/rmatch.h
+++ b/include/ruby/internal/core/rmatch.h
@@ -68,7 +68,7 @@ struct rmatch_offset {
};
/** Represents a match. */
-struct rmatch {
+struct rb_matchext_struct {
/**
* "Registers" of a match. This is a quasi-opaque struct that holds
* execution result of a match. Roughly resembles `&~`.
@@ -82,6 +82,8 @@ struct rmatch {
int char_offset_num_allocated;
};
+typedef struct rb_matchext_struct rb_matchext_t;
+
/**
* Regular expression execution context. When a regular expression "matches"
* to a string, it generates capture groups etc. This struct holds that info.
@@ -102,16 +104,13 @@ struct RMatch {
VALUE str;
/**
- * The result of this match.
- */
- struct rmatch *rmatch;
-
- /**
* The expression of this match.
*/
VALUE regexp; /* RRegexp */
};
+#define RMATCH_EXT(m) ((rb_matchext_t *)((char *)(m) + sizeof(struct RMatch)))
+
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
/**
@@ -139,8 +138,7 @@ static inline struct re_registers *
RMATCH_REGS(VALUE match)
{
RBIMPL_ASSERT_TYPE(match, RUBY_T_MATCH);
- RBIMPL_ASSERT_OR_ASSUME(RMATCH(match)->rmatch != NULL);
- return &RMATCH(match)->rmatch->regs;
+ return &RMATCH_EXT(match)->regs;
}
#endif /* RBIMPL_RMATCH_H */
diff --git a/include/ruby/internal/core/robject.h b/include/ruby/internal/core/robject.h
index f2028063a6..99f6470ac1 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_IVPTR ROBJECT_IVPTR
-#define ROBJECT_IV_INDEX_TBL ROBJECT_IV_INDEX_TBL
+#define ROBJECT_EMBED_LEN_MAX ROBJECT_EMBED_LEN_MAX
+#define ROBJECT_HEAP ROBJECT_HEAP
+#define ROBJECT_FIELDS_CAPACITY ROBJECT_FIELDS_CAPACITY
+#define ROBJECT_FIELDS ROBJECT_FIELDS
/** @endcond */
/**
@@ -56,10 +55,12 @@
*/
enum ruby_robject_flags {
/**
- * This flag has something to do with memory footprint. If the object is
- * "small" enough, ruby tries to be creative to abuse padding bits of
- * struct ::RObject for storing instance variables. This flag denotes that
- * situation.
+ * This flag marks that the object's instance variables are stored in an
+ * external heap buffer.
+ * Normally, instance variable references are stored inside the object slot,
+ * but if it overflow, Ruby may have to allocate a separate buffer and spills
+ * the instance variables there.
+ * This flag denotes that situation.
*
* @warning This bit has to be considered read-only. Setting/clearing
* this bit without corresponding fix up must cause immediate
@@ -72,16 +73,7 @@ enum ruby_robject_flags {
* 3rd parties must not be aware that there even is more than one way to
* store instance variables. Might better be hidden.
*/
- ROBJECT_EMBED = RUBY_FL_USER1
-};
-
-/**
- * This is an enum because GDB wants it (rather than a macro). People need not
- * bother.
- */
-enum ruby_robject_consts {
- /** Max possible number of instance variables that can be embedded. */
- ROBJECT_EMBED_LEN_MAX = RBIMPL_EMBED_LEN_MAX_OF(VALUE)
+ ROBJECT_HEAP = RUBY_FL_USER4
};
struct st_table;
@@ -103,60 +95,25 @@ 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;
-
- /**
- * This is a table that holds instance variable name to index
- * mapping. Used when accessing instance variables using names.
- *
- * @internal
- *
- * This is a shortcut for `RCLASS_IV_INDEX_TBL(rb_obj_class(obj))`.
- */
- struct st_table *iv_index_tbl;
+ VALUE *fields;
} heap;
- /**
- * Embedded instance variables. When an object is small enough, it
+ /* 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[ROBJECT_EMBED_LEN_MAX];
+ VALUE ary[1];
} 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;
- }
-}
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
* Queries the instance variables.
*
* @param[in] obj Object in question.
@@ -168,17 +125,17 @@ RBIMPL_ATTR_ARTIFICIAL()
* @shyouhei finds no reason for this to be visible from extension libraries.
*/
static inline VALUE *
-ROBJECT_IVPTR(VALUE obj)
+ROBJECT_FIELDS(VALUE obj)
{
RBIMPL_ASSERT_TYPE(obj, RUBY_T_OBJECT);
struct RObject *const ptr = ROBJECT(obj);
- if (RB_FL_ANY_RAW(obj, ROBJECT_EMBED)) {
- return ptr->as.ary;
+ if (RB_UNLIKELY(RB_FL_ANY_RAW(obj, ROBJECT_HEAP))) {
+ return ptr->as.heap.fields;
}
else {
- return ptr->as.heap.ivptr;
+ return ptr->as.ary;
}
}
diff --git a/include/ruby/internal/core/rstring.h b/include/ruby/internal/core/rstring.h
index a682dbe22f..35175ea94a 100644
--- a/include/ruby/internal/core/rstring.h
+++ b/include/ruby/internal/core/rstring.h
@@ -42,13 +42,7 @@
/** @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
#define RSTRING_LENINT RSTRING_LENINT
#define RSTRING_PTR RSTRING_PTR
@@ -162,21 +156,6 @@ 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
- * ::RString::ary.
- *
- * @internal
- *
- * 3rd parties must not be aware that there even is more than one way to
- * store a string. Might better be hidden.
- */
- 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.*/
@@ -202,20 +181,6 @@ 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.
- */
-enum ruby_rstring_consts {
- /** Where ::RSTRING_EMBED_LEN_MASK resides. */
- RSTRING_EMBED_LEN_SHIFT = RUBY_FL_USHIFT + 2,
-
- /** 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:
*
@@ -233,6 +198,13 @@ struct RString {
/** Basic part, including flags and class. */
struct RBasic basic;
+ /**
+ * Length of the string, not including terminating NUL character.
+ *
+ * @note This is in bytes.
+ */
+ long len;
+
/** String's specific fields. */
union {
@@ -241,14 +213,6 @@ struct RString {
* pattern.
*/
struct {
-
- /**
- * Length of the string, not including terminating NUL character.
- *
- * @note This is in bytes.
- */
- long len;
-
/**
* Pointer to the contents of the string. In the old days each
* string had dedicated memory regions. That is no longer true
@@ -279,24 +243,12 @@ struct RString {
/** Embedded contents. */
struct {
-#if USE_RVARGC
- short 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;
};
@@ -409,80 +361,12 @@ RBIMPL_ATTR_ARTIFICIAL()
*
* @param[in] str String in question.
* @return Its length, in bytes.
- * @pre `str` must be an instance of ::RString, and must has its
- * ::RSTRING_NOEMBED flag off.
- *
- * @internal
- *
- * This was a macro before. It was inevitable to be public, since macros are
- * global constructs. But should it be forever? Now that it is a function,
- * @shyouhei thinks it could just be eliminated, hidden into implementation
- * details.
- */
-static inline long
-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
- short f = RSTRING(str)->as.embed.len;
-#else
- VALUE f = RBASIC(str)->flags;
- f &= RSTRING_EMBED_LEN_MASK;
- f >>= RSTRING_EMBED_LEN_SHIFT;
-#endif
- return RBIMPL_CAST((long)f);
-}
-
-RBIMPL_WARNING_PUSH()
-#if RBIMPL_COMPILER_IS(Intel)
-RBIMPL_WARNING_IGNORED(413)
-#endif
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * @private
- *
- * "Expands" an embedded string into an ordinal one. This is a function that
- * returns aggregated type. The returned struct always has its `as.heap.len`
- * an `as.heap.ptr` fields set appropriately.
- *
- * This is an implementation detail that 3rd parties should never bother.
- */
-static inline struct RString
-rbimpl_rstring_getmem(VALUE str)
-{
- RBIMPL_ASSERT_TYPE(str, RUBY_T_STRING);
-
- if (RB_FL_ANY_RAW(str, RSTRING_NOEMBED)) {
- return *RSTRING(str);
- }
- else {
- /* Expecting compilers to optimize this on-stack struct away. */
- struct RString retval;
- retval.as.heap.len = RSTRING_EMBED_LEN(str);
- retval.as.heap.ptr = RSTRING(str)->as.embed.ary;
- return retval;
- }
-}
-
-RBIMPL_WARNING_POP()
-
-RBIMPL_ATTR_PURE_UNLESS_DEBUG()
-RBIMPL_ATTR_ARTIFICIAL()
-/**
- * Queries the length of the string.
- *
- * @param[in] str String in question.
- * @return Its length, in bytes.
* @pre `str` must be an instance of ::RString.
*/
static inline long
RSTRING_LEN(VALUE str)
{
- return rbimpl_rstring_getmem(str).as.heap.len;
+ return RSTRING(str)->len;
}
RBIMPL_ATTR_ARTIFICIAL()
@@ -496,15 +380,13 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline char *
RSTRING_PTR(VALUE str)
{
- char *ptr = rbimpl_rstring_getmem(str).as.heap.ptr;
+ char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ?
+ RSTRING(str)->as.heap.ptr :
+ RSTRING(str)->as.embed.ary;
- if (RB_UNLIKELY(! ptr)) {
+ if (RUBY_DEBUG && RB_UNLIKELY(! ptr)) {
/* :BEWARE: @shyouhei thinks that currently, there are rooms for this
- * function to return NULL. In the 20th century that was a pointless
- * concern. However struct RString can hold fake strings nowadays. It
- * seems no check against NULL are exercised around handling of them
- * (one of such usages is located in marshal.c, which scares
- * @shyouhei). Better check here for maximum safety.
+ * function to return NULL. Better check here for maximum safety.
*
* Also, this is not rb_warn() because RSTRING_PTR() can be called
* during GC (see what obj_info() does). rb_warn() needs to allocate
@@ -526,14 +408,17 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline char *
RSTRING_END(VALUE str)
{
- struct RString buf = rbimpl_rstring_getmem(str);
+ char *ptr = RB_FL_TEST_RAW(str, RSTRING_NOEMBED) ?
+ RSTRING(str)->as.heap.ptr :
+ RSTRING(str)->as.embed.ary;
+ long len = RSTRING_LEN(str);
- if (RB_UNLIKELY(! buf.as.heap.ptr)) {
+ if (RUBY_DEBUG && RB_UNLIKELY(!ptr)) {
/* Ditto. */
rb_debug_rstring_null_ptr("RSTRING_END");
}
- return &buf.as.heap.ptr[buf.as.heap.len];
+ return &ptr[len];
}
RBIMPL_ATTR_ARTIFICIAL()
@@ -562,16 +447,7 @@ RSTRING_LENINT(VALUE str)
* @param ptrvar Variable where its contents is stored.
* @param lenvar Variable where its length is stored.
*/
-#ifdef HAVE_STMT_AND_DECL_IN_EXPR
-# define RSTRING_GETMEM(str, ptrvar, lenvar) \
- __extension__ ({ \
- struct RString rbimpl_str = rbimpl_rstring_getmem(str); \
- (ptrvar) = rbimpl_str.as.heap.ptr; \
- (lenvar) = rbimpl_str.as.heap.len; \
- })
-#else
# define RSTRING_GETMEM(str, ptrvar, lenvar) \
((ptrvar) = RSTRING_PTR(str), \
(lenvar) = RSTRING_LEN(str))
-#endif /* HAVE_STMT_AND_DECL_IN_EXPR */
#endif /* RBIMPL_RSTRING_H */
diff --git a/include/ruby/internal/core/rstruct.h b/include/ruby/internal/core/rstruct.h
index 69be487b59..0028a1bdcd 100644
--- a/include/ruby/internal/core/rstruct.h
+++ b/include/ruby/internal/core/rstruct.h
@@ -31,18 +31,6 @@
# include "ruby/backward.h"
#endif
-/**
- * @private
- *
- * @deprecated This macro once was a thing in the old days, but makes no sense
- * any longer today. Exists here for backwards compatibility
- * only. You can safely forget about it.
- *
- * @internal
- *
- * Declaration of rb_struct_ptr() is at include/ruby/backward.h.
- */
-#define RSTRUCT_PTR(st) rb_struct_ptr(st)
/** @cond INTERNAL_MACRO */
#define RSTRUCT_LEN RSTRUCT_LEN
#define RSTRUCT_SET RSTRUCT_SET
diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h
index bbf208867d..ec0794e387 100644
--- a/include/ruby/internal/core/rtypeddata.h
+++ b/include/ruby/internal/core/rtypeddata.h
@@ -37,6 +37,7 @@
#include "ruby/internal/dllexport.h"
#include "ruby/internal/error.h"
#include "ruby/internal/fl_type.h"
+#include "ruby/internal/static_assert.h"
#include "ruby/internal/stdbool.h"
#include "ruby/internal/value_type.h"
@@ -108,11 +109,17 @@
/** @cond INTERNAL_MACRO */
#define RTYPEDDATA_P RTYPEDDATA_P
#define RTYPEDDATA_TYPE RTYPEDDATA_TYPE
+#define TYPED_DATA_EMBEDDED ((VALUE)1)
+#define TYPED_DATA_PTR_MASK (~(TYPED_DATA_EMBEDDED))
+/** @endcond */
+
+/**
+ * Macros to see if each corresponding flag is defined.
+ */
#define RUBY_TYPED_FREE_IMMEDIATELY RUBY_TYPED_FREE_IMMEDIATELY
#define RUBY_TYPED_FROZEN_SHAREABLE RUBY_TYPED_FROZEN_SHAREABLE
#define RUBY_TYPED_WB_PROTECTED RUBY_TYPED_WB_PROTECTED
#define RUBY_TYPED_PROMOTED1 RUBY_TYPED_PROMOTED1
-/** @endcond */
/**
* @private
@@ -137,6 +144,8 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FREE_IMMEDIATELY = 1,
+ RUBY_TYPED_EMBEDDABLE = 2,
+
/**
* This flag has something to do with Ractor. Multiple Ractors run without
* protecting each other. Sharing an object among Ractors is basically
@@ -151,6 +160,12 @@ rbimpl_typeddata_flags {
*/
RUBY_TYPED_FROZEN_SHAREABLE = RUBY_FL_SHAREABLE,
+ // experimental flag
+ // Similar to RUBY_TYPED_FROZEN_SHAREABLE, but doesn't make shareable
+ // reachable objects from this T_DATA object on the Ractor.make_shareable.
+ // If it refers to unshareable objects, simply raise an error.
+ // RUBY_TYPED_FROZEN_SHAREABLE_NO_REC = RUBY_FL_FINALIZE,
+
/**
* This flag has something to do with our garbage collector. These days
* ruby objects are "generational". There are those who are young and
@@ -173,10 +188,16 @@ rbimpl_typeddata_flags {
RUBY_TYPED_WB_PROTECTED = RUBY_FL_WB_PROTECTED, /* THIS FLAG DEPENDS ON Ruby version */
/**
- * This flag is mysterious. It seems nobody is currently using it. The
- * intention of this flag is also unclear. We need further investigations.
+ * This flag is used to distinguish RTypedData from deprecated RData objects.
*/
- RUBY_TYPED_PROMOTED1 = RUBY_FL_PROMOTED1 /* THIS FLAG DEPENDS ON Ruby version */
+ RUBY_TYPED_FL_IS_TYPED_DATA = RUBY_FL_USERPRIV0,
+
+ /**
+ * This flag determines whether marking and compaction should be carried out
+ * using the dmark/dcompact callback functions or whether we should mark
+ * declaratively using a list of references defined inside the data struct we're wrapping
+ */
+ RUBY_TYPED_DECL_MARKING = RUBY_FL_USER2
};
/**
@@ -241,10 +262,15 @@ struct rb_data_type_struct {
RUBY_DATA_FUNC dcompact;
/**
- * This field is reserved for future extension. For now, it must be
- * filled with zeros.
+ * @internal
*/
- void *reserved[1]; /* For future extension.
+ void (*handle_weak_references)(void *);
+
+ /**
+ * This field is reserved for future extension. For now, it must be
+ * filled with zeros.
+ */
+ void *reserved[7]; /* For future extension.
This array *must* be filled with ZERO. */
} function;
@@ -342,26 +368,28 @@ struct RTypedData {
/** The part that all ruby objects have in common. */
struct RBasic basic;
- /**
- * This field stores various information about how Ruby should handle a
- * data. This roughly resembles a Ruby level class (apart from method
- * definition etc.)
- */
- const rb_data_type_t *type;
+ /** Direct reference to the slots that holds instance variables, if any **/
+ VALUE fields_obj;
/**
- * This has to be always 1.
+ * This is a `const rb_data_type_t *const` value, with the low bits set:
*
- * @internal
+ * 1: Set if object is embedded.
*
- * Why, then, this is not a const ::VALUE?
+ * This field stores various information about how Ruby should handle a
+ * data. This roughly resembles a Ruby level class (apart from method
+ * definition etc.)
*/
- VALUE typed_flag;
+ const VALUE type;
/** Pointer to the actual C level struct that you want to wrap. */
void *data;
};
+#if !defined(__cplusplus) || __cplusplus >= 201103L
+RBIMPL_STATIC_ASSERT(data_in_rtypeddata, offsetof(struct RData, data) == offsetof(struct RTypedData, data));
+#endif
+
RBIMPL_SYMBOL_EXPORT_BEGIN()
RBIMPL_ATTR_NONNULL((3))
/**
@@ -376,6 +404,7 @@ RBIMPL_ATTR_NONNULL((3))
*/
VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *type);
+RBIMPL_ATTR_NONNULL((3))
/**
* Identical to rb_data_typed_object_wrap(), except it allocates a new data
* region internally instead of taking an existing one. The allocation is done
@@ -391,6 +420,7 @@ VALUE rb_data_typed_object_wrap(VALUE klass, void *datap, const rb_data_type_t *
*/
VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t *type);
+RBIMPL_ATTR_NONNULL(())
/**
* Checks for the domestic relationship between the two.
*
@@ -405,6 +435,7 @@ VALUE rb_data_typed_object_zalloc(VALUE klass, size_t size, const rb_data_type_t
*/
int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *parent);
+RBIMPL_ATTR_NONNULL((2))
/**
* Checks if the given object is of given kind.
*
@@ -415,6 +446,7 @@ int rb_typeddata_inherited_p(const rb_data_type_t *child, const rb_data_type_t *
*/
int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type);
+RBIMPL_ATTR_NONNULL((2))
/**
* Identical to rb_typeddata_is_kind_of(), except it raises exceptions instead
* of returning false.
@@ -426,8 +458,49 @@ int rb_typeddata_is_kind_of(VALUE obj, const rb_data_type_t *data_type);
* @post Upon successful return `obj`'s type is guaranteed `data_type`.
*/
void *rb_check_typeddata(VALUE obj, const rb_data_type_t *data_type);
+
+RBIMPL_ATTR_NORETURN()
+RBIMPL_ATTR_NONNULL((2))
+/**
+ * @private
+ *
+ * Fails with the given object's type incompatibility to the type.
+ *
+ * This is an implementation detail of Check_Type. People don't use it
+ * directly.
+ *
+ * @param[in] obj The object in question.
+ * @param[in] expected Name of expected data type of `obj`.
+ */
+void rb_unexpected_object_type(VALUE obj, const char *expected);
+
+RBIMPL_ATTR_NORETURN()
+RBIMPL_ATTR_NONNULL(())
+/**
+ * @private
+ *
+ * Fails with the given object's type incompatibility to the type.
+ *
+ * This is an implementation detail of #TypedData_Make_Struct. People don't
+ * use it directly.
+ *
+ * @param[in] actual Actual data type.
+ * @param[in] expected Expected data type.
+ */
+void rb_unexpected_typeddata(const rb_data_type_t *actual, const rb_data_type_t *expected);
RBIMPL_SYMBOL_EXPORT_END()
+#if RUBY_DEBUG
+# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \
+ while (RB_UNLIKELY(!RB_TYPE_P(obj, RUBY_T_DATA))) { \
+ rb_unexpected_object_type(obj, "Data"); \
+ unreachable; \
+ }
+#else
+# define RBIMPL_TYPEDDATA_PRECONDITION(obj, unreachable) \
+ RBIMPL_ASSERT_NOTHING
+#endif
+
/**
* Converts sval, a pointer to your struct, into a Ruby object.
*
@@ -456,14 +529,13 @@ RBIMPL_SYMBOL_EXPORT_END()
*/
#define TypedData_Make_Struct0(result, klass, type, size, data_type, sval) \
VALUE result = rb_data_typed_object_zalloc(klass, size, data_type); \
- (sval) = RBIMPL_CAST((type *)RTYPEDDATA_DATA(result)); \
+ (sval) = RBIMPL_CAST((type *)rbimpl_typeddata_get_data(result)); \
RBIMPL_CAST(/*suppress unused variable warnings*/(void)(sval))
/**
* Identical to #TypedData_Wrap_Struct, except it allocates a new data region
* internally instead of taking an existing one. The allocation is done using
- * ruby_calloc(). Hence it makes no sense for `data_type->function.dfree` to
- * be anything other than ::RUBY_TYPED_DEFAULT_FREE.
+ * ruby_calloc().
*
* @param klass Ruby level class of the object.
* @param type Type name of the C struct.
@@ -494,18 +566,37 @@ RBIMPL_SYMBOL_EXPORT_END()
sizeof(type))
#endif
-/**
- * Obtains a C struct from inside of a wrapper Ruby object.
- *
- * @param obj An instance of ::RTypedData.
- * @param type Type name of the C struct.
- * @param data_type The data type describing `type`.
- * @param sval Variable name of obtained C struct.
- * @exception rb_eTypeError `obj` is not a kind of `data_type`.
- * @return Unwrapped C struct that `obj` holds.
- */
-#define TypedData_Get_Struct(obj,type,data_type,sval) \
- ((sval) = RBIMPL_CAST((type *)rb_check_typeddata((obj), (data_type))))
+static inline bool
+rbimpl_typeddata_embedded_p(VALUE obj)
+{
+ return (RTYPEDDATA(obj)->type) & TYPED_DATA_EMBEDDED;
+}
+
+RBIMPL_ATTR_DEPRECATED_INTERNAL_ONLY()
+static inline bool
+RTYPEDDATA_EMBEDDED_P(VALUE obj)
+{
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
+
+ return rbimpl_typeddata_embedded_p(obj);
+}
+
+static inline void *
+rbimpl_typeddata_get_data(VALUE obj)
+{
+ /* We reuse the data pointer in embedded TypedData. */
+ return rbimpl_typeddata_embedded_p(obj) ?
+ RBIMPL_CAST((void *)&RTYPEDDATA_DATA(obj)) :
+ RTYPEDDATA_DATA(obj);
+}
+
+static inline void *
+RTYPEDDATA_GET_DATA(VALUE obj)
+{
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL));
+
+ return rbimpl_typeddata_get_data(obj);
+}
RBIMPL_ATTR_PURE()
RBIMPL_ATTR_ARTIFICIAL()
@@ -523,7 +614,28 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline bool
rbimpl_rtypeddata_p(VALUE obj)
{
- return RTYPEDDATA(obj)->typed_flag == 1;
+ return FL_TEST_RAW(obj, RUBY_TYPED_FL_IS_TYPED_DATA);
+}
+
+RBIMPL_ATTR_PURE()
+RBIMPL_ATTR_ARTIFICIAL()
+/**
+ * @private
+ *
+ * Identical to rbimpl_rtypeddata_p(), except it is allowed to call on non-data
+ * objects.
+ *
+ * This is an implementation detail of inline functions defined in this file.
+ * People don't use it directly.
+ *
+ * @param[in] obj Object in question
+ * @retval true `obj` is an instance of ::RTypedData.
+ * @retval false `obj` is not an instance of ::RTypedData
+ */
+static inline bool
+rbimpl_obj_typeddata_p(VALUE obj)
+{
+ return RB_TYPE_P(obj, RUBY_T_DATA) && rbimpl_rtypeddata_p(obj);
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
@@ -539,19 +651,14 @@ RBIMPL_ATTR_ARTIFICIAL()
static inline bool
RTYPEDDATA_P(VALUE obj)
{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(! RB_TYPE_P(obj, RUBY_T_DATA))) {
- Check_Type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(false);
- }
-#endif
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(false));
return rbimpl_rtypeddata_p(obj);
}
RBIMPL_ATTR_PURE_UNLESS_DEBUG()
RBIMPL_ATTR_ARTIFICIAL()
-/* :TODO: can this function be __attribute__((returns_nonnull)) or not? */
+RBIMPL_ATTR_RETURNS_NONNULL()
/**
* Queries for the type of given object.
*
@@ -559,19 +666,77 @@ RBIMPL_ATTR_ARTIFICIAL()
* @return Data type struct that corresponds to `obj`.
* @pre `obj` must be an instance of ::RTypedData.
*/
-static inline const struct rb_data_type_struct *
+static inline const rb_data_type_t *
RTYPEDDATA_TYPE(VALUE obj)
{
-#if RUBY_DEBUG
- if (RB_UNLIKELY(! RTYPEDDATA_P(obj))) {
- rb_unexpected_type(obj, RUBY_T_DATA);
- RBIMPL_UNREACHABLE_RETURN(NULL);
+ RBIMPL_TYPEDDATA_PRECONDITION(obj, RBIMPL_UNREACHABLE_RETURN(NULL));
+
+ VALUE type = RTYPEDDATA(obj)->type & TYPED_DATA_PTR_MASK;
+ const rb_data_type_t *ptr = RBIMPL_CAST((const rb_data_type_t *)type);
+ RBIMPL_ASSERT_OR_ASSUME(ptr);
+ return ptr;
+}
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL(())
+static inline bool
+rbimpl_typeddata_inherited_p_inline(const rb_data_type_t *child, const rb_data_type_t *parent)
+{
+ do {
+ if (RB_LIKELY(child == parent)) return true;
+ } while ((child = child->parent) != NULL);
+ return false;
+}
+#define rb_typeddata_inherited_p rbimpl_typeddata_inherited_p_inline
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL((2))
+static inline bool
+rbimpl_typeddata_is_kind_of_inline(VALUE obj, const rb_data_type_t *data_type)
+{
+ if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) return false;
+ return rb_typeddata_inherited_p(RTYPEDDATA_TYPE(obj), data_type);
+}
+#define rb_typeddata_is_kind_of rbimpl_typeddata_is_kind_of_inline
+
+RBIMPL_ATTR_ARTIFICIAL()
+RBIMPL_ATTR_NONNULL((2))
+/**
+ * @private
+ *
+ * This is an implementation detail of TypedData_Get_Struct(). Don't use it
+ * directly.
+ */
+static inline void *
+rbimpl_check_typeddata(VALUE obj, const rb_data_type_t *expected_type)
+{
+ if (RB_UNLIKELY(!rbimpl_obj_typeddata_p(obj))) {
+ rb_unexpected_object_type(obj, expected_type->wrap_struct_name);
+ }
+
+ const rb_data_type_t *actual_type = RTYPEDDATA_TYPE(obj);
+ if (RB_UNLIKELY(!rb_typeddata_inherited_p(actual_type, expected_type))){
+ rb_unexpected_typeddata(actual_type, expected_type);
}
-#endif
- return RTYPEDDATA(obj)->type;
+ return RTYPEDDATA_GET_DATA(obj);
}
+
+/**
+ * Obtains a C struct from inside of a wrapper Ruby object.
+ *
+ * @param obj An instance of ::RTypedData.
+ * @param type Type name of the C struct.
+ * @param data_type The data type describing `type`.
+ * @param sval Variable name of obtained C struct.
+ * @exception rb_eTypeError `obj` is not a kind of `data_type`.
+ * @return Unwrapped C struct that `obj` holds.
+ */
+#define TypedData_Get_Struct(obj,type,data_type,sval) \
+ ((sval) = RBIMPL_CAST((type *)rbimpl_check_typeddata((obj), (data_type))))
+
+RBIMPL_ATTR_NONNULL((2))
/**
* While we don't stop you from using this function, it seems to be an
* implementation detail of #TypedData_Make_Struct, which is preferred over
@@ -593,12 +758,4 @@ rb_data_typed_object_make(VALUE klass, const rb_data_type_t *type, void **datap,
return result;
}
-RBIMPL_ATTR_DEPRECATED(("by: rb_data_typed_object_wrap"))
-/** @deprecated This function was renamed to rb_data_typed_object_wrap(). */
-static inline VALUE
-rb_data_typed_object_alloc(VALUE klass, void *datap, const rb_data_type_t *type)
-{
- return rb_data_typed_object_wrap(klass, datap, type);
-}
-
#endif /* RBIMPL_RTYPEDDATA_H */