3#include "eval_intern.h"
5#include "internal/box.h"
6#include "internal/class.h"
7#include "internal/eval.h"
8#include "internal/error.h"
9#include "internal/file.h"
10#include "internal/gc.h"
11#include "internal/hash.h"
12#include "internal/io.h"
13#include "internal/load.h"
14#include "internal/random.h"
15#include "internal/st.h"
16#include "internal/variable.h"
31#ifdef HAVE_SYS_SENDFILE_H
32# include <sys/sendfile.h>
39VALUE rb_cBoxEntry = 0;
40VALUE rb_mBoxLoader = 0;
49static bool tmp_dir_has_dirsep;
52# define MAXPATHLEN 1024
56static char box_ext_tmp_dir[MAXPATHLEN];
57static rb_pid_t box_ext_tmp_dir_owner;
58static unsigned long box_ext_seq;
60#define BOX_TMP_PREFIX "_ruby_box_"
68bool ruby_box_enabled =
false;
69bool ruby_box_init_done =
false;
70bool ruby_box_crashed =
false;
79 box_gem_flags->gem = flags->gem;
80 box_gem_flags->error_highlight = flags->error_highlight;
81 box_gem_flags->did_you_mean = flags->did_you_mean;
82 box_gem_flags->syntax_suggest = flags->syntax_suggest;
88 ruby_box_init_done =
true;
127 return rb_vm_current_box(GET_EC());
139 return rb_vm_loading_box(GET_EC());
144rb_current_box_in_crash_report(
void)
146 if (ruby_box_crashed)
148 return rb_current_box();
151static long box_id_counter = 0;
158 id = ++box_id_counter;
164box_main_to_s(
VALUE obj)
172 const rb_box_t *master = rb_master_box();
181 box->load_path =
rb_ary_dup(master->load_path);
182 box->expanded_load_path =
rb_ary_dup(master->expanded_load_path);
184 box->load_path_check_cache = 0;
185 box->loaded_features =
rb_ary_dup(master->loaded_features);
187 box->loaded_features_index = st_init_numtable();
188 box->loaded_features_realpaths = rb_hash_dup(master->loaded_features_realpaths);
189 box->loaded_features_realpath_map = rb_hash_dup(master->loaded_features_realpath_map);
190 box->loading_table = st_init_strtable();
191 box->ruby_dln_libmap = rb_hash_new();
192 box->gvar_tbl = rb_hash_new();
193 box->classext_cow_classes = st_init_numtable();
196 box->is_optional =
true;
200rb_box_gc_update_references(
void *ptr)
206 rb_gc_update_moved(&box->box_object);
208 rb_gc_update_moved(&box->top_self);
209 rb_gc_update_moved(&box->load_path);
210 rb_gc_update_moved(&box->expanded_load_path);
211 rb_gc_update_moved(&box->load_path_snapshot);
212 if (box->load_path_check_cache) {
213 rb_gc_update_moved(&box->load_path_check_cache);
215 rb_gc_update_moved(&box->loaded_features);
216 rb_gc_update_moved(&box->loaded_features_snapshot);
217 rb_gc_update_moved(&box->loaded_features_realpaths);
218 rb_gc_update_moved(&box->loaded_features_realpath_map);
219 rb_gc_update_moved(&box->ruby_dln_libmap);
220 rb_gc_update_moved(&box->gvar_tbl);
224rb_box_entry_mark(
void *ptr)
229 rb_gc_mark(box->box_object);
230 rb_gc_mark(box->top_self);
231 rb_gc_mark(box->load_path);
232 rb_gc_mark(box->expanded_load_path);
233 rb_gc_mark(box->load_path_snapshot);
234 rb_gc_mark(box->load_path_check_cache);
235 rb_gc_mark(box->loaded_features);
236 rb_gc_mark(box->loaded_features_snapshot);
237 rb_gc_mark(box->loaded_features_realpaths);
238 rb_gc_mark(box->loaded_features_realpath_map);
239 if (box->loading_table) {
240 rb_mark_tbl(box->loading_table);
242 rb_gc_mark(box->ruby_dln_libmap);
243 rb_gc_mark(box->gvar_tbl);
244 if (box->classext_cow_classes) {
245 rb_mark_set(box->classext_cow_classes);
250free_loading_table_entry(st_data_t key, st_data_t value, st_data_t arg)
257free_loaded_feature_index_i(st_data_t key, st_data_t value, st_data_t arg)
260 rb_darray_free_sized((
void *)value,
long);
266free_box_st_tables(
void *ptr)
269 if (box->loading_table) {
270 st_foreach(box->loading_table, free_loading_table_entry, 0);
271 st_free_table(box->loading_table);
272 box->loading_table = 0;
275 if (box->loaded_features_index) {
276 st_foreach(box->loaded_features_index, free_loaded_feature_index_i, 0);
277 st_free_table(box->loaded_features_index);
282free_classext_for_box(st_data_t key, st_data_t _value, st_data_t box_arg)
289 ext = rb_class_unlink_classext(obj, box);
290 rb_class_classext_free(obj, ext,
false);
293 ext = rb_class_unlink_classext(obj, box);
294 rb_iclass_classext_free(obj, ext,
false);
297 rb_bug(
"Invalid type of object in classext_cow_classes: %s", rb_type_str(
BUILTIN_TYPE(obj)));
303box_entry_free(
void *ptr)
307 if (box->classext_cow_classes) {
308 st_foreach(box->classext_cow_classes, free_classext_for_box, (st_data_t)box);
311 free_box_st_tables(ptr);
316box_entry_memsize(
const void *ptr)
320 if (box->loaded_features_index) {
321 size += rb_st_memsize(box->loaded_features_index);
323 if (box->loading_table) {
324 size += rb_st_memsize(box->loading_table);
335 rb_box_gc_update_references,
346 rb_box_gc_update_references,
348 &rb_box_data_type, 0, RUBY_TYPED_THREAD_SAFE_FREE
352rb_box_entry_alloc(
VALUE klass)
356 box_entry_initialize(entry);
361get_box_struct_internal(
VALUE entry)
369rb_get_box_t(
VALUE box)
379 VM_ASSERT(BOX_OBJ_P(box));
381 CONST_ID(id_box_entry,
"__box_entry__");
382 entry = rb_attr_get(box, id_box_entry);
383 return get_box_struct_internal(entry);
389 VM_ASSERT(box && box->box_object);
390 return box->box_object;
400box_initialize(
VALUE box_value)
406 CONST_ID(id_box_entry,
"__box_entry__");
408 if (!rb_box_available()) {
409 rb_raise(
rb_eRuntimeError,
"Ruby Box is disabled. Set RUBY_BOX=1 environment variable to use Ruby::Box.");
413 box = get_box_struct_internal(entry);
415 box->box_object = box_value;
416 box->box_id = box_generate_id();
422 RCLASS_SET_PRIME_CLASSEXT_WRITABLE(box_value,
true);
426 object_classext = RCLASS_EXT_WRITABLE_IN_BOX(
rb_cObject, box);
427 RCLASS_SET_CONST_TBL(box_value, RCLASSEXT_CONST_TBL(object_classext),
true);
431 if (ruby_box_init_done) {
432 if (box_gem_flags->gem) {
433 rb_vm_call_cfunc_in_box(
Qnil, rb_define_gem_modules, (
VALUE)box_gem_flags,
Qnil,
435 rb_load_gem_prelude((
VALUE)box);
440 rb_zjit_invalidate_root_box();
452rb_box_s_getenabled(
VALUE recv)
454 return RBOOL(rb_box_available());
465rb_box_s_current(
VALUE recv)
469 if (!rb_box_available())
472 box = rb_vm_current_box(GET_EC());
473 VM_ASSERT(box && box->box_object);
474 return box->box_object;
484rb_box_load_path(
VALUE box)
486 VM_ASSERT(BOX_OBJ_P(box));
487 return rb_get_box_t(box)->load_path;
491UINT rb_w32_system_tmpdir(WCHAR *path, UINT
len);
496system_default_tmpdir(
void)
500 WCHAR tmppath[_MAX_PATH];
501 UINT
len = rb_w32_system_tmpdir(tmppath, numberof(tmppath));
503 int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath,
len, NULL, 0, NULL, NULL);
504 char *tmpdir =
xmalloc(blen + 1);
505 WideCharToMultiByte(CP_UTF8, 0, tmppath,
len, tmpdir, blen, NULL, NULL);
509#elif defined _CS_DARWIN_USER_TEMP_DIR
510 char path[MAXPATHLEN];
511 size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path,
sizeof(path));
514 if (
len >
sizeof(path)) {
515 confstr(_CS_DARWIN_USER_TEMP_DIR, tmpdir,
len);
518 memcpy(tmpdir, path,
len);
527check_tmpdir(
const char *dir)
531 if (!dir)
return FALSE;
532 if (stat(dir, &st))
return FALSE;
534# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
536 if (!S_ISDIR(st.st_mode))
return FALSE;
541 if (st.st_mode & S_IWOTH) {
543 if (!(st.st_mode & S_ISVTX))
return FALSE;
548 if (access(dir, W_OK))
return FALSE;
557# define RETURN_ENV(name) \
558 if (check_tmpdir(tmpdir = getenv(name))) return ruby_strdup(tmpdir)
559 RETURN_ENV(
"TMPDIR");
561 tmpdir = system_default_tmpdir();
562 if (check_tmpdir(tmpdir))
return tmpdir;
576ensure_box_ext_tmp_dir(
void)
581 if (box_ext_tmp_dir[0] && box_ext_tmp_dir_owner != getpid()) {
582 box_ext_tmp_dir[0] =
'\0';
585 if (box_ext_tmp_dir[0])
return;
588 for (
int retry = 0; retry < 10; retry++) {
589 char path[MAXPATHLEN];
591 if (ruby_fill_random_bytes(&suffix,
sizeof(suffix), FALSE) != 0) {
593 suffix = (uint64_t)(uintptr_t)&suffix ^ (uint64_t)retry;
595 int wrote = snprintf(path,
sizeof(path),
"%s%s%sp%"PRI_PIDT_PREFIX"u_%.16"PRIx64,
596 tmp_dir, tmp_dir_has_dirsep ?
"" : DIRSEP,
597 BOX_TMP_PREFIX, getpid(), suffix);
598 if (wrote >= (
int)
sizeof(path)) {
599 rb_raise(
rb_eLoadError,
"TMPDIR for Ruby Box extensions is too long: %s", tmp_dir);
601 if (mkdir(path, 0700) == 0) {
602 strlcpy(box_ext_tmp_dir, path,
sizeof(box_ext_tmp_dir));
603 box_ext_tmp_dir_owner = getpid();
607 if (last_errno != EEXIST)
break;
609 rb_raise(
rb_eLoadError,
"can't create the temporary directory for Ruby Box extensions under %s: %s",
610 tmp_dir, strerror(last_errno));
613enum copy_error_type {
618 COPY_ERROR_DST_WRITE,
620 COPY_ERROR_DST_CHMOD,
625copy_ext_file_error(
char *message,
size_t size,
int copy_retvalue)
628 int error = GetLastError();
630 size_t len = snprintf(message, size,
"%d: ", error);
632#define format_message(sublang) FormatMessage(\
633 FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, \
634 NULL, error, MAKELANGID(LANG_NEUTRAL, (sublang)), \
635 message + len, size - len, NULL)
636 if (format_message(SUBLANG_ENGLISH_US) == 0)
637 format_message(SUBLANG_DEFAULT);
638 for (p = message +
len; *p; p++) {
639 if (*p ==
'\n' || *p ==
'\r')
643 switch (copy_retvalue) {
644 case COPY_ERROR_SRC_OPEN:
645 strlcpy(message,
"can't open the extension path", size);
647 case COPY_ERROR_DST_OPEN:
648 strlcpy(message,
"can't open the file to write", size);
650 case COPY_ERROR_SRC_READ:
651 strlcpy(message,
"failed to read the extension path", size);
653 case COPY_ERROR_DST_WRITE:
654 strlcpy(message,
"failed to write the extension path", size);
656 case COPY_ERROR_SRC_STAT:
657 strlcpy(message,
"failed to stat the extension path to copy permissions", size);
659 case COPY_ERROR_DST_CHMOD:
660 strlcpy(message,
"failed to set permissions to the copied extension path", size);
662 case COPY_ERROR_SYSERR:
663 strlcpy(message, strerror(
errno), size);
665 case COPY_ERROR_NONE:
667 rb_bug(
"unknown return value of copy_ext_file: %d", copy_retvalue);
674static enum copy_error_type
675copy_stream(
int src_fd,
int dst_fd)
680 while ((rsize = read(src_fd, buffer,
sizeof(buffer))) != 0) {
681 if (rsize < 0)
return COPY_ERROR_SRC_READ;
682 for (
size_t written = 0; written < (size_t)rsize;) {
683 ssize_t wsize = write(dst_fd, buffer+written, rsize-written);
684 if (wsize < 0)
return COPY_ERROR_DST_WRITE;
685 written += (size_t)wsize;
688 return COPY_ERROR_NONE;
692static enum copy_error_type
693copy_ext_file(
const char *src_path,
const char *dst_path)
696 WCHAR *w_src = rb_w32_mbstr_to_wstr(CP_UTF8, src_path, -1, NULL);
697 WCHAR *w_dst = rb_w32_mbstr_to_wstr(CP_UTF8, dst_path, -1, NULL);
698 if (!w_src || !w_dst) {
704 enum copy_error_type rvalue = CopyFileW(w_src, w_dst, TRUE) ?
705 COPY_ERROR_NONE : COPY_ERROR_SYSERR;
711 const int bin = O_BINARY;
716 const int cloexec = O_CLOEXEC;
718 const int cloexec = 0;
720 const int src_fd = open(src_path, O_RDONLY|cloexec|bin);
721 if (src_fd < 0)
return COPY_ERROR_SRC_OPEN;
722 if (!cloexec) rb_maygvl_fd_fix_cloexec(src_fd);
725 if (fstat(src_fd, &src_st)) {
727 return COPY_ERROR_SRC_STAT;
730 const int dst_fd = open(dst_path, O_WRONLY|O_CREAT|O_EXCL|cloexec|bin, S_IRWXU);
733 return COPY_ERROR_DST_OPEN;
735 if (!cloexec) rb_maygvl_fd_fix_cloexec(dst_fd);
737 enum copy_error_type ret = COPY_ERROR_NONE;
739 if (fchmod(dst_fd, src_st.st_mode & 0777)) {
740 ret = COPY_ERROR_DST_CHMOD;
744 const size_t count_max = (SIZE_MAX >> 1) + 1;
747# ifdef HAVE_COPY_FILE_RANGE
749 ssize_t written = copy_file_range(src_fd, NULL, dst_fd, NULL, count_max, 0);
750 if (written == 0)
goto done;
751 if (written < 0)
break;
754# ifdef HAVE_FCOPYFILE
755 if (fcopyfile(src_fd, dst_fd, NULL, COPYFILE_DATA) == 0) {
761 ssize_t written = sendfile(src_fd, dst_fd, NULL count_max);
762 if (written == 0)
goto done;
763 if (written < 0)
break;
766 ret = copy_stream(src_fd, dst_fd);
770 if (dst_fd >= 0) close(dst_fd);
771 if (ret != COPY_ERROR_NONE) unlink(dst_path);
776#if defined __CYGWIN__ || defined DOSISH
777#define isdirsep(x) ((x) == '/' || (x) == '\\')
779#define isdirsep(x) ((x) == '/')
783ext_basename(
const char *path)
785 const char *base = path;
786 for (
const char *pos = path; *pos; pos++) {
787 if (isdirsep(*pos)) base = pos + 1;
793box_ext_cleanup_mark(
void *p)
795 rb_gc_mark((
VALUE)p);
799box_ext_cleanup_free(
void *p)
802 unlink(RSTRING_PTR(path));
807 {box_ext_cleanup_mark, box_ext_cleanup_free},
812rb_box_cleanup_local_extension(
VALUE cleanup)
817 if (p) box_ext_cleanup_free(p);
831rb_box_defer_unload_local_extension(
void *handle)
841 ext->handle = (HMODULE)handle;
842 ext->next = box_local_exts;
843 box_local_exts = ext;
848rb_box_unload_local_extensions(
void)
852 box_local_exts = NULL;
855 WCHAR module_path[MAXPATHLEN];
856 DWORD
len = GetModuleFileNameW(ext->handle, module_path, numberof(module_path));
858 FreeLibrary(ext->handle);
859 if (
len > 0 &&
len < numberof(module_path)) DeleteFileW(module_path);
864 if (box_ext_tmp_dir[0] && box_ext_tmp_dir_owner == getpid()) {
865 rmdir(box_ext_tmp_dir);
866 box_ext_tmp_dir[0] =
'\0';
873 char ext_path[MAXPATHLEN];
875 const char *src_path = RSTRING_PTR(path);
876 rb_box_t *box = rb_get_box_t(box_value);
878 ensure_box_ext_tmp_dir();
879 wrote = snprintf(ext_path,
sizeof(ext_path),
"%s%s%ld_%lu_%s",
880 box_ext_tmp_dir, DIRSEP, box->box_id, box_ext_seq++, ext_basename(src_path));
881 if (wrote >= (
int)
sizeof(ext_path)) {
882 rb_raise(
rb_eLoadError,
"extension file path in the box is too long: %"PRIsVALUE, path);
886 enum copy_error_type copy_error = copy_ext_file(src_path, ext_path);
889 copy_ext_file_error(message,
sizeof(message), copy_error);
890 rb_raise(
rb_eLoadError,
"can't prepare the extension file for Ruby Box (%s from %"PRIsVALUE
"): %s", ext_path, path, message);
892 DATA_PTR(*cleanup) = (
void *)new_path;
902 rb_vm_frame_flag_set_box_require(GET_EC());
904 return rb_load_entrypoint(fname, wrap);
910 rb_vm_frame_flag_set_box_require(GET_EC());
916rb_box_require_relative(
VALUE box,
VALUE fname)
918 rb_vm_frame_flag_set_box_require(GET_EC());
920 return rb_require_relative_entrypoint(fname);
924initialize_master_box(
void)
932 master->load_path_check_cache = 0;
937 master->loaded_features_index = st_init_numtable();
938 master->loaded_features_realpaths = rb_hash_new();
940 master->loaded_features_realpath_map = rb_hash_new();
943 master->ruby_dln_libmap = rb_hash_new();
944 master->gvar_tbl = rb_hash_new();
945 master->classext_cow_classes = NULL;
947 vm->master_box = master;
949 if (rb_box_available()) {
950 VALUE master_box, entry;
952 CONST_ID(id_box_entry,
"__box_entry__");
955 RCLASS_SET_PRIME_CLASSEXT_WRITABLE(master_box,
true);
956 RCLASS_SET_CONST_TBL(master_box, RCLASSEXT_CONST_TBL(RCLASS_EXT_PRIME(
rb_cObject)),
true);
958 master->box_id = box_generate_id();
959 master->box_object = master_box;
964 rb_gc_register_mark_object(master_box);
965 rb_gc_register_mark_object(entry);
969 master->box_object =
Qnil;
984 box = (
const rb_box_t *)rb_get_box_t(box_value);
986 return rb_iseq_eval(iseq, box);
989static int box_experimental_warned = 0;
994box_value_initialize(
bool root,
bool user,
bool optional)
999 VM_ASSERT(BOX_OBJ_P(box_value));
1001 box = rb_get_box_t(box_value);
1002 box->box_object = box_value;
1003 box->is_root = root;
1004 box->is_user = user;
1005 box->is_optional = optional;
1010rb_initialize_mandatory_boxes(
void)
1012 VALUE root_box_value, main_box_value;
1015 VM_ASSERT(rb_box_available());
1017 if (!box_experimental_warned) {
1019 "Ruby::Box is experimental, and the behavior may change in the future!\n"
1020 "See https://docs.ruby-lang.org/en/%s/Ruby/Box.html for known issues, etc.",
1021 ruby_api_version_name);
1022 box_experimental_warned = 1;
1025 root_box_value = box_value_initialize(
true,
false,
false);
1026 main_box_value = box_value_initialize(
false,
true,
false);
1031 vm->root_box = root_box = rb_get_box_t(root_box_value);
1032 vm->main_box = main_box = rb_get_box_t(main_box_value);
1035 RCLASS_EXT_WRITABLE_IN_BOX(
rb_cObject, root_box);
1036 RCLASS_EXT_WRITABLE_IN_BOX(
rb_cObject, main_box);
1040rb_box_inspect(
VALUE obj)
1048 box = rb_get_box_t(obj);
1051 if (BOX_MASTER_P(box)) {
1054 if (BOX_ROOT_P(box)) {
1057 if (BOX_USER_P(box)) {
1060 if (BOX_MAIN_P(box)) {
1063 else if (BOX_OPTIONAL_P(box)) {
1071rb_box_loading_func(
int argc,
VALUE *argv,
VALUE _self)
1073 rb_vm_frame_flag_set_box_require(GET_EC());
1078box_define_loader_method(
const char *name)
1085Init_master_box(
void)
1087 master_box->loading_table = st_init_strtable();
1091Init_enable_box(
void)
1093 const char *env = getenv(
"RUBY_BOX");
1094 if (env && strlen(env) == 1 && env[0] ==
'1') {
1095 ruby_box_enabled =
true;
1098 ruby_box_init_done =
true;
1104rb_box_s_master(
VALUE recv)
1106 return master_box->box_object;
1111rb_box_s_root(
VALUE recv)
1113 return root_box->box_object;
1118rb_box_s_main(
VALUE recv)
1120 return main_box->box_object;
1125rb_box_master_p(
VALUE box_value)
1128 return RBOOL(BOX_MASTER_P(box));
1133rb_box_root_p(
VALUE box_value)
1136 return RBOOL(BOX_ROOT_P(box));
1141rb_box_main_p(
VALUE box_value)
1144 return RBOOL(BOX_MAIN_P(box));
1150classname(
VALUE klass)
1156 p = RCLASSEXT_CLASSPATH(RCLASS_EXT_PRIME(klass));
1158 return RSTRING_PTR(p);
1160 return "AnyClassValue";
1161 return "NonClassValue";
1164static enum rb_id_table_iterator_result
1165dump_classext_methods_i(
ID mid,
VALUE _val,
void *data)
1169 return ID_TABLE_CONTINUE;
1172static enum rb_id_table_iterator_result
1173dump_classext_constants_i(
ID mid,
VALUE _val,
void *data)
1177 return ID_TABLE_CONTINUE;
1187 snprintf(buf, 4096,
"Ruby::Box %ld:%s classext %p\n",
1188 RCLASSEXT_BOX(ext)->box_id, is_prime ?
" prime" :
"", (void *)ext);
1191 snprintf(buf, 2048,
" Super: %s\n", classname(RCLASSEXT_SUPER(ext)));
1194 tbl = RCLASSEXT_M_TBL(ext);
1197 rb_id_table_foreach(RCLASSEXT_M_TBL(ext), dump_classext_methods_i, (
void *)ary);
1199 snprintf(buf, 4096,
" Methods(%ld): ",
RARRAY_LEN(ary));
1208 tbl = RCLASSEXT_CONST_TBL(ext);
1211 rb_id_table_foreach(tbl, dump_classext_constants_i, (
void *)ary);
1213 snprintf(buf, 4096,
" Constants(%ld): ",
RARRAY_LEN(ary));
1248 snprintf(buf, 2048,
"Non-class/module value: %p (%s)\n", (
void *)klass, rb_type_str(
BUILTIN_TYPE(klass)));
1253 snprintf(buf, 2048,
"Class: %p (%s)%s\n",
1254 (
void *)klass, classname(klass), RCLASS_SINGLETON_P(klass) ?
" [singleton]" :
"");
1257 snprintf(buf, 2048,
"Module: %p (%s)\n", (
void *)klass, classname(klass));
1261 ext = RCLASS_EXT_PRIME(klass);
1262 box = RCLASSEXT_BOX(ext);
1263 snprintf(buf, 2048,
"Prime classext box(%ld,%s), readable(%s), writable(%s)\n",
1265 BOX_MASTER_P(box) ?
"master" : (BOX_ROOT_P(box) ?
"root" : (BOX_MAIN_P(box) ?
"main" :
"optional")),
1266 RCLASS_PRIME_CLASSEXT_READABLE_P(klass) ?
"t" :
"f",
1267 RCLASS_PRIME_CLASSEXT_WRITABLE_P(klass) ?
"t" :
"f");
1270 classext_tbl = RCLASS_CLASSEXT_TBL(klass);
1271 if (!classext_tbl) {
1275 snprintf(buf, 2048,
"Non-prime classexts: %zu\n", st_table_size(classext_tbl));
1279 rb_class_classext_foreach(klass, dump_classext_i, (
void *)res);
1295 tmp_dir = system_tmpdir();
1296 tmp_dir_has_dirsep = (strcmp(tmp_dir + (strlen(tmp_dir) - strlen(DIRSEP)), DIRSEP) == 0);
1298 VALUE mRuby = rb_define_module(
"Ruby");
1307 initialize_master_box();
1310 rb_mBoxLoader = rb_define_module_under(
rb_cBox,
"Loader");
1311 box_define_loader_method(
"require");
1312 box_define_loader_method(
"require_relative");
1313 box_define_loader_method(
"load");
1315 if (rb_box_available()) {
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_private_method(klass, mid, func, arity)
Defines klass#mid and makes it private.
#define rb_define_global_function(mid, func, arity)
Defines rb_mKernel #mid.
#define RUBY_EXTERN
Declaration of externally visible global variables.
Ruby-level global variables / constants, visible from C.
void rb_include_module(VALUE klass, VALUE module)
Includes a module to a class.
VALUE rb_singleton_class(VALUE obj)
Finds or creates the singleton class of the passed object.
void rb_define_alias(VALUE klass, const char *name1, const char *name2)
Defines an alias of a method.
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Retrieves argument from argc and argv to given VALUE references according to the format string.
#define rb_str_new2
Old name of rb_str_new_cstr.
#define xfree
Old name of ruby_xfree.
#define xmalloc
Old name of ruby_xmalloc.
#define T_MODULE
Old name of RUBY_T_MODULE.
#define T_ICLASS
Old name of RUBY_T_ICLASS.
#define LONG2NUM
Old name of RB_LONG2NUM.
#define Qnil
Old name of RUBY_Qnil.
#define Qfalse
Old name of RUBY_Qfalse.
#define NIL_P
Old name of RB_NIL_P.
#define T_CLASS
Old name of RUBY_T_CLASS.
#define BUILTIN_TYPE
Old name of RB_BUILTIN_TYPE.
#define FIXNUM_P
Old name of RB_FIXNUM_P.
#define CONST_ID
Old name of RUBY_CONST_ID.
void rb_category_warn(rb_warning_category_t category, const char *fmt,...)
Identical to rb_category_warning(), except it reports unless $VERBOSE is nil.
VALUE rb_eLoadError
LoadError exception.
VALUE rb_eRuntimeError
RuntimeError exception.
@ RB_WARN_CATEGORY_EXPERIMENTAL
Warning is for experimental features.
VALUE rb_cObject
Object class.
VALUE rb_obj_alloc(VALUE klass)
Allocates an instance of the given class.
VALUE rb_class_new_instance(int argc, const VALUE *argv, VALUE klass)
Allocates, then initialises an instance of the given class.
VALUE rb_cBox
Ruby::Box class.
VALUE rb_obj_hide(VALUE obj)
Make the object invisible from Ruby code.
VALUE rb_class_new_instance_pass_kw(int argc, const VALUE *argv, VALUE klass)
Identical to rb_class_new_instance(), except it passes the passed keywords if any to the #initialize ...
VALUE rb_cModule
Module class.
VALUE rb_funcall(VALUE recv, ID mid, int n,...)
Calls a method.
VALUE rb_call_super(int argc, const VALUE *argv)
This resembles ruby's super.
VALUE rb_ary_dup(VALUE ary)
Duplicates an array.
VALUE rb_ary_new(void)
Allocates a new, empty array.
VALUE rb_ary_new_capa(long capa)
Identical to rb_ary_new(), except it additionally specifies how many rooms of objects it should alloc...
VALUE rb_ary_hidden_new(long capa)
Allocates a hidden (no class) empty array.
VALUE rb_ary_push(VALUE ary, VALUE elem)
Special case of rb_ary_cat() that it adds only one element.
VALUE rb_ary_sort_bang(VALUE ary)
Destructively sorts the passed array in-place, according to each elements' <=> result.
VALUE rb_ary_join(VALUE ary, VALUE sep)
Recursively stringises the elements of the passed array, flattens that result, then joins the sequenc...
VALUE rb_require_string(VALUE feature)
Finds and loads the given feature, if absent.
VALUE rb_str_concat(VALUE dst, VALUE src)
Identical to rb_str_append(), except it also accepts an integer as a codepoint.
#define rb_str_cat_cstr(buf, str)
Identical to rb_str_cat(), except it assumes the passed pointer is a pointer to a C string.
#define rb_str_new_cstr(str)
Identical to rb_str_new, except it assumes the passed pointer is a pointer to a C string.
VALUE rb_ivar_set(VALUE obj, ID name, VALUE val)
Identical to rb_iv_set(), except it accepts the name as an ID instead of a C string.
void rb_const_set(VALUE space, ID name, VALUE val)
Names a constant.
void rb_define_alloc_func(VALUE klass, rb_alloc_func_t func)
Sets the allocator function of a class.
int len
Length of the buffer.
char * ruby_strdup(const char *str)
This is our own version of strdup(3) that uses ruby_xmalloc() instead of system malloc (benefits our ...
#define PRI_PIDT_PREFIX
A rb_sprintf() format prefix to be used for a pid_t parameter.
#define RARRAY_LEN
Just another name of rb_array_len.
#define StringValue(v)
Ensures that the parameter object is a String.
#define RUBY_TYPED_FREE_IMMEDIATELY
Macros to see if each corresponding flag is defined.
#define TypedData_Get_Struct(obj, type, data_type, sval)
Obtains a C struct from inside of a wrapper Ruby object.
#define DATA_PTR(obj)
Convenient casting macro for backward compatibility.
#define TypedData_Wrap_Struct(klass, data_type, sval)
Converts sval, a pointer to your struct, into a Ruby object.
#define TypedData_Make_Struct(klass, type, data_type, sval)
Identical to TypedData_Wrap_Struct, except it allocates a new data region internally instead of takin...
#define errno
Ractor-aware version of errno.
#define RTEST
This is an old name of RB_TEST.
Internal header for Ruby Box.
This is the struct that holds necessary info for a struct.
uintptr_t ID
Type that represents a Ruby identifier such as a variable name.
uintptr_t VALUE
Type that represents a Ruby object.
static bool RB_TYPE_P(VALUE obj, enum ruby_value_type t)
Queries if the given object is of given type.