summaryrefslogtreecommitdiff
path: root/variable.c
diff options
context:
space:
mode:
Diffstat (limited to 'variable.c')
-rw-r--r--variable.c1360
1 files changed, 592 insertions, 768 deletions
diff --git a/variable.c b/variable.c
index 3146168924..bfb6fa2edd 100644
--- a/variable.c
+++ b/variable.c
@@ -11,10 +11,9 @@
**********************************************************************/
-#include "ruby/encoding.h"
+#include "internal.h"
#include "ruby/st.h"
#include "ruby/util.h"
-#include "internal.h"
#include "id_table.h"
#include "constant.h"
#include "id.h"
@@ -22,12 +21,9 @@
#include "id_table.h"
#include "debug_counter.h"
#include "vm_core.h"
-#include "transient_heap.h"
-#include "variable.h"
-static struct rb_id_table *rb_global_tbl;
-static ID autoload, classpath, tmp_classpath;
-static VALUE autoload_featuremap; /* feature => autoload_i */
+struct rb_id_table *rb_global_tbl;
+static ID autoload, classpath, tmp_classpath, classid;
static void check_before_mod_set(VALUE, ID, VALUE, const char *);
static void setup_const_entry(rb_const_entry_t *, VALUE, VALUE, rb_const_flag_t);
@@ -35,6 +31,12 @@ static VALUE rb_const_search(VALUE klass, ID id, int exclude, int recurse, int v
static st_table *generic_iv_tbl;
static st_table *generic_iv_tbl_compat;
+/* per-object */
+struct gen_ivtbl {
+ uint32_t numiv;
+ VALUE ivptr[1]; /* flexible array */
+};
+
struct ivar_update {
union {
st_table *iv_index_tbl;
@@ -54,41 +56,167 @@ Init_var_tables(void)
classpath = rb_intern_const("__classpath__");
/* __tmp_classpath__: temporary class path which contains anonymous names */
tmp_classpath = rb_intern_const("__tmp_classpath__");
+ /* __classid__: name given to class/module under an anonymous namespace */
+ classid = rb_intern_const("__classid__");
}
-static inline bool
-rb_namespace_p(VALUE obj)
+struct fc_result {
+ ID name, preferred;
+ VALUE klass;
+ VALUE path;
+ VALUE track;
+ struct fc_result *prev;
+};
+
+static VALUE
+fc_path(struct fc_result *fc, ID name)
+{
+ VALUE path, tmp;
+
+ path = rb_id2str(name);
+ while (fc) {
+ st_data_t n;
+ if (fc->track == rb_cObject) break;
+ if (RCLASS_IV_TBL(fc->track) &&
+ st_lookup(RCLASS_IV_TBL(fc->track), (st_data_t)classpath, &n)) {
+ tmp = rb_str_dup((VALUE)n);
+ rb_str_cat2(tmp, "::");
+ rb_str_append(tmp, path);
+ path = tmp;
+ break;
+ }
+ tmp = rb_str_dup(rb_id2str(fc->name));
+ rb_str_cat2(tmp, "::");
+ rb_str_append(tmp, path);
+ path = tmp;
+ fc = fc->prev;
+ }
+ OBJ_FREEZE(path);
+ return path;
+}
+
+static enum rb_id_table_iterator_result
+fc_i(ID key, VALUE v, void *a)
{
- if (RB_SPECIAL_CONST_P(obj)) return false;
- switch (RB_BUILTIN_TYPE(obj)) {
- case T_MODULE: case T_CLASS: return true;
+ rb_const_entry_t *ce = (rb_const_entry_t *)v;
+ struct fc_result *res = a;
+ VALUE value = ce->value;
+ if (!rb_is_const_id(key)) return ID_TABLE_CONTINUE;
+
+ if (value == res->klass && (!res->preferred || key == res->preferred)) {
+ res->path = fc_path(res, key);
+ return ID_TABLE_STOP;
}
- return false;
+ if (RB_TYPE_P(value, T_MODULE) || RB_TYPE_P(value, T_CLASS)) {
+ if (!RCLASS_CONST_TBL(value)) return ID_TABLE_CONTINUE;
+ else {
+ struct fc_result arg;
+ struct fc_result *list;
+
+ list = res;
+ while (list) {
+ if (list->track == value) return ID_TABLE_CONTINUE;
+ list = list->prev;
+ }
+
+ arg.name = key;
+ arg.preferred = res->preferred;
+ arg.path = 0;
+ arg.klass = res->klass;
+ arg.track = value;
+ arg.prev = res;
+ rb_id_table_foreach(RCLASS_CONST_TBL(value), fc_i, &arg);
+ if (arg.path) {
+ res->path = arg.path;
+ return ID_TABLE_STOP;
+ }
+ }
+ }
+ return ID_TABLE_CONTINUE;
+}
+
+/**
+ * Traverse constant namespace and find +classpath+ for _klass_. If
+ * _preferred_ is not 0, choice the path whose base name is set to it.
+ * If +classpath+ is found, the hidden instance variable __classpath__
+ * is set to the found path, and __tmp_classpath__ is removed.
+ * The path is frozen.
+ */
+static VALUE
+find_class_path(VALUE klass, ID preferred)
+{
+ struct fc_result arg;
+
+ arg.preferred = preferred;
+ arg.name = 0;
+ arg.path = 0;
+ arg.klass = klass;
+ arg.track = rb_cObject;
+ arg.prev = 0;
+ if (RCLASS_CONST_TBL(rb_cObject)) {
+ rb_id_table_foreach(RCLASS_CONST_TBL(rb_cObject), fc_i, &arg);
+ }
+ if (arg.path) {
+ st_data_t tmp = tmp_classpath;
+ if (!RCLASS_IV_TBL(klass)) {
+ RCLASS_IV_TBL(klass) = st_init_numtable();
+ }
+ rb_class_ivar_set(klass, classpath, arg.path);
+
+ st_delete(RCLASS_IV_TBL(klass), &tmp, 0);
+ return arg.path;
+ }
+ return Qnil;
}
/**
* Returns +classpath+ of _klass_, if it is named, or +nil+ for
- * anonymous +class+/+module+. A named +classpath+ may contain
- * an anonymous component, but the last component is guaranteed
- * to not be anonymous. <code>*permanent</code> is set to 1
- * if +classpath+ has no anonymous components. There is no builtin
- * Ruby level APIs that can change a permanent +classpath+.
+ * anonymous +class+/+module+. The last part of named +classpath+ is
+ * never anonymous, but anonymous +class+/+module+ names may be
+ * contained. If the path is "permanent", that means it has no
+ * anonymous names, <code>*permanent</code> is set to 1.
*/
static VALUE
classname(VALUE klass, int *permanent)
{
- st_table *ivtbl;
+ VALUE path = Qnil;
st_data_t n;
- *permanent = 0;
- if (!RCLASS_EXT(klass)) return Qnil;
- if (!(ivtbl = RCLASS_IV_TBL(klass))) return Qnil;
- if (st_lookup(ivtbl, (st_data_t)classpath, &n)) {
- *permanent = 1;
- return (VALUE)n;
+ if (!klass) klass = rb_cObject;
+ *permanent = 1;
+ if (RCLASS_IV_TBL(klass)) {
+ if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classpath, &n)) {
+ ID cid = 0;
+ if (st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classid, &n)) {
+ VALUE cname = (VALUE)n;
+ cid = rb_check_id(&cname);
+ if (cid) path = find_class_path(klass, cid);
+ }
+ if (NIL_P(path)) {
+ path = find_class_path(klass, (ID)0);
+ }
+ if (NIL_P(path)) {
+ if (!cid) {
+ return Qnil;
+ }
+ if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)tmp_classpath, &n)) {
+ path = rb_id2str(cid);
+ return path;
+ }
+ *permanent = 0;
+ path = (VALUE)n;
+ return path;
+ }
+ }
+ else {
+ path = (VALUE)n;
+ }
+ if (!RB_TYPE_P(path, T_STRING)) {
+ rb_bug("class path is not set properly");
+ }
+ return path;
}
- if (st_lookup(ivtbl, (st_data_t)tmp_classpath, &n)) return (VALUE)n;
- return Qnil;
+ return find_class_path(klass, (ID)0);
}
/*
@@ -102,7 +230,10 @@ VALUE
rb_mod_name(VALUE mod)
{
int permanent;
- return classname(mod, &permanent);
+ VALUE path = classname(mod, &permanent);
+
+ if (!NIL_P(path)) return rb_str_dup(path);
+ return path;
}
static VALUE
@@ -124,16 +255,22 @@ make_temporary_path(VALUE obj, VALUE klass)
return path;
}
-typedef VALUE (*fallback_func)(VALUE obj, VALUE name);
+typedef VALUE (*path_cache_func)(VALUE obj, VALUE name);
static VALUE
-rb_tmp_class_path(VALUE klass, int *permanent, fallback_func fallback)
+rb_tmp_class_path(VALUE klass, int *permanent, path_cache_func cache_path)
{
VALUE path = classname(klass, permanent);
+ st_data_t n = (st_data_t)path;
if (!NIL_P(path)) {
return path;
}
+ if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),
+ (st_data_t)tmp_classpath, &n)) {
+ *permanent = 0;
+ return (VALUE)n;
+ }
else {
if (RB_TYPE_P(klass, T_MODULE)) {
if (rb_obj_class(klass) == rb_cModule) {
@@ -141,57 +278,68 @@ rb_tmp_class_path(VALUE klass, int *permanent, fallback_func fallback)
}
else {
int perm;
- path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, fallback);
+ path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, cache_path);
}
}
*permanent = 0;
- return fallback(klass, path);
+ return cache_path(klass, path);
}
}
+static VALUE
+ivar_cache(VALUE obj, VALUE name)
+{
+ return rb_ivar_set(obj, tmp_classpath, make_temporary_path(obj, name));
+}
+
VALUE
rb_class_path(VALUE klass)
{
int permanent;
- VALUE path = rb_tmp_class_path(klass, &permanent, make_temporary_path);
+ VALUE path = rb_tmp_class_path(klass, &permanent, ivar_cache);
if (!NIL_P(path)) path = rb_str_dup(path);
return path;
}
-VALUE
-rb_class_path_cached(VALUE klass)
+static VALUE
+null_cache(VALUE obj, VALUE name)
{
- int permanent;
- return classname(klass, &permanent);
+ return make_temporary_path(obj, name);
}
-static VALUE
-no_fallback(VALUE obj, VALUE name)
+VALUE
+rb_class_path_no_cache(VALUE klass)
{
- return name;
+ int permanent;
+ VALUE path = rb_tmp_class_path(klass, &permanent, null_cache);
+ if (!NIL_P(path)) path = rb_str_dup(path);
+ return path;
}
VALUE
-rb_search_class_path(VALUE klass)
+rb_class_path_cached(VALUE klass)
{
- int permanent;
- return rb_tmp_class_path(klass, &permanent, no_fallback);
+ st_table *ivtbl;
+ st_data_t n;
+
+ if (!RCLASS_EXT(klass)) return Qnil;
+ if (!(ivtbl = RCLASS_IV_TBL(klass))) return Qnil;
+ if (st_lookup(ivtbl, (st_data_t)classpath, &n)) return (VALUE)n;
+ if (st_lookup(ivtbl, (st_data_t)tmp_classpath, &n)) return (VALUE)n;
+ return Qnil;
}
static VALUE
-build_const_pathname(VALUE head, VALUE tail)
+never_cache(VALUE obj, VALUE name)
{
- VALUE path = rb_str_dup(head);
- rb_str_cat2(path, "::");
- rb_str_append(path, tail);
- OBJ_FREEZE(path);
- return path;
+ return name;
}
-static VALUE
-build_const_path(VALUE head, ID tail)
+VALUE
+rb_search_class_path(VALUE klass)
{
- return build_const_pathname(head, rb_id2str(tail));
+ int permanent;
+ return rb_tmp_class_path(klass, &permanent, never_cache);
}
void
@@ -205,10 +353,13 @@ rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
}
else {
int permanent;
- str = rb_tmp_class_path(under, &permanent, make_temporary_path);
- str = build_const_pathname(str, name);
+ str = rb_str_dup(rb_tmp_class_path(under, &permanent, ivar_cache));
+ rb_str_cat2(str, "::");
+ rb_str_append(str, name);
+ OBJ_FREEZE(str);
if (!permanent) {
pathid = tmp_classpath;
+ rb_ivar_set(klass, classid, rb_str_intern(name));
}
}
rb_ivar_set(klass, pathid, str);
@@ -217,9 +368,24 @@ rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
void
rb_set_class_path(VALUE klass, VALUE under, const char *name)
{
- VALUE str = rb_str_new2(name);
+ VALUE str;
+ ID pathid = classpath;
+
+ if (under == rb_cObject) {
+ str = rb_str_new2(name);
+ }
+ else {
+ int permanent;
+ str = rb_str_dup(rb_tmp_class_path(under, &permanent, ivar_cache));
+ rb_str_cat2(str, "::");
+ rb_str_cat2(str, name);
+ if (!permanent) {
+ pathid = tmp_classpath;
+ rb_ivar_set(klass, classid, rb_str_intern(rb_str_new_cstr(name)));
+ }
+ }
OBJ_FREEZE(str);
- rb_set_class_path_string(klass, under, str);
+ rb_ivar_set(klass, pathid, str);
}
VALUE
@@ -254,7 +420,7 @@ rb_path_to_class(VALUE pathname)
}
c = rb_const_search(c, id, TRUE, FALSE, FALSE);
if (c == Qundef) goto undefined_class;
- if (!rb_namespace_p(c)) {
+ if (!RB_TYPE_P(c, T_MODULE) && !RB_TYPE_P(c, T_CLASS)) {
rb_raise(rb_eTypeError, "%"PRIsVALUE" does not refer to class/module",
pathname);
}
@@ -270,6 +436,12 @@ rb_path2class(const char *path)
return rb_path_to_class(rb_str_new_cstr(path));
}
+void
+rb_name_class(VALUE klass, ID id)
+{
+ rb_ivar_set(klass, classid, ID2SYM(id));
+}
+
VALUE
rb_class_name(VALUE klass)
{
@@ -280,7 +452,7 @@ const char *
rb_class2name(VALUE klass)
{
int permanent;
- VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, make_temporary_path);
+ VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, ivar_cache);
if (NIL_P(path)) return NULL;
return RSTRING_PTR(path);
}
@@ -301,32 +473,20 @@ struct trace_var {
struct rb_global_variable {
int counter;
int block_trace;
- VALUE *data;
+ void *data;
rb_gvar_getter_t *getter;
rb_gvar_setter_t *setter;
rb_gvar_marker_t *marker;
struct trace_var *trace;
};
-static struct rb_global_entry*
-rb_find_global_entry(ID id)
+struct rb_global_entry*
+rb_global_entry(ID id)
{
struct rb_global_entry *entry;
VALUE data;
if (!rb_id_table_lookup(rb_global_tbl, id, &data)) {
- return NULL;
- }
- entry = (struct rb_global_entry *)data;
- ASSUME(entry != NULL);
- return entry;
-}
-
-MJIT_FUNC_EXPORTED struct rb_global_entry*
-rb_global_entry(ID id)
-{
- struct rb_global_entry *entry = rb_find_global_entry(id);
- if (!entry) {
struct rb_global_variable *var;
entry = ALLOC(struct rb_global_entry);
var = ALLOC(struct rb_global_variable);
@@ -342,11 +502,14 @@ rb_global_entry(ID id)
var->trace = 0;
rb_id_table_insert(rb_global_tbl, id, (VALUE)entry);
}
+ else {
+ entry = (struct rb_global_entry *)data;
+ }
return entry;
}
VALUE
-rb_gvar_undef_getter(ID id, VALUE *_)
+rb_gvar_undef_getter(ID id, void *data, struct rb_global_variable *var)
{
rb_warning("global variable `%"PRIsVALUE"' not initialized", QUOTE_ID(id));
@@ -354,9 +517,8 @@ rb_gvar_undef_getter(ID id, VALUE *_)
}
void
-rb_gvar_undef_setter(VALUE val, ID id, VALUE *_)
+rb_gvar_undef_setter(VALUE val, ID id, void *d, struct rb_global_variable *var)
{
- struct rb_global_variable *var = rb_global_entry(id)->var;
var->getter = rb_gvar_val_getter;
var->setter = rb_gvar_val_setter;
var->marker = rb_gvar_val_marker;
@@ -370,15 +532,14 @@ rb_gvar_undef_marker(VALUE *var)
}
VALUE
-rb_gvar_val_getter(ID id, VALUE *data)
+rb_gvar_val_getter(ID id, void *data, struct rb_global_variable *var)
{
return (VALUE)data;
}
void
-rb_gvar_val_setter(VALUE val, ID id, VALUE *_)
+rb_gvar_val_setter(VALUE val, ID id, void *data, struct rb_global_variable *var)
{
- struct rb_global_variable *var = rb_global_entry(id)->var;
var->data = (void*)val;
}
@@ -390,16 +551,17 @@ rb_gvar_val_marker(VALUE *var)
}
VALUE
-rb_gvar_var_getter(ID id, VALUE *var)
+rb_gvar_var_getter(ID id, void *data, struct rb_global_variable *gvar)
{
+ VALUE *var = data;
if (!var) return Qnil;
return *var;
}
void
-rb_gvar_var_setter(VALUE val, ID id, VALUE *data)
+rb_gvar_var_setter(VALUE val, ID id, void *data, struct rb_global_variable *g)
{
- *data = val;
+ *(VALUE *)data = val;
}
void
@@ -409,7 +571,7 @@ rb_gvar_var_marker(VALUE *var)
}
void
-rb_gvar_readonly_setter(VALUE v, ID id, VALUE *_)
+rb_gvar_readonly_setter(VALUE v, ID id, void *d, struct rb_global_variable *g)
{
rb_name_error(id, "%"PRIsVALUE" is a read-only variable", QUOTE_ID(id));
}
@@ -445,34 +607,11 @@ global_id(const char *name)
if (name[0] == '$') id = rb_intern(name);
else {
size_t len = strlen(name);
- VALUE vbuf = 0;
- char *buf = ALLOCV_N(char, vbuf, len+1);
+ char *buf = ALLOCA_N(char, len+1);
buf[0] = '$';
memcpy(buf+1, name, len);
id = rb_intern2(buf, len+1);
- ALLOCV_END(vbuf);
- }
- return id;
-}
-
-static ID
-find_global_id(const char *name)
-{
- ID id;
- size_t len = strlen(name);
-
- if (name[0] == '$') {
- id = rb_check_id_cstr(name, len, NULL);
- }
- else {
- VALUE vbuf = 0;
- char *buf = ALLOCV_N(char, vbuf, len+1);
- buf[0] = '$';
- memcpy(buf+1, name, len);
- id = rb_check_id_cstr(buf, len+1, NULL);
- ALLOCV_END(vbuf);
}
-
return id;
}
@@ -480,8 +619,8 @@ void
rb_define_hooked_variable(
const char *name,
VALUE *var,
- rb_gvar_getter_t *getter,
- rb_gvar_setter_t *setter)
+ VALUE (*getter)(ANYARGS),
+ void (*setter)(ANYARGS))
{
volatile VALUE tmp = var ? *var : Qnil;
ID id = global_id(name);
@@ -510,8 +649,8 @@ rb_define_readonly_variable(const char *name, const VALUE *var)
void
rb_define_virtual_variable(
const char *name,
- rb_gvar_getter_t *getter,
- rb_gvar_setter_t *setter)
+ VALUE (*getter)(ANYARGS),
+ void (*setter)(ANYARGS))
{
if (!getter) getter = rb_gvar_val_getter;
if (!setter) setter = rb_gvar_readonly_setter;
@@ -521,9 +660,32 @@ rb_define_virtual_variable(
static void
rb_trace_eval(VALUE cmd, VALUE val)
{
- rb_eval_cmd_kw(cmd, rb_ary_new3(1, val), RB_NO_KEYWORDS);
+ rb_eval_cmd(cmd, rb_ary_new3(1, val), 0);
}
+/*
+ * call-seq:
+ * trace_var(symbol, cmd ) -> nil
+ * trace_var(symbol) {|val| block } -> nil
+ *
+ * Controls tracing of assignments to global variables. The parameter
+ * +symbol+ identifies the variable (as either a string name or a
+ * symbol identifier). _cmd_ (which may be a string or a
+ * +Proc+ object) or block is executed whenever the variable
+ * is assigned. The block or +Proc+ object receives the
+ * variable's new value as a parameter. Also see
+ * <code>Kernel::untrace_var</code>.
+ *
+ * trace_var :$_, proc {|v| puts "$_ is now '#{v}'" }
+ * $_ = "hello"
+ * $_ = ' there'
+ *
+ * <em>produces:</em>
+ *
+ * $_ is now 'hello'
+ * $_ is now ' there'
+ */
+
VALUE
rb_f_trace_var(int argc, const VALUE *argv)
{
@@ -538,6 +700,9 @@ rb_f_trace_var(int argc, const VALUE *argv)
return rb_f_untrace_var(argc, argv);
}
entry = rb_global_entry(rb_to_id(var));
+ if (OBJ_TAINTED(cmd)) {
+ rb_raise(rb_eSecurityError, "Insecure: tainted variable trace");
+ }
trace = ALLOC(struct trace_var);
trace->next = entry->var->trace;
trace->func = rb_trace_eval;
@@ -570,6 +735,16 @@ remove_trace(struct rb_global_variable *var)
var->trace = t.next;
}
+/*
+ * call-seq:
+ * untrace_var(symbol [, cmd] ) -> array or nil
+ *
+ * Removes tracing for the specified command on the given global
+ * variable and returns +nil+. If no command is specified,
+ * removes all tracing for that variable and returns an array
+ * containing the commands actually removed.
+ */
+
VALUE
rb_f_untrace_var(int argc, const VALUE *argv)
{
@@ -615,11 +790,11 @@ rb_f_untrace_var(int argc, const VALUE *argv)
return Qnil;
}
-MJIT_FUNC_EXPORTED VALUE
+VALUE
rb_gvar_get(struct rb_global_entry *entry)
{
struct rb_global_variable *var = entry->var;
- return (*var->getter)(entry->id, var->data);
+ return (*var->getter)(entry->id, var->data, var);
}
struct trace_data {
@@ -628,9 +803,8 @@ struct trace_data {
};
static VALUE
-trace_ev(VALUE v)
+trace_ev(struct trace_data *data)
{
- struct trace_data *data = (void *)v;
struct trace_var *trace = data->trace;
while (trace) {
@@ -642,21 +816,20 @@ trace_ev(VALUE v)
}
static VALUE
-trace_en(VALUE v)
+trace_en(struct rb_global_variable *var)
{
- struct rb_global_variable *var = (void *)v;
var->block_trace = 0;
remove_trace(var);
return Qnil; /* not reached */
}
-MJIT_FUNC_EXPORTED VALUE
+VALUE
rb_gvar_set(struct rb_global_entry *entry, VALUE val)
{
struct trace_data trace;
struct rb_global_variable *var = entry->var;
- (*var->setter)(val, entry->id, var->data);
+ (*var->setter)(val, entry->id, var->data, var);
if (var->trace && !var->block_trace) {
var->block_trace = 1;
@@ -680,42 +853,18 @@ VALUE
rb_gv_get(const char *name)
{
struct rb_global_entry *entry;
- ID id = find_global_id(name);
- if (!id) {
- rb_warning("global variable `%s' not initialized", name);
- return Qnil;
- }
-
- entry = rb_global_entry(id);
+ entry = rb_global_entry(global_id(name));
return rb_gvar_get(entry);
}
-MJIT_FUNC_EXPORTED VALUE
+VALUE
rb_gvar_defined(struct rb_global_entry *entry)
{
if (entry->var->getter == rb_gvar_undef_getter) return Qfalse;
return Qtrue;
}
-rb_gvar_getter_t *
-rb_gvar_getter_function_of(const struct rb_global_entry *entry)
-{
- return entry->var->getter;
-}
-
-rb_gvar_setter_t *
-rb_gvar_setter_function_of(const struct rb_global_entry *entry)
-{
- return entry->var->setter;
-}
-
-bool
-rb_gvar_is_traced(const struct rb_global_entry *entry)
-{
- return !!entry->var->trace;
-}
-
static enum rb_id_table_iterator_result
gvar_i(ID key, VALUE val, void *a)
{
@@ -724,6 +873,15 @@ gvar_i(ID key, VALUE val, void *a)
return ID_TABLE_CONTINUE;
}
+/*
+ * call-seq:
+ * global_variables -> array
+ *
+ * Returns an array of the names of global variables.
+ *
+ * global_variables.grep /std/ #=> [:$stdin, :$stdout, :$stderr]
+ */
+
VALUE
rb_f_global_variables(void)
{
@@ -799,12 +957,6 @@ gen_ivtbl_get(VALUE obj, struct gen_ivtbl **ivtbl)
return 0;
}
-MJIT_FUNC_EXPORTED struct st_table *
-rb_ivar_generic_ivtbl(void)
-{
- return generic_iv_tbl;
-}
-
static VALUE
generic_ivar_delete(VALUE obj, ID id, VALUE undef)
{
@@ -849,7 +1001,7 @@ generic_ivar_get(VALUE obj, ID id, VALUE undef)
static size_t
gen_ivtbl_bytes(size_t n)
{
- return offsetof(struct gen_ivtbl, ivptr) + n * sizeof(VALUE);
+ return sizeof(struct gen_ivtbl) + n * sizeof(VALUE) - sizeof(VALUE);
}
static struct gen_ivtbl *
@@ -980,16 +1132,6 @@ rb_mark_generic_ivar(VALUE obj)
}
void
-rb_mv_generic_ivar(VALUE rsrc, VALUE dst)
-{
- st_data_t key = (st_data_t)rsrc;
- struct gen_ivtbl *ivtbl;
-
- if (st_delete(generic_iv_tbl, &key, (st_data_t *)&ivtbl))
- st_insert(generic_iv_tbl, (st_data_t)dst, (st_data_t)ivtbl);
-}
-
-void
rb_free_generic_ivar(VALUE obj)
{
st_data_t key = (st_data_t)obj;
@@ -1171,148 +1313,65 @@ generic_ivar_set(VALUE obj, ID id, VALUE val)
RB_OBJ_WRITTEN(obj, Qundef, val);
}
-static VALUE *
-obj_ivar_heap_alloc(VALUE obj, size_t newsize)
-{
- VALUE *newptr = rb_transient_heap_alloc(obj, sizeof(VALUE) * newsize);
-
- if (newptr != NULL) {
- ROBJ_TRANSIENT_SET(obj);
- }
- else {
- ROBJ_TRANSIENT_UNSET(obj);
- newptr = ALLOC_N(VALUE, newsize);
- }
- return newptr;
-}
-
-static VALUE *
-obj_ivar_heap_realloc(VALUE obj, int32_t len, size_t newsize)
-{
- VALUE *newptr;
- int i;
-
- if (ROBJ_TRANSIENT_P(obj)) {
- const VALUE *orig_ptr = ROBJECT(obj)->as.heap.ivptr;
- newptr = obj_ivar_heap_alloc(obj, newsize);
-
- assert(newptr);
- ROBJECT(obj)->as.heap.ivptr = newptr;
- for (i=0; i<(int)len; i++) {
- newptr[i] = orig_ptr[i];
- }
- }
- else {
- REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);
- newptr = ROBJECT(obj)->as.heap.ivptr;
- }
-
- return newptr;
-}
-
-#if USE_TRANSIENT_HEAP
-void
-rb_obj_transient_heap_evacuate(VALUE obj, int promote)
-{
- if (ROBJ_TRANSIENT_P(obj)) {
- uint32_t len = ROBJECT_NUMIV(obj);
- const VALUE *old_ptr = ROBJECT_IVPTR(obj);
- VALUE *new_ptr;
-
- if (promote) {
- new_ptr = ALLOC_N(VALUE, len);
- ROBJ_TRANSIENT_UNSET(obj);
- }
- else {
- new_ptr = obj_ivar_heap_alloc(obj, len);
- }
- MEMCPY(new_ptr, old_ptr, VALUE, len);
- ROBJECT(obj)->as.heap.ivptr = new_ptr;
- }
-}
-#endif
-
-static VALUE
-obj_ivar_set(VALUE obj, ID id, VALUE val)
+VALUE
+rb_ivar_set(VALUE obj, ID id, VALUE val)
{
struct ivar_update ivup;
uint32_t i, len;
- ivup.iv_extended = 0;
- ivup.u.iv_index_tbl = iv_index_tbl_make(obj);
- iv_index_tbl_extend(&ivup, id);
- len = ROBJECT_NUMIV(obj);
- if (len <= ivup.index) {
- VALUE *ptr = ROBJECT_IVPTR(obj);
- if (ivup.index < ROBJECT_EMBED_LEN_MAX) {
- RBASIC(obj)->flags |= ROBJECT_EMBED;
- ptr = ROBJECT(obj)->as.ary;
- for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
- ptr[i] = Qundef;
- }
- }
- else {
- VALUE *newptr;
- uint32_t newsize = iv_index_tbl_newsize(&ivup);
-
- if (RBASIC(obj)->flags & ROBJECT_EMBED) {
- newptr = obj_ivar_heap_alloc(obj, newsize);
- MEMCPY(newptr, ptr, VALUE, len);
- RBASIC(obj)->flags &= ~ROBJECT_EMBED;
- ROBJECT(obj)->as.heap.ivptr = newptr;
- }
- else {
- newptr = obj_ivar_heap_realloc(obj, len, newsize);
- }
- for (; len < newsize; len++) {
- newptr[len] = Qundef;
- }
- ROBJECT(obj)->as.heap.numiv = newsize;
- ROBJECT(obj)->as.heap.iv_index_tbl = ivup.u.iv_index_tbl;
- }
- }
- RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val);
-
- return val;
-}
-
-static void
-ivar_set(VALUE obj, ID id, VALUE val)
-{
RB_DEBUG_COUNTER_INC(ivar_set_base);
+ rb_check_frozen(obj);
+
switch (BUILTIN_TYPE(obj)) {
case T_OBJECT:
- obj_ivar_set(obj, id, val);
- break;
+ ivup.iv_extended = 0;
+ ivup.u.iv_index_tbl = iv_index_tbl_make(obj);
+ iv_index_tbl_extend(&ivup, id);
+ len = ROBJECT_NUMIV(obj);
+ if (len <= ivup.index) {
+ VALUE *ptr = ROBJECT_IVPTR(obj);
+ if (ivup.index < ROBJECT_EMBED_LEN_MAX) {
+ RBASIC(obj)->flags |= ROBJECT_EMBED;
+ ptr = ROBJECT(obj)->as.ary;
+ for (i = 0; i < ROBJECT_EMBED_LEN_MAX; i++) {
+ ptr[i] = Qundef;
+ }
+ }
+ else {
+ VALUE *newptr;
+ uint32_t newsize = iv_index_tbl_newsize(&ivup);
+
+ if (RBASIC(obj)->flags & ROBJECT_EMBED) {
+ newptr = ALLOC_N(VALUE, newsize);
+ MEMCPY(newptr, ptr, VALUE, len);
+ RBASIC(obj)->flags &= ~ROBJECT_EMBED;
+ ROBJECT(obj)->as.heap.ivptr = newptr;
+ }
+ else {
+ REALLOC_N(ROBJECT(obj)->as.heap.ivptr, VALUE, newsize);
+ newptr = ROBJECT(obj)->as.heap.ivptr;
+ }
+ for (; len < newsize; len++)
+ newptr[len] = Qundef;
+ ROBJECT(obj)->as.heap.numiv = newsize;
+ ROBJECT(obj)->as.heap.iv_index_tbl = ivup.u.iv_index_tbl;
+ }
+ }
+ RB_OBJ_WRITE(obj, &ROBJECT_IVPTR(obj)[ivup.index], val);
+ break;
case T_CLASS:
case T_MODULE:
- if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
- rb_class_ivar_set(obj, id, val);
+ if (!RCLASS_IV_TBL(obj)) RCLASS_IV_TBL(obj) = st_init_numtable();
+ rb_class_ivar_set(obj, id, val);
break;
default:
- generic_ivar_set(obj, id, val);
- break;
+ generic_ivar_set(obj, id, val);
+ break;
}
-}
-
-VALUE
-rb_ivar_set(VALUE obj, ID id, VALUE val)
-{
- rb_check_frozen(obj);
- ivar_set(obj, id, val);
return val;
}
-void
-rb_ivar_set_internal(VALUE obj, ID id, VALUE val)
-{
- // should be internal instance variable name (no @ prefix)
- VM_ASSERT(!rb_is_instance_id(id));
-
- ivar_set(obj, id, val);
-}
-
VALUE
rb_ivar_defined(VALUE obj, ID id)
{
@@ -1333,7 +1392,7 @@ rb_ivar_defined(VALUE obj, ID id)
break;
case T_CLASS:
case T_MODULE:
- if (RCLASS_IV_TBL(obj) && st_is_member(RCLASS_IV_TBL(obj), (st_data_t)id))
+ if (RCLASS_IV_TBL(obj) && st_lookup(RCLASS_IV_TBL(obj), (st_data_t)id, 0))
return Qtrue;
break;
default:
@@ -1344,11 +1403,9 @@ rb_ivar_defined(VALUE obj, ID id)
return Qfalse;
}
-typedef int rb_ivar_foreach_callback_func(ID key, VALUE val, st_data_t arg);
-
struct obj_ivar_tag {
VALUE obj;
- rb_ivar_foreach_callback_func *func;
+ int (*func)(ID key, VALUE val, st_data_t arg);
st_data_t arg;
};
@@ -1366,7 +1423,7 @@ obj_ivar_i(st_data_t key, st_data_t index, st_data_t arg)
}
static void
-obj_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
+obj_ivar_each(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
{
st_table *tbl;
struct obj_ivar_tag data;
@@ -1384,7 +1441,7 @@ obj_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
struct gen_ivar_tag {
struct gen_ivtbl *ivtbl;
- rb_ivar_foreach_callback_func *func;
+ int (*func)(ID key, VALUE val, st_data_t arg);
st_data_t arg;
};
@@ -1403,7 +1460,7 @@ gen_ivar_each_i(st_data_t key, st_data_t index, st_data_t data)
}
static void
-gen_ivar_each(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
+gen_ivar_each(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
{
struct gen_ivar_tag data;
st_table *iv_index_tbl = RCLASS_IV_INDEX_TBL(rb_obj_class(obj));
@@ -1486,7 +1543,7 @@ rb_copy_generic_ivar(VALUE clone, VALUE obj)
}
void
-rb_ivar_foreach(VALUE obj, rb_ivar_foreach_callback_func *func, st_data_t arg)
+rb_ivar_foreach(VALUE obj, int (*func)(ANYARGS), st_data_t arg)
{
if (SPECIAL_CONST_P(obj)) return;
switch (BUILTIN_TYPE(obj)) {
@@ -1609,11 +1666,9 @@ check_id_type(VALUE obj, VALUE *pname,
/*
* call-seq:
* obj.remove_instance_variable(symbol) -> obj
- * obj.remove_instance_variable(string) -> obj
*
* Removes the named instance variable from <i>obj</i>, returning that
* variable's value.
- * String arguments are converted to symbols.
*
* class Dummy
* attr_reader :var
@@ -1675,7 +1730,7 @@ rb_obj_remove_instance_variable(VALUE obj, VALUE name)
not_defined:
rb_name_err_raise("instance variable %1$s not defined",
obj, name);
- UNREACHABLE_RETURN(Qnil);
+ UNREACHABLE;
}
NORETURN(static void uninitialized_constant(VALUE, VALUE));
@@ -1693,7 +1748,7 @@ uninitialized_constant(VALUE klass, VALUE name)
VALUE
rb_const_missing(VALUE klass, VALUE name)
{
- VALUE value = rb_funcallv(klass, idConst_missing, 1, &name);
+ VALUE value = rb_funcallv(klass, rb_intern("const_missing"), 1, &name);
rb_vm_inc_const_missing_count();
return value;
}
@@ -1738,21 +1793,16 @@ rb_const_missing(VALUE klass, VALUE name)
VALUE
rb_mod_const_missing(VALUE klass, VALUE name)
{
- VALUE ref = GET_EC()->private_const_reference;
rb_vm_pop_cfunc_frame();
- if (ref) {
- rb_name_err_raise("private constant %2$s::%1$s referenced",
- ref, name);
- }
uninitialized_constant(klass, name);
- UNREACHABLE_RETURN(Qnil);
+ UNREACHABLE;
}
static void
autoload_mark(void *ptr)
{
- rb_mark_tbl_no_pin((st_table *)ptr);
+ rb_mark_tbl((st_table *)ptr);
}
static void
@@ -1768,15 +1818,9 @@ autoload_memsize(const void *ptr)
return st_memsize(tbl);
}
-static void
-autoload_compact(void *ptr)
-{
- rb_gc_update_tbl_refs((st_table *)ptr);
-}
-
static const rb_data_type_t autoload_data_type = {
"autoload",
- {autoload_mark, autoload_free, autoload_memsize, autoload_compact,},
+ {autoload_mark, autoload_free, autoload_memsize,},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
@@ -1797,61 +1841,34 @@ autoload_data(VALUE mod, ID id)
return (VALUE)val;
}
-struct autoload_const {
- struct list_node cnode; /* <=> autoload_data_i.constants */
- VALUE mod;
- VALUE ad; /* autoload_data_i */
- VALUE value;
- VALUE file;
- ID id;
- rb_const_flag_t flag;
- int line;
-};
-
/* always on stack, no need to mark */
struct autoload_state {
- struct autoload_const *ac;
+ struct autoload_data_i *ele;
+ VALUE mod;
VALUE result;
+ ID id;
VALUE thread;
- struct list_node waitq;
+ union {
+ struct list_node node;
+ struct list_head head;
+ } waitq;
};
struct autoload_data_i {
VALUE feature;
+ int safe_level;
+ rb_const_flag_t flag;
+ VALUE value;
struct autoload_state *state; /* points to on-stack struct */
rb_serial_t fork_gen;
- struct list_head constants; /* <=> autoload_const.cnode */
};
static void
-autoload_i_compact(void *ptr)
-{
- struct autoload_data_i *p = ptr;
- p->feature = rb_gc_location(p->feature);
-}
-
-static void
autoload_i_mark(void *ptr)
{
struct autoload_data_i *p = ptr;
-
- rb_gc_mark_movable(p->feature);
-
- /* allow GC to free us if no modules refer to this via autoload_const.ad */
- if (list_empty(&p->constants)) {
- rb_hash_delete(autoload_featuremap, p->feature);
- }
-}
-
-static void
-autoload_i_free(void *ptr)
-{
- struct autoload_data_i *p = ptr;
-
- /* we may leak some memory at VM shutdown time, no big deal */
- if (list_empty(&p->constants)) {
- xfree(p);
- }
+ rb_gc_mark(p->feature);
+ rb_gc_mark(p->value);
}
static size_t
@@ -1862,65 +1879,20 @@ autoload_i_memsize(const void *ptr)
static const rb_data_type_t autoload_data_i_type = {
"autoload_i",
- {autoload_i_mark, autoload_i_free, autoload_i_memsize, autoload_i_compact},
- 0, 0, RUBY_TYPED_FREE_IMMEDIATELY
-};
-
-static void
-autoload_c_compact(void *ptr)
-{
- struct autoload_const *ac = ptr;
-
- ac->mod = rb_gc_location(ac->mod);
- ac->ad = rb_gc_location(ac->ad);
- ac->value = rb_gc_location(ac->value);
- ac->file = rb_gc_location(ac->file);
-}
-
-static void
-autoload_c_mark(void *ptr)
-{
- struct autoload_const *ac = ptr;
-
- rb_gc_mark_movable(ac->mod);
- rb_gc_mark_movable(ac->ad);
- rb_gc_mark_movable(ac->value);
- rb_gc_mark_movable(ac->file);
-}
-
-static void
-autoload_c_free(void *ptr)
-{
- struct autoload_const *ac = ptr;
- list_del(&ac->cnode);
- xfree(ac);
-}
-
-static size_t
-autoload_c_memsize(const void *ptr)
-{
- return sizeof(struct autoload_const);
-}
-
-static const rb_data_type_t autoload_const_type = {
- "autoload_const",
- {autoload_c_mark, autoload_c_free, autoload_c_memsize, autoload_c_compact,},
+ {autoload_i_mark, RUBY_TYPED_DEFAULT_FREE, autoload_i_memsize,},
0, 0, RUBY_TYPED_FREE_IMMEDIATELY
};
static struct autoload_data_i *
-get_autoload_data(VALUE acv, struct autoload_const **acp)
+get_autoload_data(VALUE av)
{
- struct autoload_const *ac = rb_check_typeddata(acv, &autoload_const_type);
- struct autoload_data_i *ele;
+ struct autoload_data_i *ele = rb_check_typeddata(av, &autoload_data_i_type);
- ele = rb_check_typeddata(ac->ad, &autoload_data_i_type);
/* do not reach across stack for ->state after forking: */
if (ele && ele->state && ele->fork_gen != GET_VM()->fork_gen) {
ele->state = 0;
ele->fork_gen = 0;
}
- if (acp) *acp = ac;
return ele;
}
@@ -1970,37 +1942,17 @@ rb_autoload_str(VALUE mod, ID id, VALUE file)
DATA_PTR(av) = tbl = st_init_numtable();
}
- file = rb_fstring(file);
- if (!autoload_featuremap) {
- autoload_featuremap = rb_ident_hash_new();
- rb_obj_hide(autoload_featuremap);
- rb_gc_register_mark_object(autoload_featuremap);
- }
- ad = rb_hash_aref(autoload_featuremap, file);
- if (NIL_P(ad)) {
- ad = TypedData_Make_Struct(0, struct autoload_data_i,
- &autoload_data_i_type, ele);
- ele->feature = file;
- ele->state = 0;
- list_head_init(&ele->constants);
- rb_hash_aset(autoload_featuremap, file, ad);
- }
- else {
- ele = rb_check_typeddata(ad, &autoload_data_i_type);
- }
- {
- VALUE acv;
- struct autoload_const *ac;
- acv = TypedData_Make_Struct(0, struct autoload_const,
- &autoload_const_type, ac);
- ac->mod = mod;
- ac->id = id;
- ac->value = Qundef;
- ac->flag = CONST_PUBLIC;
- ac->ad = ad;
- list_add_tail(&ele->constants, &ac->cnode);
- st_insert(tbl, (st_data_t)id, (st_data_t)acv);
+ ad = TypedData_Make_Struct(0, struct autoload_data_i, &autoload_data_i_type, ele);
+ if (OBJ_TAINTED(file)) {
+ file = rb_str_dup(file);
+ FL_UNSET(file, FL_TAINT);
}
+ ele->feature = rb_fstring(file);
+ ele->safe_level = rb_safe_level();
+ ele->value = Qundef;
+ ele->state = 0;
+ ele->flag = CONST_PUBLIC;
+ st_insert(tbl, (st_data_t)id, (st_data_t)ad);
}
static void
@@ -2010,22 +1962,8 @@ autoload_delete(VALUE mod, ID id)
if (st_lookup(RCLASS_IV_TBL(mod), (st_data_t)autoload, &val)) {
struct st_table *tbl = check_autoload_table((VALUE)val);
- struct autoload_data_i *ele;
- struct autoload_const *ac;
st_delete(tbl, &n, &load);
- ele = get_autoload_data((VALUE)load, &ac);
- VM_ASSERT(ele);
- if (ele) {
- VM_ASSERT(!list_empty(&ele->constants));
- }
-
- /*
- * we must delete here to avoid "already initialized" warnings
- * with parallel autoload. Using list_del_init here so list_del
- * works in autoload_c_free
- */
- list_del_init(&ac->cnode);
if (tbl->num_entries == 0) {
n = autoload;
@@ -2035,14 +1973,28 @@ autoload_delete(VALUE mod, ID id)
}
static VALUE
+autoload_provided(VALUE arg)
+{
+ const char **p = (const char **)arg;
+ return rb_feature_provided(*p, p);
+}
+
+static VALUE
+reset_safe(VALUE safe)
+{
+ rb_set_safe_level_force((int)safe);
+ return safe;
+}
+
+static VALUE
check_autoload_required(VALUE mod, ID id, const char **loadingpath)
{
- VALUE file;
- VALUE load = autoload_data(mod, id);
+ VALUE file, load;
struct autoload_data_i *ele;
const char *loading;
+ int safe;
- if (!load || !(ele = get_autoload_data(load, 0))) {
+ if (!(load = autoload_data(mod, id)) || !(ele = get_autoload_data(load))) {
return 0;
}
file = ele->feature;
@@ -2062,7 +2014,9 @@ check_autoload_required(VALUE mod, ID id, const char **loadingpath)
}
loading = RSTRING_PTR(file);
- if (!rb_feature_provided(loading, &loading)) {
+ safe = rb_safe_level();
+ rb_set_safe_level_force(0);
+ if (!rb_ensure(autoload_provided, (VALUE)&loading, reset_safe, (VALUE)safe)) {
return load;
}
if (loadingpath && loading) {
@@ -2072,37 +2026,24 @@ check_autoload_required(VALUE mod, ID id, const char **loadingpath)
return 0;
}
-static struct autoload_const *autoloading_const_entry(VALUE mod, ID id);
-
-MJIT_FUNC_EXPORTED int
+int
rb_autoloading_value(VALUE mod, ID id, VALUE* value, rb_const_flag_t *flag)
{
- struct autoload_const *ac = autoloading_const_entry(mod, id);
- if (!ac) return FALSE;
-
- if (value) {
- *value = ac->value;
- }
- if (flag) {
- *flag = ac->flag;
- }
- return TRUE;
-}
-
-struct autoload_const *
-autoloading_const_entry(VALUE mod, ID id)
-{
- VALUE load = autoload_data(mod, id);
+ VALUE load;
struct autoload_data_i *ele;
- struct autoload_const *ac;
- if (!load || !(ele = get_autoload_data(load, &ac))) {
- return 0;
+ if (!(load = autoload_data(mod, id)) || !(ele = get_autoload_data(load))) {
+ return 0;
}
-
if (ele->state && ele->state->thread == rb_thread_current()) {
- if (ac->value != Qundef) {
- return ac;
+ if (ele->value != Qundef) {
+ if (value) {
+ *value = ele->value;
+ }
+ if (flag) {
+ *flag = ele->flag;
+ }
+ return 1;
}
}
return 0;
@@ -2119,16 +2060,23 @@ autoload_defined_p(VALUE mod, ID id)
return !rb_autoloading_value(mod, id, NULL, NULL);
}
-static void const_tbl_update(struct autoload_const *);
+struct autoload_const_set_args {
+ VALUE mod;
+ ID id;
+ VALUE value;
+ rb_const_flag_t flag;
+};
+
+static void const_tbl_update(struct autoload_const_set_args *);
static VALUE
autoload_const_set(VALUE arg)
{
- struct autoload_const *ac = (struct autoload_const *)arg;
- VALUE klass = ac->mod;
- ID id = ac->id;
- check_before_mod_set(klass, id, ac->value, "constant");
- const_tbl_update(ac);
+ struct autoload_const_set_args* args = (struct autoload_const_set_args *)arg;
+ VALUE klass = args->mod;
+ ID id = args->id;
+ check_before_mod_set(klass, id, args->value, "constant");
+ const_tbl_update(args);
return 0; /* ignored */
}
@@ -2136,13 +2084,10 @@ static VALUE
autoload_require(VALUE arg)
{
struct autoload_state *state = (struct autoload_state *)arg;
- struct autoload_const *ac = state->ac;
- struct autoload_data_i *ele;
- ele = rb_check_typeddata(ac->ad, &autoload_data_i_type);
/* this may release GVL and switch threads: */
state->result = rb_funcall(rb_vm_top_self(), rb_intern("require"), 1,
- ele->feature);
+ state->ele->feature);
return state->result;
}
@@ -2152,36 +2097,37 @@ autoload_reset(VALUE arg)
{
struct autoload_state *state = (struct autoload_state *)arg;
int need_wakeups = 0;
- struct autoload_const *ac = state->ac;
- struct autoload_data_i *ele;
- ele = rb_check_typeddata(ac->ad, &autoload_data_i_type);
- if (ele->state == state) {
+ if (state->ele->state == state) {
need_wakeups = 1;
- ele->state = 0;
- ele->fork_gen = 0;
+ state->ele->state = 0;
+ state->ele->fork_gen = 0;
}
/* At the last, move a value defined in autoload to constant table */
- if (RTEST(state->result)) {
- struct autoload_const *next;
+ if (RTEST(state->result) && state->ele->value != Qundef) {
+ int safe_backup;
+ struct autoload_const_set_args args;
- list_for_each_safe(&ele->constants, ac, next, cnode) {
- if (ac->value != Qundef) {
- autoload_const_set((VALUE)ac);
- }
- }
+ args.mod = state->mod;
+ args.id = state->id;
+ args.value = state->ele->value;
+ args.flag = state->ele->flag;
+ safe_backup = rb_safe_level();
+ rb_set_safe_level_force(state->ele->safe_level);
+ rb_ensure(autoload_const_set, (VALUE)&args,
+ reset_safe, (VALUE)safe_backup);
}
/* wakeup any waiters we had */
if (need_wakeups) {
struct autoload_state *cur = 0, *nxt;
- list_for_each_safe((struct list_head *)&state->waitq, cur, nxt, waitq) {
+ list_for_each_safe(&state->waitq.head, cur, nxt, waitq.node) {
VALUE th = cur->thread;
cur->thread = Qfalse;
- list_del_init(&cur->waitq); /* idempotent */
+ list_del_init(&cur->waitq.node); /* idempotent */
/*
* cur is stored on the stack of cur->waiting_th,
@@ -2216,7 +2162,7 @@ autoload_sleep_done(VALUE arg)
struct autoload_state *state = (struct autoload_state *)arg;
if (state->thread != Qfalse && rb_thread_to_be_killed(state->thread)) {
- list_del(&state->waitq); /* idempotent after list_del_init */
+ list_del(&state->waitq.node); /* idempotent after list_del_init */
}
return Qfalse;
@@ -2228,10 +2174,7 @@ rb_autoload_load(VALUE mod, ID id)
VALUE load, result;
const char *loading = 0, *src;
struct autoload_data_i *ele;
- struct autoload_const *ac;
struct autoload_state state;
- int flag = -1;
- rb_const_entry_t *ce;
if (!autoload_defined_p(mod, id)) return Qfalse;
load = check_autoload_required(mod, id, &loading);
@@ -2239,15 +2182,14 @@ rb_autoload_load(VALUE mod, ID id)
src = rb_sourcefile();
if (src && loading && strcmp(src, loading) == 0) return Qfalse;
- if ((ce = rb_const_lookup(mod, id))) {
- flag = ce->flag & (CONST_DEPRECATED | CONST_VISIBILITY_MASK);
- }
-
/* set ele->state for a marker of autoloading thread */
- if (!(ele = get_autoload_data(load, &ac))) {
+ if (!(ele = get_autoload_data(load))) {
return Qfalse;
}
- state.ac = ac;
+
+ state.ele = ele;
+ state.mod = mod;
+ state.id = id;
state.thread = rb_thread_current();
if (!ele->state) {
ele->state = &state;
@@ -2257,26 +2199,22 @@ rb_autoload_load(VALUE mod, ID id)
* autoload_reset will wake up any threads added to this
* iff the GVL is released during autoload_require
*/
- list_head_init((struct list_head *)&state.waitq);
+ list_head_init(&state.waitq.head);
}
else if (state.thread == ele->state->thread) {
return Qfalse;
}
else {
- list_add_tail((struct list_head *)&ele->state->waitq, &state.waitq);
+ list_add_tail(&ele->state->waitq.head, &state.waitq.node);
rb_ensure(autoload_sleep, (VALUE)&state,
autoload_sleep_done, (VALUE)&state);
}
/* autoload_data_i can be deleted by another thread while require */
- state.result = Qfalse;
result = rb_ensure(autoload_require, (VALUE)&state,
autoload_reset, (VALUE)&state);
- if (flag > 0 && (ce = rb_const_lookup(mod, id))) {
- ce->flag |= flag;
- }
RB_GC_GUARD(load);
return result;
}
@@ -2284,30 +2222,22 @@ rb_autoload_load(VALUE mod, ID id)
VALUE
rb_autoload_p(VALUE mod, ID id)
{
- return rb_autoload_at_p(mod, id, TRUE);
-}
-
-VALUE
-rb_autoload_at_p(VALUE mod, ID id, int recur)
-{
VALUE load;
struct autoload_data_i *ele;
while (!autoload_defined_p(mod, id)) {
- if (!recur) return Qnil;
mod = RCLASS_SUPER(mod);
if (!mod) return Qnil;
}
load = check_autoload_required(mod, id, 0);
if (!load) return Qnil;
- return (ele = get_autoload_data(load, 0)) ? ele->feature : Qnil;
+ return (ele = get_autoload_data(load)) ? ele->feature : Qnil;
}
-MJIT_FUNC_EXPORTED void
+void
rb_const_warn_if_deprecated(const rb_const_entry_t *ce, VALUE klass, ID id)
{
- if (RB_CONST_DEPRECATED_P(ce) &&
- rb_warning_category_enabled_p(RB_WARN_CATEGORY_DEPRECATED)) {
+ if (RB_CONST_DEPRECATED_P(ce)) {
if (klass == rb_cObject) {
rb_warn("constant ::%"PRIsVALUE" is deprecated", QUOTE_ID(id));
}
@@ -2327,11 +2257,14 @@ rb_const_get_0(VALUE klass, ID id, int exclude, int recurse, int visibility)
}
static VALUE
-rb_const_search_from(VALUE klass, ID id, int exclude, int recurse, int visibility)
+rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility)
{
- VALUE value, tmp;
+ VALUE value, tmp, av;
+ rb_const_flag_t flag;
+ int mod_retry = 0;
tmp = klass;
+ retry:
while (RTEST(tmp)) {
VALUE am = 0;
rb_const_entry_t *ce;
@@ -2339,48 +2272,40 @@ rb_const_search_from(VALUE klass, ID id, int exclude, int recurse, int visibilit
while ((ce = rb_const_lookup(tmp, id))) {
if (visibility && RB_CONST_PRIVATE_P(ce)) {
if (BUILTIN_TYPE(tmp) == T_ICLASS) tmp = RBASIC(tmp)->klass;
- GET_EC()->private_const_reference = tmp;
- return Qundef;
+ rb_name_err_raise("private constant %2$s::%1$s referenced",
+ tmp, ID2SYM(id));
}
rb_const_warn_if_deprecated(ce, tmp, id);
value = ce->value;
if (value == Qundef) {
- struct autoload_const *ac;
if (am == tmp) break;
am = tmp;
- ac = autoloading_const_entry(tmp, id);
- if (ac) return ac->value;
+ if (rb_autoloading_value(tmp, id, &av, &flag)) return av;
rb_autoload_load(tmp, id);
continue;
}
- if (exclude && tmp == rb_cObject) {
- goto not_found;
+ if (exclude && tmp == rb_cObject && klass != rb_cObject) {
+#if 0
+ rb_warn("toplevel constant %"PRIsVALUE" referenced by %"PRIsVALUE"::%"PRIsVALUE"",
+ QUOTE_ID(id), rb_class_name(klass), QUOTE_ID(id));
+#else
+ return Qundef;
+#endif
}
return value;
}
if (!recurse) break;
tmp = RCLASS_SUPER(tmp);
}
+ if (!exclude && !mod_retry && BUILTIN_TYPE(klass) == T_MODULE) {
+ mod_retry = 1;
+ tmp = rb_cObject;
+ goto retry;
+ }
- not_found:
- GET_EC()->private_const_reference = 0;
return Qundef;
}
-static VALUE
-rb_const_search(VALUE klass, ID id, int exclude, int recurse, int visibility)
-{
- VALUE value;
-
- if (klass == rb_cObject) exclude = FALSE;
- value = rb_const_search_from(klass, id, exclude, recurse, visibility);
- if (value != Qundef) return value;
- if (exclude) return value;
- if (BUILTIN_TYPE(klass) != T_MODULE) return value;
- /* search global const too, if klass is a module */
- return rb_const_search_from(rb_cObject, id, FALSE, recurse, visibility);
-}
-
VALUE
rb_const_get_from(VALUE klass, ID id)
{
@@ -2399,74 +2324,22 @@ rb_const_get_at(VALUE klass, ID id)
return rb_const_get_0(klass, id, TRUE, FALSE, FALSE);
}
-MJIT_FUNC_EXPORTED VALUE
+VALUE
rb_public_const_get_from(VALUE klass, ID id)
{
return rb_const_get_0(klass, id, TRUE, TRUE, TRUE);
}
-MJIT_FUNC_EXPORTED VALUE
-rb_public_const_get_at(VALUE klass, ID id)
-{
- return rb_const_get_0(klass, id, TRUE, FALSE, TRUE);
-}
-
-NORETURN(static void undefined_constant(VALUE mod, VALUE name));
-static void
-undefined_constant(VALUE mod, VALUE name)
-{
- rb_name_err_raise("constant %2$s::%1$s not defined",
- mod, name);
-}
-
-static VALUE
-rb_const_location_from(VALUE klass, ID id, int exclude, int recurse, int visibility)
-{
- while (RTEST(klass)) {
- rb_const_entry_t *ce;
-
- while ((ce = rb_const_lookup(klass, id))) {
- if (visibility && RB_CONST_PRIVATE_P(ce)) {
- return Qnil;
- }
- if (exclude && klass == rb_cObject) {
- goto not_found;
- }
- if (NIL_P(ce->file)) return rb_ary_new();
- return rb_assoc_new(ce->file, INT2NUM(ce->line));
- }
- if (!recurse) break;
- klass = RCLASS_SUPER(klass);
- }
-
- not_found:
- return Qnil;
-}
-
-static VALUE
-rb_const_location(VALUE klass, ID id, int exclude, int recurse, int visibility)
-{
- VALUE loc;
-
- if (klass == rb_cObject) exclude = FALSE;
- loc = rb_const_location_from(klass, id, exclude, recurse, visibility);
- if (!NIL_P(loc)) return loc;
- if (exclude) return loc;
- if (BUILTIN_TYPE(klass) != T_MODULE) return loc;
- /* search global const too, if klass is a module */
- return rb_const_location_from(rb_cObject, id, FALSE, recurse, visibility);
-}
-
VALUE
-rb_const_source_location(VALUE klass, ID id)
+rb_public_const_get(VALUE klass, ID id)
{
- return rb_const_location(klass, id, FALSE, TRUE, FALSE);
+ return rb_const_get_0(klass, id, FALSE, TRUE, TRUE);
}
-MJIT_FUNC_EXPORTED VALUE
-rb_const_source_location_at(VALUE klass, ID id)
+VALUE
+rb_public_const_get_at(VALUE klass, ID id)
{
- return rb_const_location(klass, id, TRUE, FALSE, FALSE);
+ return rb_const_get_0(klass, id, TRUE, FALSE, TRUE);
}
/*
@@ -2485,7 +2358,8 @@ rb_mod_remove_const(VALUE mod, VALUE name)
const ID id = id_for_var(mod, name, a, constant);
if (!id) {
- undefined_constant(mod, name);
+ rb_name_err_raise("constant %2$s::%1$s not defined",
+ mod, name);
}
return rb_const_remove(mod, id);
}
@@ -2503,7 +2377,8 @@ rb_const_remove(VALUE mod, ID id)
rb_name_err_raise("cannot remove %2$s::%1$s",
mod, ID2SYM(id));
}
- undefined_constant(mod, ID2SYM(id));
+ rb_name_err_raise("constant %2$s::%1$s not defined",
+ mod, ID2SYM(id));
}
rb_clear_constant_cache();
@@ -2623,17 +2498,22 @@ rb_const_list(void *data)
* IO.constants.include?(:SYNC) #=> true
* IO.constants(false).include?(:SYNC) #=> false
*
- * Also see Module#const_defined?.
+ * Also see <code>Module::const_defined?</code>.
*/
VALUE
rb_mod_constants(int argc, const VALUE *argv, VALUE mod)
{
- bool inherit = true;
+ VALUE inherit;
- if (rb_check_arity(argc, 0, 1)) inherit = RTEST(argv[0]);
+ if (argc == 0) {
+ inherit = Qtrue;
+ }
+ else {
+ rb_scan_args(argc, argv, "01", &inherit);
+ }
- if (inherit) {
+ if (RTEST(inherit)) {
return rb_const_list(rb_mod_const_of(mod, 0));
}
else {
@@ -2694,62 +2574,28 @@ rb_const_defined_at(VALUE klass, ID id)
return rb_const_defined_0(klass, id, TRUE, FALSE, FALSE);
}
-MJIT_FUNC_EXPORTED int
+int
rb_public_const_defined_from(VALUE klass, ID id)
{
return rb_const_defined_0(klass, id, TRUE, TRUE, TRUE);
}
-static void
-check_before_mod_set(VALUE klass, ID id, VALUE val, const char *dest)
+int
+rb_public_const_defined(VALUE klass, ID id)
{
- rb_check_frozen(klass);
+ return rb_const_defined_0(klass, id, FALSE, TRUE, TRUE);
}
-static void set_namespace_path(VALUE named_namespace, VALUE name);
-
-static enum rb_id_table_iterator_result
-set_namespace_path_i(ID id, VALUE v, void *payload)
+int
+rb_public_const_defined_at(VALUE klass, ID id)
{
- rb_const_entry_t *ce = (rb_const_entry_t *)v;
- VALUE value = ce->value;
- int has_permanent_classpath;
- VALUE parental_path = *((VALUE *) payload);
- if (!rb_is_const_id(id)) {
- return ID_TABLE_CONTINUE;
- }
- if (!rb_namespace_p(value)) {
- return ID_TABLE_CONTINUE;
- }
- classname(value, &has_permanent_classpath);
- if (has_permanent_classpath) {
- return ID_TABLE_CONTINUE;
- }
- set_namespace_path(value, build_const_path(parental_path, id));
- if (RCLASS_IV_TBL(value)) {
- st_data_t tmp = tmp_classpath;
- st_delete(RCLASS_IV_TBL(value), &tmp, 0);
- }
-
- return ID_TABLE_CONTINUE;
+ return rb_const_defined_0(klass, id, TRUE, FALSE, TRUE);
}
-/*
- * Assign permanent classpaths to all namespaces that are directly or indirectly
- * nested under +named_namespace+. +named_namespace+ must have a permanent
- * classpath.
- */
static void
-set_namespace_path(VALUE named_namespace, VALUE namespace_path)
+check_before_mod_set(VALUE klass, ID id, VALUE val, const char *dest)
{
- struct rb_id_table *const_table = RCLASS_CONST_TBL(named_namespace);
- if (!RCLASS_IV_TBL(named_namespace)) {
- RCLASS_IV_TBL(named_namespace) = st_init_numtable();
- }
- rb_class_ivar_set(named_namespace, classpath, namespace_path);
- if (const_table) {
- rb_id_table_foreach(const_table, set_namespace_path_i, &namespace_path);
- }
+ rb_check_frozen(klass);
}
void
@@ -2772,34 +2618,36 @@ rb_const_set(VALUE klass, ID id, VALUE val)
setup_const_entry(ce, klass, val, CONST_PUBLIC);
}
else {
- struct autoload_const ac = {
- .mod = klass, .id = id,
- .value = val, .flag = CONST_PUBLIC,
- /* fill the rest with 0 */
- };
- const_tbl_update(&ac);
+ struct autoload_const_set_args args;
+ args.mod = klass;
+ args.id = id;
+ args.value = val;
+ args.flag = CONST_PUBLIC;
+ const_tbl_update(&args);
}
/*
* Resolve and cache class name immediately to resolve ambiguity
* and avoid order-dependency on const_tbl
*/
- if (rb_cObject && rb_namespace_p(val)) {
- int val_path_permanent;
- VALUE val_path = classname(val, &val_path_permanent);
- if (NIL_P(val_path) || !val_path_permanent) {
+ if (rb_cObject && (RB_TYPE_P(val, T_MODULE) || RB_TYPE_P(val, T_CLASS))) {
+ if (NIL_P(rb_class_path_cached(val))) {
if (klass == rb_cObject) {
- set_namespace_path(val, rb_id2str(id));
+ rb_ivar_set(val, classpath, rb_id2str(id));
+ rb_name_class(val, id);
}
else {
- int parental_path_permanent;
- VALUE parental_path = classname(klass, &parental_path_permanent);
- if (!NIL_P(parental_path)) {
- if (parental_path_permanent && !val_path_permanent) {
- set_namespace_path(val, build_const_path(parental_path, id));
- }
- else if (!parental_path_permanent && NIL_P(val_path)) {
- rb_ivar_set(val, tmp_classpath, build_const_path(parental_path, id));
- }
+ VALUE path;
+ ID pathid;
+ st_data_t n;
+ st_table *ivtbl = RCLASS_IV_TBL(klass);
+ if (ivtbl &&
+ (st_lookup(ivtbl, (st_data_t)(pathid = classpath), &n) ||
+ st_lookup(ivtbl, (st_data_t)(pathid = tmp_classpath), &n))) {
+ path = rb_str_dup((VALUE)n);
+ rb_str_append(rb_str_cat2(path, "::"), rb_id2str(id));
+ OBJ_FREEZE(path);
+ rb_ivar_set(val, pathid, path);
+ rb_name_class(val, id);
}
}
}
@@ -2807,12 +2655,12 @@ rb_const_set(VALUE klass, ID id, VALUE val)
}
static struct autoload_data_i *
-current_autoload_data(VALUE mod, ID id, struct autoload_const **acp)
+current_autoload_data(VALUE mod, ID id)
{
struct autoload_data_i *ele;
VALUE load = autoload_data(mod, id);
if (!load) return 0;
- ele = get_autoload_data(load, acp);
+ ele = get_autoload_data(load);
if (!ele) return 0;
/* for autoloading thread, keep the defined value to autoloading storage */
if (ele->state && (ele->state->thread == rb_thread_current())) {
@@ -2822,36 +2670,29 @@ current_autoload_data(VALUE mod, ID id, struct autoload_const **acp)
}
static void
-const_tbl_update(struct autoload_const *ac)
+const_tbl_update(struct autoload_const_set_args *args)
{
VALUE value;
- VALUE klass = ac->mod;
- VALUE val = ac->value;
- ID id = ac->id;
+ VALUE klass = args->mod;
+ VALUE val = args->value;
+ ID id = args->id;
struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
- rb_const_flag_t visibility = ac->flag;
+ rb_const_flag_t visibility = args->flag;
rb_const_entry_t *ce;
if (rb_id_table_lookup(tbl, id, &value)) {
ce = (rb_const_entry_t *)value;
if (ce->value == Qundef) {
- struct autoload_data_i *ele = current_autoload_data(klass, id, &ac);
+ struct autoload_data_i *ele = current_autoload_data(klass, id);
if (ele) {
rb_clear_constant_cache();
- ac->value = val; /* autoload_i is non-WB-protected */
- ac->file = rb_source_location(&ac->line);
+ ele->value = val; /* autoload_i is non-WB-protected */
+ return;
}
- else {
- /* otherwise autoloaded constant, allow to override */
- autoload_delete(klass, id);
- ce->flag = visibility;
- RB_OBJ_WRITE(klass, &ce->value, val);
- RB_OBJ_WRITE(klass, &ce->file, ac->file);
- ce->line = ac->line;
- }
- return;
+ /* otherwise, allow to override */
+ autoload_delete(klass, id);
}
else {
VALUE name = QUOTE_ID(id);
@@ -2895,7 +2736,6 @@ rb_define_const(VALUE klass, const char *name, VALUE val)
if (!rb_is_const_id(id)) {
rb_warn("rb_define_const: invalid name `%s' for constant", name);
}
- rb_gc_register_mark_object(val);
rb_const_set(klass, id, val);
}
@@ -2913,7 +2753,7 @@ set_const_visibility(VALUE mod, int argc, const VALUE *argv,
rb_const_entry_t *ce;
ID id;
- rb_class_modify_check(mod);
+ rb_frozen_class_p(mod);
if (argc == 0) {
rb_warning("%"PRIsVALUE" with no argument is just ignored",
QUOTE_ID(rb_frame_callee()));
@@ -2921,7 +2761,6 @@ set_const_visibility(VALUE mod, int argc, const VALUE *argv,
}
for (i = 0; i < argc; i++) {
- struct autoload_const *ac;
VALUE val = argv[i];
id = rb_check_id(&val);
if (!id) {
@@ -2929,18 +2768,17 @@ set_const_visibility(VALUE mod, int argc, const VALUE *argv,
rb_clear_constant_cache();
}
- undefined_constant(mod, val);
+ rb_name_err_raise("constant %2$s::%1$s not defined",
+ mod, val);
}
if ((ce = rb_const_lookup(mod, id))) {
ce->flag &= ~mask;
ce->flag |= flag;
if (ce->value == Qundef) {
- struct autoload_data_i *ele;
-
- ele = current_autoload_data(mod, id, &ac);
+ struct autoload_data_i *ele = current_autoload_data(mod, id);
if (ele) {
- ac->flag &= ~mask;
- ac->flag |= flag;
+ ele->flag &= ~mask;
+ ele->flag |= flag;
}
}
}
@@ -2948,7 +2786,8 @@ set_const_visibility(VALUE mod, int argc, const VALUE *argv,
if (i > 0) {
rb_clear_constant_cache();
}
- undefined_constant(mod, ID2SYM(id));
+ rb_name_err_raise("constant %2$s::%1$s not defined",
+ mod, ID2SYM(id));
}
}
rb_clear_constant_cache();
@@ -2961,12 +2800,11 @@ rb_deprecate_constant(VALUE mod, const char *name)
ID id;
long len = strlen(name);
- rb_class_modify_check(mod);
- if (!(id = rb_check_id_cstr(name, len, NULL))) {
- undefined_constant(mod, rb_fstring_new(name, len));
- }
- if (!(ce = rb_const_lookup(mod, id))) {
- undefined_constant(mod, ID2SYM(id));
+ rb_frozen_class_p(mod);
+ if (!(id = rb_check_id_cstr(name, len, NULL)) ||
+ !(ce = rb_const_lookup(mod, id))) {
+ rb_name_err_raise("constant %2$s::%1$s not defined",
+ mod, rb_fstring_new(name, len));
}
ce->flag |= CONST_DEPRECATED;
}
@@ -3003,19 +2841,7 @@ rb_mod_public_constant(int argc, const VALUE *argv, VALUE obj)
* call-seq:
* mod.deprecate_constant(symbol, ...) => mod
*
- * Makes a list of existing constants deprecated. Attempt
- * to refer to them will produce a warning.
- *
- * module HTTP
- * NotFound = Exception.new
- * NOT_FOUND = NotFound # previous version of the library used this name
- *
- * deprecate_constant :NOT_FOUND
- * end
- *
- * HTTP::NOT_FOUND
- * # warning: constant HTTP::NOT_FOUND is deprecated
- *
+ * Makes a list of existing constants deprecated.
*/
VALUE
@@ -3045,30 +2871,13 @@ cvar_front_klass(VALUE klass)
{
if (FL_TEST(klass, FL_SINGLETON)) {
VALUE obj = rb_ivar_get(klass, id__attached__);
- if (rb_namespace_p(obj)) {
+ if (RB_TYPE_P(obj, T_MODULE) || RB_TYPE_P(obj, T_CLASS)) {
return obj;
}
}
return RCLASS_SUPER(klass);
}
-static void
-cvar_overtaken(VALUE front, VALUE target, ID id)
-{
- if (front && target != front) {
- st_data_t did = (st_data_t)id;
-
- if (RTEST(ruby_verbose) && original_module(front) != original_module(target)) {
- rb_warning("class variable % "PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",
- ID2SYM(id), rb_class_name(original_module(front)),
- rb_class_name(original_module(target)));
- }
- if (BUILTIN_TYPE(front) == T_CLASS) {
- st_delete(RCLASS_IV_TBL(front), &did, 0);
- }
- }
-}
-
#define CVAR_FOREACH_ANCESTORS(klass, v, r) \
for (klass = cvar_front_klass(klass); klass; klass = RCLASS_SUPER(klass)) { \
if (cvar_lookup_at(klass, id, (v))) { \
@@ -3089,7 +2898,18 @@ rb_cvar_set(VALUE klass, ID id, VALUE val)
tmp = klass;
CVAR_LOOKUP(0, {if (!front) front = klass; target = klass;});
if (target) {
- cvar_overtaken(front, target, id);
+ if (front && target != front) {
+ st_data_t did = id;
+
+ if (RTEST(ruby_verbose)) {
+ rb_warning("class variable %"PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",
+ QUOTE_ID(id), rb_class_name(original_module(front)),
+ rb_class_name(original_module(target)));
+ }
+ if (BUILTIN_TYPE(front) == T_CLASS) {
+ st_delete(RCLASS_IV_TBL(front),&did,0);
+ }
+ }
}
else {
target = tmp;
@@ -3115,7 +2935,18 @@ rb_cvar_get(VALUE klass, ID id)
rb_name_err_raise("uninitialized class variable %1$s in %2$s",
tmp, ID2SYM(id));
}
- cvar_overtaken(front, target, id);
+ if (front && target != front) {
+ st_data_t did = id;
+
+ if (RTEST(ruby_verbose)) {
+ rb_warning("class variable %"PRIsVALUE" of %"PRIsVALUE" is overtaken by %"PRIsVALUE"",
+ QUOTE_ID(id), rb_class_name(original_module(front)),
+ rb_class_name(original_module(target)));
+ }
+ if (BUILTIN_TYPE(front) == T_CLASS) {
+ st_delete(RCLASS_IV_TBL(front),&did,0);
+ }
+ }
return (VALUE)value;
}
@@ -3188,12 +3019,6 @@ static void*
mod_cvar_of(VALUE mod, void *data)
{
VALUE tmp = mod;
- if (FL_TEST(mod, FL_SINGLETON)) {
- if (rb_namespace_p(rb_ivar_get(mod, id__attached__))) {
- data = mod_cvar_at(tmp, data);
- tmp = cvar_front_klass(tmp);
- }
- }
for (;;) {
data = mod_cvar_at(tmp, data);
tmp = RCLASS_SUPER(tmp);
@@ -3247,11 +3072,16 @@ cvar_list(void *data)
VALUE
rb_mod_class_variables(int argc, const VALUE *argv, VALUE mod)
{
- bool inherit = true;
+ VALUE inherit;
st_table *tbl;
- if (rb_check_arity(argc, 0, 1)) inherit = RTEST(argv[0]);
- if (inherit) {
+ if (argc == 0) {
+ inherit = Qtrue;
+ }
+ else {
+ rb_scan_args(argc, argv, "01", &inherit);
+ }
+ if (RTEST(inherit)) {
tbl = mod_cvar_of(mod, 0);
}
else {
@@ -3304,13 +3134,8 @@ rb_mod_remove_cvar(VALUE mod, VALUE name)
VALUE
rb_iv_get(VALUE obj, const char *name)
{
- ID id = rb_check_id_cstr(name, strlen(name), rb_usascii_encoding());
+ ID id = rb_intern(name);
- if (!id) {
- if (RTEST(ruby_verbose))
- rb_warning("instance variable %s not initialized", name);
- return Qnil;
- }
return rb_ivar_get(obj, id);
}
@@ -3339,16 +3164,15 @@ tbl_copy_i(st_data_t key, st_data_t value, st_data_t data)
return ST_CONTINUE;
}
-void
-rb_iv_tbl_copy(VALUE dst, VALUE src)
+st_table *
+rb_st_copy(VALUE obj, struct st_table *orig_tbl)
{
- st_table *orig_tbl = RCLASS_IV_TBL(src);
st_table *new_tbl = st_copy(orig_tbl);
- st_foreach(new_tbl, tbl_copy_i, (st_data_t)dst);
- RCLASS_IV_TBL(dst) = new_tbl;
+ st_foreach(new_tbl, tbl_copy_i, (st_data_t)obj);
+ return new_tbl;
}
-MJIT_FUNC_EXPORTED rb_const_entry_t *
+rb_const_entry_t *
rb_const_lookup(VALUE klass, ID id)
{
struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);