mirror of
https://github.com/ruby/ruby.git
synced 2026-01-26 12:14:51 +00:00
RSTRUCT_LEN / RSTRUCT_GET / RSTRUCT_SET all existing in two versions, one public that does type and frozens checks and one private that doesn't. The problem is that this is error prone because the public version is always accessible, but the private one require to include `internal/struct.h`. So you may have some code that rely on the public version, and later on the private header is included and changes the behavior. This already led to introducing a bug in YJIT & ZJIT: https://github.com/ruby/ruby/pull/15835
141 lines
4.0 KiB
C
141 lines
4.0 KiB
C
#ifndef INTERNAL_STRUCT_H /*-*-C-*-vi:se ft=c:*/
|
|
#define INTERNAL_STRUCT_H
|
|
/**
|
|
* @author Ruby developers <ruby-core@ruby-lang.org>
|
|
* @copyright This file is a part of the programming language Ruby.
|
|
* Permission is hereby granted, to either redistribute and/or
|
|
* modify this file, provided that the conditions mentioned in the
|
|
* file COPYING are met. Consult the file for details.
|
|
* @brief Internal header for Struct.
|
|
*/
|
|
#include "ruby/internal/stdbool.h" /* for bool */
|
|
#include "ruby/ruby.h" /* for struct RBasic */
|
|
|
|
/* Flags of RStruct
|
|
*
|
|
* 1-7: RSTRUCT_EMBED_LEN
|
|
* If non-zero, the struct is embedded (its contents follow the
|
|
* header, rather than being on a separately allocated buffer) and
|
|
* these bits are the length of the Struct.
|
|
* 8: RSTRUCT_GEN_FIELDS
|
|
* The struct is embedded and has no space left to store the
|
|
* IMEMO/fields reference. Any ivar this struct may have will be in
|
|
* the generic_fields_tbl. This flag doesn't imply the struct has
|
|
* ivars.
|
|
*/
|
|
enum {
|
|
RSTRUCT_EMBED_LEN_MASK = RUBY_FL_USER7 | RUBY_FL_USER6 | RUBY_FL_USER5 | RUBY_FL_USER4 |
|
|
RUBY_FL_USER3 | RUBY_FL_USER2 | RUBY_FL_USER1,
|
|
RSTRUCT_EMBED_LEN_SHIFT = (RUBY_FL_USHIFT+1),
|
|
RSTRUCT_GEN_FIELDS = RUBY_FL_USER8,
|
|
};
|
|
|
|
struct RStruct {
|
|
struct RBasic basic;
|
|
union {
|
|
struct {
|
|
long len;
|
|
const VALUE *ptr;
|
|
VALUE fields_obj;
|
|
} heap;
|
|
/* 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;
|
|
};
|
|
|
|
#define RSTRUCT(obj) ((struct RStruct *)(obj))
|
|
|
|
/* struct.c */
|
|
VALUE rb_struct_init_copy(VALUE copy, VALUE s);
|
|
VALUE rb_struct_lookup(VALUE s, VALUE idx);
|
|
VALUE rb_struct_s_keyword_init(VALUE klass);
|
|
static inline long RSTRUCT_EMBED_LEN(VALUE st);
|
|
static inline long RSTRUCT_LEN_RAW(VALUE st);
|
|
static inline int RSTRUCT_LENINT(VALUE st);
|
|
static inline const VALUE *RSTRUCT_CONST_PTR(VALUE st);
|
|
static inline void RSTRUCT_SET_RAW(VALUE st, long k, VALUE v);
|
|
static inline VALUE RSTRUCT_GET_RAW(VALUE st, long k);
|
|
|
|
static inline long
|
|
RSTRUCT_EMBED_LEN(VALUE st)
|
|
{
|
|
long ret = FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK);
|
|
ret >>= RSTRUCT_EMBED_LEN_SHIFT;
|
|
return ret;
|
|
}
|
|
|
|
static inline long
|
|
RSTRUCT_LEN_RAW(VALUE st)
|
|
{
|
|
if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) {
|
|
return RSTRUCT_EMBED_LEN(st);
|
|
}
|
|
else {
|
|
return RSTRUCT(st)->as.heap.len;
|
|
}
|
|
}
|
|
|
|
static inline int
|
|
RSTRUCT_LENINT(VALUE st)
|
|
{
|
|
return rb_long2int(RSTRUCT_LEN_RAW(st));
|
|
}
|
|
|
|
static inline const VALUE *
|
|
RSTRUCT_CONST_PTR(VALUE st)
|
|
{
|
|
const struct RStruct *p = RSTRUCT(st);
|
|
|
|
if (FL_TEST_RAW(st, RSTRUCT_EMBED_LEN_MASK)) {
|
|
return p->as.ary;
|
|
}
|
|
else {
|
|
return p->as.heap.ptr;
|
|
}
|
|
}
|
|
|
|
static inline void
|
|
RSTRUCT_SET_RAW(VALUE st, long k, VALUE v)
|
|
{
|
|
RB_OBJ_WRITE(st, &RSTRUCT_CONST_PTR(st)[k], v);
|
|
}
|
|
|
|
static inline VALUE
|
|
RSTRUCT_GET_RAW(VALUE st, long k)
|
|
{
|
|
return RSTRUCT_CONST_PTR(st)[k];
|
|
}
|
|
|
|
static inline VALUE
|
|
RSTRUCT_FIELDS_OBJ(VALUE st)
|
|
{
|
|
const long embed_len = RSTRUCT_EMBED_LEN(st);
|
|
VALUE fields_obj;
|
|
if (embed_len) {
|
|
RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
|
|
fields_obj = RSTRUCT_GET_RAW(st, embed_len);
|
|
}
|
|
else {
|
|
fields_obj = RSTRUCT(st)->as.heap.fields_obj;
|
|
}
|
|
return fields_obj;
|
|
}
|
|
|
|
static inline void
|
|
RSTRUCT_SET_FIELDS_OBJ(VALUE st, VALUE fields_obj)
|
|
{
|
|
const long embed_len = RSTRUCT_EMBED_LEN(st);
|
|
if (embed_len) {
|
|
RUBY_ASSERT(!FL_TEST_RAW(st, RSTRUCT_GEN_FIELDS));
|
|
RSTRUCT_SET_RAW(st, embed_len, fields_obj);
|
|
}
|
|
else {
|
|
RB_OBJ_WRITE(st, &RSTRUCT(st)->as.heap.fields_obj, fields_obj);
|
|
}
|
|
}
|
|
#endif /* INTERNAL_STRUCT_H */
|