mirror of
https://github.com/ruby/ruby.git
synced 2026-10-28 16:36:20 +08:00
Only imemo_count_up and imemo_count_value treat the count as unsigned, so keep cnt as rb_len_t for the other users of MEMO and give them their own member. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
303 lines
8.7 KiB
C
303 lines
8.7 KiB
C
#ifndef INTERNAL_IMEMO_H /*-*-C-*-vi:se ft=c:*/
|
|
#define INTERNAL_IMEMO_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 IMEMO: Internal memo object.
|
|
*/
|
|
#include "ruby/internal/config.h"
|
|
#include <stddef.h> /* for size_t */
|
|
#include "id_table.h"
|
|
#include "internal/array.h" /* for rb_ary_hidden_new_fill */
|
|
#include "ruby/internal/stdbool.h" /* for bool */
|
|
#include "ruby/ruby.h" /* for rb_block_call_func_t */
|
|
|
|
struct rb_gc_mark_ctx; /* internal/gc.h */
|
|
|
|
#define IMEMO_MASK (FL_USER0 | FL_USER1 | FL_USER2 | FL_USER3 | FL_USER4)
|
|
|
|
/* FL_USER0 to FL_USER4 is for type */
|
|
#define IMEMO_FL_USHIFT (FL_USHIFT + 5)
|
|
#define IMEMO_FL_USER0 FL_USER5
|
|
#define IMEMO_FL_USER1 FL_USER6
|
|
#define IMEMO_FL_USER2 FL_USER7
|
|
#define IMEMO_FL_USER3 FL_USER8
|
|
#define IMEMO_FL_USER4 FL_USER9
|
|
#define IMEMO_FL_USER5 FL_USER10
|
|
#define IMEMO_FL_USER6 FL_USER11
|
|
|
|
enum imemo_type {
|
|
imemo_env = 0,
|
|
imemo_cref = 1, /*!< class reference */
|
|
imemo_svar = 2, /*!< special variable */
|
|
imemo_throw_data = 3,
|
|
imemo_ifunc = 4, /*!< iterator function */
|
|
imemo_memo = 5,
|
|
imemo_ment = 6,
|
|
imemo_iseq = 7,
|
|
imemo_tmpbuf = 8,
|
|
imemo_cvar_entry = 9,
|
|
imemo_callinfo = 10,
|
|
imemo_callcache = 11,
|
|
imemo_constcache = 12,
|
|
imemo_fields = 13,
|
|
imemo_subclasses = 14,
|
|
imemo_cdhash = 15,
|
|
};
|
|
|
|
/* CREF (Class REFerence) is defined in method.h */
|
|
|
|
/*! SVAR (Special VARiable) */
|
|
struct vm_svar {
|
|
VALUE flags;
|
|
const VALUE cref_or_me; /*!< class reference or rb_method_entry_t */
|
|
const VALUE lastline;
|
|
const VALUE backref;
|
|
const VALUE others;
|
|
};
|
|
|
|
/*! THROW_DATA */
|
|
struct vm_throw_data {
|
|
VALUE flags;
|
|
const VALUE throw_obj;
|
|
const struct rb_control_frame_struct *catch_frame;
|
|
int throw_state;
|
|
};
|
|
|
|
#define THROW_DATA_CONSUMED IMEMO_FL_USER0
|
|
|
|
/* IFUNC (Internal FUNCtion) */
|
|
|
|
struct vm_ifunc_argc {
|
|
#if SIZEOF_INT * 2 > SIZEOF_VALUE
|
|
signed int min: (SIZEOF_VALUE * CHAR_BIT) / 2;
|
|
signed int max: (SIZEOF_VALUE * CHAR_BIT) / 2;
|
|
#else
|
|
int min, max;
|
|
#endif
|
|
};
|
|
|
|
/*! IFUNC (Internal FUNCtion)
|
|
*
|
|
* Bookkeeping for converting a C function and some closed-over data into a
|
|
* block passable to methods. Like Ruby Proc, but not directly accessible at
|
|
* Ruby level since this is an imemo. See rb_block_call() and friends.
|
|
*/
|
|
struct vm_ifunc {
|
|
VALUE flags;
|
|
VALUE *svar_lep;
|
|
rb_block_call_func_t func;
|
|
const void *data;
|
|
struct vm_ifunc_argc argc;
|
|
};
|
|
#define IFUNC_YIELD_OPTIMIZABLE IMEMO_FL_USER0
|
|
|
|
struct rb_imemo_tmpbuf_struct {
|
|
VALUE flags;
|
|
VALUE *ptr; /* malloc'ed buffer */
|
|
size_t size; /* buffer size in bytes */
|
|
bool marked; /* whether the buffer may contain object references */
|
|
};
|
|
|
|
struct rb_imemo_cdhash {
|
|
VALUE flags;
|
|
st_table tbl;
|
|
};
|
|
|
|
/* Set on imemo_memo when u3 holds a VALUE that GC must mark.
|
|
* When unset, u3 is a non-VALUE (cnt/ucnt/state). */
|
|
#define MEMO_U3_IS_VALUE IMEMO_FL_USER0
|
|
|
|
/*! MEMO
|
|
*
|
|
* @see imemo_type
|
|
* */
|
|
struct MEMO {
|
|
VALUE flags;
|
|
const VALUE v1;
|
|
const VALUE v2;
|
|
union {
|
|
rb_len_t cnt;
|
|
rb_ulen_t ucnt;
|
|
long state;
|
|
const VALUE value;
|
|
} u3;
|
|
};
|
|
|
|
#define IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), false))
|
|
#define SHAREABLE_IMEMO_NEW(T, type, v0) ((T *)rb_imemo_new((type), (v0), sizeof(T), true))
|
|
|
|
/* ment is in method.h */
|
|
|
|
#define THROW_DATA_P(err) imemo_throw_data_p((VALUE)err)
|
|
#define MEMO_CAST(m) ((struct MEMO *)(m))
|
|
#define MEMO_FOR(type, value) ((type *)RARRAY_PTR(value))
|
|
#define NEW_MEMO_FOR(type, value) \
|
|
((value) = rb_ary_hidden_new_fill(type_roomof(type, VALUE)), MEMO_FOR(type, value))
|
|
#define NEW_PARTIAL_MEMO_FOR(type, value, member) \
|
|
((value) = rb_ary_hidden_new_fill(type_roomof(type, VALUE)), \
|
|
rb_ary_set_len((value), offsetof(type, member) / sizeof(VALUE)), \
|
|
MEMO_FOR(type, value))
|
|
|
|
#ifndef RUBY_RUBYPARSER_H
|
|
typedef struct rb_imemo_tmpbuf_struct rb_imemo_tmpbuf_t;
|
|
#endif
|
|
VALUE rb_imemo_new(enum imemo_type type, VALUE v0, size_t size, bool is_shareable);
|
|
struct MEMO *rb_imemo_memo_new(VALUE a, VALUE b, rb_len_t c);
|
|
struct MEMO *rb_imemo_memo_new_value(VALUE a, VALUE b, VALUE c);
|
|
struct vm_ifunc *rb_vm_ifunc_new(rb_block_call_func_t func, const void *data, int min_argc, int max_argc);
|
|
static inline enum imemo_type imemo_type(VALUE imemo);
|
|
static inline int imemo_type_p(VALUE imemo, enum imemo_type imemo_type);
|
|
static inline bool imemo_throw_data_p(VALUE imemo);
|
|
static inline struct vm_ifunc *rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data);
|
|
static inline void *RB_IMEMO_TMPBUF_PTR(VALUE v);
|
|
static inline void MEMO_V1_SET(struct MEMO *m, VALUE v);
|
|
static inline void MEMO_V2_SET(struct MEMO *m, VALUE v);
|
|
|
|
size_t rb_imemo_memsize(VALUE obj);
|
|
void rb_imemo_mark_and_move(const struct rb_gc_mark_ctx *ctx, VALUE obj, bool reference_updating);
|
|
void rb_imemo_free(VALUE obj);
|
|
|
|
RUBY_SYMBOL_EXPORT_BEGIN
|
|
const char *rb_imemo_name(enum imemo_type type);
|
|
ID rb_imemo_callinfo_mid(VALUE obj);
|
|
struct rb_imemo_callcache_data {
|
|
VALUE klass;
|
|
ID called_id;
|
|
};
|
|
bool rb_imemo_callcache_get_data(VALUE obj, struct rb_imemo_callcache_data *data);
|
|
RUBY_SYMBOL_EXPORT_END
|
|
|
|
static inline enum imemo_type
|
|
imemo_type(VALUE imemo)
|
|
{
|
|
return (RBASIC(imemo)->flags & IMEMO_MASK) >> FL_USHIFT;
|
|
}
|
|
|
|
static inline int
|
|
imemo_type_p(VALUE imemo, enum imemo_type imemo_type)
|
|
{
|
|
if (LIKELY(!RB_SPECIAL_CONST_P(imemo))) {
|
|
/* fixed at compile time if imemo_type is given. */
|
|
const VALUE mask = IMEMO_MASK | RUBY_T_MASK;
|
|
const VALUE expected_type = (imemo_type << FL_USHIFT) | T_IMEMO;
|
|
/* fixed at runtime. */
|
|
return expected_type == (RBASIC(imemo)->flags & mask);
|
|
}
|
|
else {
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
#define IMEMO_TYPE_P(v, t) imemo_type_p((VALUE)(v), t)
|
|
|
|
static inline bool
|
|
imemo_throw_data_p(VALUE imemo)
|
|
{
|
|
return RB_TYPE_P(imemo, T_IMEMO);
|
|
}
|
|
|
|
static inline struct vm_ifunc *
|
|
rb_vm_ifunc_proc_new(rb_block_call_func_t func, const void *data)
|
|
{
|
|
return rb_vm_ifunc_new(func, data, 0, UNLIMITED_ARGUMENTS);
|
|
}
|
|
|
|
static inline void *
|
|
RB_IMEMO_TMPBUF_PTR(VALUE v)
|
|
{
|
|
const struct rb_imemo_tmpbuf_struct *p = (const void *)v;
|
|
return p->ptr;
|
|
}
|
|
|
|
static inline VALUE
|
|
rb_imemo_tmpbuf_new_from_an_RString(VALUE str)
|
|
{
|
|
VALUE imemo;
|
|
size_t len;
|
|
|
|
StringValue(str);
|
|
len = RSTRING_LEN(str);
|
|
rb_alloc_tmp_buffer(&imemo, len, false);
|
|
memcpy(RB_IMEMO_TMPBUF_PTR(imemo), RSTRING_PTR(str), len);
|
|
return imemo;
|
|
}
|
|
|
|
static inline void
|
|
MEMO_V1_SET(struct MEMO *m, VALUE v)
|
|
{
|
|
RB_OBJ_WRITE(m, &m->v1, v);
|
|
}
|
|
|
|
static inline void
|
|
MEMO_V2_SET(struct MEMO *m, VALUE v)
|
|
{
|
|
RB_OBJ_WRITE(m, &m->v2, v);
|
|
}
|
|
|
|
VALUE rb_imemo_cdhash_new(size_t size, const struct st_hash_type *type);
|
|
|
|
static inline st_table *
|
|
rb_imemo_cdhash_tbl(VALUE obj)
|
|
{
|
|
RUBY_ASSERT(IMEMO_TYPE_P(obj, imemo_cdhash));
|
|
return &((struct rb_imemo_cdhash *)obj)->tbl;
|
|
}
|
|
|
|
struct rb_fields {
|
|
struct RBasic basic;
|
|
union {
|
|
struct {
|
|
VALUE fields[1];
|
|
} embed;
|
|
struct {
|
|
st_table table;
|
|
} complex;
|
|
} as;
|
|
};
|
|
|
|
// IMEMO/fields and T_OBJECT have exactly the same layout.
|
|
// This is useful for JIT and common codepaths.
|
|
STATIC_ASSERT(imemo_fields_embed_offset, offsetof(struct RObject, as.ary) == offsetof(struct rb_fields, as.embed.fields));
|
|
|
|
#define IMEMO_OBJ_FIELDS(fields) ((struct rb_fields *)fields)
|
|
|
|
#define IMEMO_SUBCLASSES_HEAP IMEMO_FL_USER0
|
|
|
|
struct rb_subclasses {
|
|
VALUE flags;
|
|
uint32_t count;
|
|
uint32_t capacity;
|
|
union {
|
|
VALUE *external;
|
|
VALUE embed[1];
|
|
} as;
|
|
};
|
|
|
|
static inline VALUE *
|
|
rb_imemo_subclasses_entries(VALUE v)
|
|
{
|
|
struct rb_subclasses *s = (struct rb_subclasses *)v;
|
|
return FL_TEST_RAW(v, IMEMO_SUBCLASSES_HEAP) ? s->as.external : s->as.embed;
|
|
}
|
|
|
|
VALUE rb_imemo_fields_new(VALUE owner, /* shape_id_t */ uint32_t shape_id, bool shareable);
|
|
VALUE rb_imemo_subclasses_new(uint32_t capacity);
|
|
VALUE rb_imemo_fields_new_complex(VALUE owner, /* shape_id_t */ uint32_t shape_id, size_t capa, bool shareable);
|
|
VALUE rb_imemo_fields_new_complex_empty(VALUE owner);
|
|
VALUE rb_imemo_fields_clone(VALUE fields_obj);
|
|
void rb_imemo_fields_clear(VALUE fields_obj);
|
|
|
|
static inline VALUE
|
|
rb_imemo_fields_owner(VALUE fields_obj)
|
|
{
|
|
RUBY_ASSERT(IMEMO_TYPE_P(fields_obj, imemo_fields));
|
|
|
|
return CLASS_OF(fields_obj);
|
|
}
|
|
|
|
#endif /* INTERNAL_IMEMO_H */
|