Eagerly name modules and classes
* variable.c: make the hidden ivars `classpath` and `tmp_classpath` the source of truth for module and constant names. Assign to them when modules are bind to constants. * variable.c: remove references to module name cache, as what used to be the cache is now the source of truth. Remove rb_class_path_no_cache(). * variable.c: remove the hidden ivar `classid`. This existed for the purposes of module name search, which is now replaced. Also, remove the associated rb_name_class(). * class.c: use rb_set_class_path_string to set the name of Object during boot. Must use a fstring as this runs before rb_cString is initialized and creating a normal string leads to a VALUE without a class. * spec/ruby/core/module/name_spec.rb: add a few specs to specify what happens to Module#name across multiple operations. These specs pass without other code changes in this commit. [Feature #15765]
This commit is contained in:
parent
a829be209f
commit
b00f280d4b
5
class.c
5
class.c
@ -537,7 +537,6 @@ boot_defclass(const char *name, VALUE super)
|
|||||||
VALUE obj = rb_class_boot(super);
|
VALUE obj = rb_class_boot(super);
|
||||||
ID id = rb_intern(name);
|
ID id = rb_intern(name);
|
||||||
|
|
||||||
rb_name_class(obj, id);
|
|
||||||
rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
|
rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
|
||||||
rb_vm_add_root_module(id, obj);
|
rb_vm_add_root_module(id, obj);
|
||||||
return obj;
|
return obj;
|
||||||
@ -551,7 +550,7 @@ Init_class_hierarchy(void)
|
|||||||
rb_gc_register_mark_object(rb_cObject);
|
rb_gc_register_mark_object(rb_cObject);
|
||||||
|
|
||||||
/* resolve class name ASAP for order-independence */
|
/* resolve class name ASAP for order-independence */
|
||||||
rb_class_name(rb_cObject);
|
rb_set_class_path_string(rb_cObject, rb_cObject, rb_fstring_lit("Object"));
|
||||||
|
|
||||||
rb_cModule = boot_defclass("Module", rb_cObject);
|
rb_cModule = boot_defclass("Module", rb_cObject);
|
||||||
rb_cClass = boot_defclass("Class", rb_cModule);
|
rb_cClass = boot_defclass("Class", rb_cModule);
|
||||||
@ -669,7 +668,6 @@ rb_define_class(const char *name, VALUE super)
|
|||||||
}
|
}
|
||||||
klass = rb_define_class_id(id, super);
|
klass = rb_define_class_id(id, super);
|
||||||
rb_vm_add_root_module(id, klass);
|
rb_vm_add_root_module(id, klass);
|
||||||
rb_name_class(klass, id);
|
|
||||||
rb_const_set(rb_cObject, id, klass);
|
rb_const_set(rb_cObject, id, klass);
|
||||||
rb_class_inherited(super, klass);
|
rb_class_inherited(super, klass);
|
||||||
|
|
||||||
@ -767,7 +765,6 @@ rb_define_module_id(ID id)
|
|||||||
VALUE mdl;
|
VALUE mdl;
|
||||||
|
|
||||||
mdl = rb_module_new();
|
mdl = rb_module_new();
|
||||||
rb_name_class(mdl, id);
|
|
||||||
|
|
||||||
return mdl;
|
return mdl;
|
||||||
}
|
}
|
||||||
|
6
gc.c
6
gc.c
@ -11097,7 +11097,7 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (RTEST(RBASIC(obj)->klass)) {
|
if (RTEST(RBASIC(obj)->klass)) {
|
||||||
VALUE class_path = rb_class_path_cached(RBASIC(obj)->klass);
|
VALUE class_path = rb_class_path(RBASIC(obj)->klass);
|
||||||
if (!NIL_P(class_path)) {
|
if (!NIL_P(class_path)) {
|
||||||
APPENDF((BUFF_ARGS, "(%s)", RSTRING_PTR(class_path)));
|
APPENDF((BUFF_ARGS, "(%s)", RSTRING_PTR(class_path)));
|
||||||
}
|
}
|
||||||
@ -11151,7 +11151,7 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
|
|||||||
case T_CLASS:
|
case T_CLASS:
|
||||||
case T_MODULE:
|
case T_MODULE:
|
||||||
{
|
{
|
||||||
VALUE class_path = rb_class_path_cached(obj);
|
VALUE class_path = rb_class_path(obj);
|
||||||
if (!NIL_P(class_path)) {
|
if (!NIL_P(class_path)) {
|
||||||
APPENDF((BUFF_ARGS, "%s", RSTRING_PTR(class_path)));
|
APPENDF((BUFF_ARGS, "%s", RSTRING_PTR(class_path)));
|
||||||
}
|
}
|
||||||
@ -11159,7 +11159,7 @@ rb_raw_obj_info(char *buff, const int buff_size, VALUE obj)
|
|||||||
}
|
}
|
||||||
case T_ICLASS:
|
case T_ICLASS:
|
||||||
{
|
{
|
||||||
VALUE class_path = rb_class_path_cached(RBASIC_CLASS(obj));
|
VALUE class_path = rb_class_path(RBASIC_CLASS(obj));
|
||||||
if (!NIL_P(class_path)) {
|
if (!NIL_P(class_path)) {
|
||||||
APPENDF((BUFF_ARGS, "src:%s", RSTRING_PTR(class_path)));
|
APPENDF((BUFF_ARGS, "src:%s", RSTRING_PTR(class_path)));
|
||||||
}
|
}
|
||||||
|
@ -949,7 +949,6 @@ void rb_set_class_path(VALUE, VALUE, const char*);
|
|||||||
void rb_set_class_path_string(VALUE, VALUE, VALUE);
|
void rb_set_class_path_string(VALUE, VALUE, VALUE);
|
||||||
VALUE rb_path_to_class(VALUE);
|
VALUE rb_path_to_class(VALUE);
|
||||||
VALUE rb_path2class(const char*);
|
VALUE rb_path2class(const char*);
|
||||||
void rb_name_class(VALUE, ID);
|
|
||||||
VALUE rb_class_name(VALUE);
|
VALUE rb_class_name(VALUE);
|
||||||
VALUE rb_autoload_load(VALUE, ID);
|
VALUE rb_autoload_load(VALUE, ID);
|
||||||
VALUE rb_autoload_p(VALUE, ID);
|
VALUE rb_autoload_p(VALUE, ID);
|
||||||
|
@ -18,6 +18,33 @@ describe "Module#name" do
|
|||||||
m::N.name.should =~ /#<Module:0x[0-9a-f]+>::N/
|
m::N.name.should =~ /#<Module:0x[0-9a-f]+>::N/
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "changes when the module is reachable through a constant path" do
|
||||||
|
m = Module.new
|
||||||
|
module m::N; end
|
||||||
|
m::N.name.should =~ /#<Module:0x[0-9a-f]+>::N/
|
||||||
|
ModuleSpecs::Anonymous::WasAnnon = m::N
|
||||||
|
m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon"
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is set after it is removed from a constant" do
|
||||||
|
module ModuleSpecs
|
||||||
|
module ModuleToRemove
|
||||||
|
end
|
||||||
|
|
||||||
|
mod = ModuleToRemove
|
||||||
|
remove_const(:ModuleToRemove)
|
||||||
|
mod.name.should == "ModuleSpecs::ModuleToRemove"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
it "is set after it is removed from a constant under an anonymous module" do
|
||||||
|
m = Module.new
|
||||||
|
module m::Child; end
|
||||||
|
child = m::Child
|
||||||
|
m.send(:remove_const, :Child)
|
||||||
|
child.name.should =~ /#<Module:0x[0-9a-f]+>::Child/
|
||||||
|
end
|
||||||
|
|
||||||
it "is set when opened with the module keyword" do
|
it "is set when opened with the module keyword" do
|
||||||
ModuleSpecs.name.should == "ModuleSpecs"
|
ModuleSpecs.name.should == "ModuleSpecs"
|
||||||
end
|
end
|
||||||
@ -40,6 +67,15 @@ describe "Module#name" do
|
|||||||
m.name.should == "ModuleSpecs::Anonymous::B"
|
m.name.should == "ModuleSpecs::Anonymous::B"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
it "is not modified when assigned to a different anonymous module" do
|
||||||
|
m = Module.new
|
||||||
|
module m::M; end
|
||||||
|
first_name = m::M.name.dup
|
||||||
|
module m::N; end
|
||||||
|
m::N::F = m::M
|
||||||
|
m::M.name.should == first_name
|
||||||
|
end
|
||||||
|
|
||||||
# http://bugs.ruby-lang.org/issues/6067
|
# http://bugs.ruby-lang.org/issues/6067
|
||||||
it "is set with a conditional assignment to a nested constant" do
|
it "is set with a conditional assignment to a nested constant" do
|
||||||
eval("ModuleSpecs::Anonymous::F ||= Module.new")
|
eval("ModuleSpecs::Anonymous::F ||= Module.new")
|
||||||
|
320
variable.c
320
variable.c
@ -25,7 +25,7 @@
|
|||||||
#include "transient_heap.h"
|
#include "transient_heap.h"
|
||||||
|
|
||||||
static struct rb_id_table *rb_global_tbl;
|
static struct rb_id_table *rb_global_tbl;
|
||||||
static ID autoload, classpath, tmp_classpath, classid;
|
static ID autoload, classpath, tmp_classpath;
|
||||||
static VALUE autoload_featuremap; /* feature => autoload_i */
|
static VALUE autoload_featuremap; /* feature => autoload_i */
|
||||||
|
|
||||||
static void check_before_mod_set(VALUE, ID, VALUE, const char *);
|
static void check_before_mod_set(VALUE, ID, VALUE, const char *);
|
||||||
@ -59,8 +59,6 @@ Init_var_tables(void)
|
|||||||
classpath = rb_intern_const("__classpath__");
|
classpath = rb_intern_const("__classpath__");
|
||||||
/* __tmp_classpath__: temporary class path which contains anonymous names */
|
/* __tmp_classpath__: temporary class path which contains anonymous names */
|
||||||
tmp_classpath = rb_intern_const("__tmp_classpath__");
|
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
|
static inline bool
|
||||||
@ -73,163 +71,29 @@ rb_namespace_p(VALUE obj)
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
|
||||||
{
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
if (rb_namespace_p(value)) {
|
|
||||||
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
|
* Returns +classpath+ of _klass_, if it is named, or +nil+ for
|
||||||
* anonymous +class+/+module+. The last part of named +classpath+ is
|
* anonymous +class+/+module+. A named +classpath+ may contain
|
||||||
* never anonymous, but anonymous +class+/+module+ names may be
|
* an anonymous component, but the last component is guaranteed
|
||||||
* contained. If the path is "permanent", that means it has no
|
* to not be anonymous. <code>*permanent</code> is set to 1
|
||||||
* anonymous names, <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+.
|
||||||
*/
|
*/
|
||||||
static VALUE
|
static VALUE
|
||||||
classname(VALUE klass, int *permanent)
|
classname(VALUE klass, int *permanent)
|
||||||
{
|
{
|
||||||
VALUE path = Qnil;
|
st_table *ivtbl;
|
||||||
st_data_t n;
|
st_data_t 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;
|
*permanent = 0;
|
||||||
path = (VALUE)n;
|
if (!RCLASS_EXT(klass)) return Qnil;
|
||||||
return path;
|
if (!(ivtbl = RCLASS_IV_TBL(klass))) return Qnil;
|
||||||
|
if (st_lookup(ivtbl, (st_data_t)classpath, &n)) {
|
||||||
|
*permanent = 1;
|
||||||
|
return (VALUE)n;
|
||||||
}
|
}
|
||||||
}
|
if (st_lookup(ivtbl, (st_data_t)tmp_classpath, &n)) return (VALUE)n;
|
||||||
else {
|
return Qnil;
|
||||||
path = (VALUE)n;
|
|
||||||
}
|
|
||||||
if (!RB_TYPE_P(path, T_STRING)) {
|
|
||||||
rb_bug("class path is not set properly");
|
|
||||||
}
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
return find_class_path(klass, (ID)0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -268,22 +132,16 @@ make_temporary_path(VALUE obj, VALUE klass)
|
|||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef VALUE (*path_cache_func)(VALUE obj, VALUE name);
|
typedef VALUE (*fallback_func)(VALUE obj, VALUE name);
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_tmp_class_path(VALUE klass, int *permanent, path_cache_func cache_path)
|
rb_tmp_class_path(VALUE klass, int *permanent, fallback_func fallback)
|
||||||
{
|
{
|
||||||
VALUE path = classname(klass, permanent);
|
VALUE path = classname(klass, permanent);
|
||||||
st_data_t n = (st_data_t)path;
|
|
||||||
|
|
||||||
if (!NIL_P(path)) {
|
if (!NIL_P(path)) {
|
||||||
return 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 {
|
else {
|
||||||
if (RB_TYPE_P(klass, T_MODULE)) {
|
if (RB_TYPE_P(klass, T_MODULE)) {
|
||||||
if (rb_obj_class(klass) == rb_cModule) {
|
if (rb_obj_class(klass) == rb_cModule) {
|
||||||
@ -291,40 +149,19 @@ rb_tmp_class_path(VALUE klass, int *permanent, path_cache_func cache_path)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int perm;
|
int perm;
|
||||||
path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, cache_path);
|
path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, fallback);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*permanent = 0;
|
*permanent = 0;
|
||||||
return cache_path(klass, path);
|
return fallback(klass, path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
|
||||||
ivar_cache(VALUE obj, VALUE name)
|
|
||||||
{
|
|
||||||
return rb_ivar_set(obj, tmp_classpath, make_temporary_path(obj, name));
|
|
||||||
}
|
|
||||||
|
|
||||||
VALUE
|
VALUE
|
||||||
rb_class_path(VALUE klass)
|
rb_class_path(VALUE klass)
|
||||||
{
|
{
|
||||||
int permanent;
|
int permanent;
|
||||||
VALUE path = rb_tmp_class_path(klass, &permanent, ivar_cache);
|
VALUE path = rb_tmp_class_path(klass, &permanent, make_temporary_path);
|
||||||
if (!NIL_P(path)) path = rb_str_dup(path);
|
|
||||||
return path;
|
|
||||||
}
|
|
||||||
|
|
||||||
static VALUE
|
|
||||||
null_cache(VALUE obj, VALUE name)
|
|
||||||
{
|
|
||||||
return make_temporary_path(obj, name);
|
|
||||||
}
|
|
||||||
|
|
||||||
VALUE
|
|
||||||
rb_class_path_no_cache(VALUE klass)
|
|
||||||
{
|
|
||||||
int permanent;
|
|
||||||
VALUE path = rb_tmp_class_path(klass, &permanent, null_cache);
|
|
||||||
if (!NIL_P(path)) path = rb_str_dup(path);
|
if (!NIL_P(path)) path = rb_str_dup(path);
|
||||||
return path;
|
return path;
|
||||||
}
|
}
|
||||||
@ -332,18 +169,12 @@ rb_class_path_no_cache(VALUE klass)
|
|||||||
VALUE
|
VALUE
|
||||||
rb_class_path_cached(VALUE klass)
|
rb_class_path_cached(VALUE klass)
|
||||||
{
|
{
|
||||||
st_table *ivtbl;
|
int permanent;
|
||||||
st_data_t n;
|
return classname(klass, &permanent);
|
||||||
|
|
||||||
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
|
static VALUE
|
||||||
never_cache(VALUE obj, VALUE name)
|
no_fallback(VALUE obj, VALUE name)
|
||||||
{
|
{
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
@ -352,7 +183,13 @@ VALUE
|
|||||||
rb_search_class_path(VALUE klass)
|
rb_search_class_path(VALUE klass)
|
||||||
{
|
{
|
||||||
int permanent;
|
int permanent;
|
||||||
return rb_tmp_class_path(klass, &permanent, never_cache);
|
return rb_tmp_class_path(klass, &permanent, no_fallback);
|
||||||
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
save_temporary_path(VALUE obj, VALUE name)
|
||||||
|
{
|
||||||
|
return rb_ivar_set(obj, tmp_classpath, make_temporary_path(obj, name));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -366,13 +203,12 @@ rb_set_class_path_string(VALUE klass, VALUE under, VALUE name)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int permanent;
|
int permanent;
|
||||||
str = rb_str_dup(rb_tmp_class_path(under, &permanent, ivar_cache));
|
str = rb_str_dup(rb_tmp_class_path(under, &permanent, save_temporary_path));
|
||||||
rb_str_cat2(str, "::");
|
rb_str_cat2(str, "::");
|
||||||
rb_str_append(str, name);
|
rb_str_append(str, name);
|
||||||
OBJ_FREEZE(str);
|
OBJ_FREEZE(str);
|
||||||
if (!permanent) {
|
if (!permanent) {
|
||||||
pathid = tmp_classpath;
|
pathid = tmp_classpath;
|
||||||
rb_ivar_set(klass, classid, rb_str_intern(name));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
rb_ivar_set(klass, pathid, str);
|
rb_ivar_set(klass, pathid, str);
|
||||||
@ -389,12 +225,11 @@ rb_set_class_path(VALUE klass, VALUE under, const char *name)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int permanent;
|
int permanent;
|
||||||
str = rb_str_dup(rb_tmp_class_path(under, &permanent, ivar_cache));
|
str = rb_str_dup(rb_tmp_class_path(under, &permanent, save_temporary_path));
|
||||||
rb_str_cat2(str, "::");
|
rb_str_cat2(str, "::");
|
||||||
rb_str_cat2(str, name);
|
rb_str_cat2(str, name);
|
||||||
if (!permanent) {
|
if (!permanent) {
|
||||||
pathid = tmp_classpath;
|
pathid = tmp_classpath;
|
||||||
rb_ivar_set(klass, classid, rb_str_intern(rb_str_new_cstr(name)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
OBJ_FREEZE(str);
|
OBJ_FREEZE(str);
|
||||||
@ -449,12 +284,6 @@ rb_path2class(const char *path)
|
|||||||
return rb_path_to_class(rb_str_new_cstr(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
|
VALUE
|
||||||
rb_class_name(VALUE klass)
|
rb_class_name(VALUE klass)
|
||||||
{
|
{
|
||||||
@ -465,7 +294,7 @@ const char *
|
|||||||
rb_class2name(VALUE klass)
|
rb_class2name(VALUE klass)
|
||||||
{
|
{
|
||||||
int permanent;
|
int permanent;
|
||||||
VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, ivar_cache);
|
VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, make_temporary_path);
|
||||||
if (NIL_P(path)) return NULL;
|
if (NIL_P(path)) return NULL;
|
||||||
return RSTRING_PTR(path);
|
return RSTRING_PTR(path);
|
||||||
}
|
}
|
||||||
@ -2853,6 +2682,64 @@ check_before_mod_set(VALUE klass, ID id, VALUE val, const char *dest)
|
|||||||
rb_check_frozen(klass);
|
rb_check_frozen(klass);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static VALUE
|
||||||
|
build_const_path(VALUE head, ID tail)
|
||||||
|
{
|
||||||
|
VALUE path = rb_str_dup(head);
|
||||||
|
rb_str_cat2(path, "::");
|
||||||
|
rb_str_append(path, rb_id2str(tail));
|
||||||
|
OBJ_FREEZE(path);
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void finalize_classpath_for_children(VALUE named_namespace);
|
||||||
|
|
||||||
|
static enum rb_id_table_iterator_result
|
||||||
|
finalize_classpath_i(ID id, VALUE v, void *payload)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
rb_ivar_set(value, classpath, 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);
|
||||||
|
}
|
||||||
|
finalize_classpath_for_children(value);
|
||||||
|
|
||||||
|
return ID_TABLE_CONTINUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Assign permanent classpaths to all namespaces that are directly or indirectly
|
||||||
|
* nested under +named_namespace+. +named_namespace+ must have a permanent
|
||||||
|
* classpath.
|
||||||
|
*/
|
||||||
|
static void
|
||||||
|
finalize_classpath_for_children(VALUE named_namespace)
|
||||||
|
{
|
||||||
|
struct rb_id_table *const_table = RCLASS_CONST_TBL(named_namespace);
|
||||||
|
|
||||||
|
if (const_table) {
|
||||||
|
int permanent;
|
||||||
|
VALUE parental_path = classname(named_namespace, &permanent);
|
||||||
|
VM_ASSERT(RB_TYPE_P(parental_path, T_STRING));
|
||||||
|
VM_ASSERT(permanent);
|
||||||
|
rb_id_table_foreach(const_table, finalize_classpath_i, &parental_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
rb_const_set(VALUE klass, ID id, VALUE val)
|
rb_const_set(VALUE klass, ID id, VALUE val)
|
||||||
{
|
{
|
||||||
@ -2885,24 +2772,23 @@ rb_const_set(VALUE klass, ID id, VALUE val)
|
|||||||
* and avoid order-dependency on const_tbl
|
* and avoid order-dependency on const_tbl
|
||||||
*/
|
*/
|
||||||
if (rb_cObject && rb_namespace_p(val)) {
|
if (rb_cObject && rb_namespace_p(val)) {
|
||||||
if (NIL_P(rb_class_path_cached(val))) {
|
int val_path_permanent;
|
||||||
|
VALUE val_path = classname(val, &val_path_permanent);
|
||||||
|
if (NIL_P(val_path) || !val_path_permanent) {
|
||||||
if (klass == rb_cObject) {
|
if (klass == rb_cObject) {
|
||||||
rb_ivar_set(val, classpath, rb_id2str(id));
|
rb_ivar_set(val, classpath, rb_id2str(id));
|
||||||
rb_name_class(val, id);
|
finalize_classpath_for_children(val);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VALUE path;
|
int parental_path_permanent;
|
||||||
ID pathid;
|
VALUE parental_path = classname(klass, &parental_path_permanent);
|
||||||
st_data_t n;
|
if (!NIL_P(parental_path)) {
|
||||||
st_table *ivtbl = RCLASS_IV_TBL(klass);
|
if (parental_path_permanent && !val_path_permanent) {
|
||||||
if (ivtbl &&
|
rb_ivar_set(val, classpath, build_const_path(parental_path, id));
|
||||||
(st_lookup(ivtbl, (st_data_t)(pathid = classpath), &n) ||
|
finalize_classpath_for_children(val);
|
||||||
st_lookup(ivtbl, (st_data_t)(pathid = tmp_classpath), &n))) {
|
} else if (!parental_path_permanent && NIL_P(val_path)) {
|
||||||
path = rb_str_dup((VALUE)n);
|
rb_ivar_set(val, tmp_classpath, build_const_path(parental_path, id));
|
||||||
rb_str_append(rb_str_cat2(path, "::"), rb_id2str(id));
|
}
|
||||||
OBJ_FREEZE(path);
|
|
||||||
rb_ivar_set(val, pathid, path);
|
|
||||||
rb_name_class(val, id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
4
vm.c
4
vm.c
@ -374,8 +374,6 @@ rb_vm_inc_const_missing_count(void)
|
|||||||
ruby_vm_const_missing_count +=1;
|
ruby_vm_const_missing_count +=1;
|
||||||
}
|
}
|
||||||
|
|
||||||
VALUE rb_class_path_no_cache(VALUE _klass);
|
|
||||||
|
|
||||||
MJIT_FUNC_EXPORTED int
|
MJIT_FUNC_EXPORTED int
|
||||||
rb_dtrace_setup(rb_execution_context_t *ec, VALUE klass, ID id,
|
rb_dtrace_setup(rb_execution_context_t *ec, VALUE klass, ID id,
|
||||||
struct ruby_dtrace_method_hook_args *args)
|
struct ruby_dtrace_method_hook_args *args)
|
||||||
@ -395,7 +393,7 @@ rb_dtrace_setup(rb_execution_context_t *ec, VALUE klass, ID id,
|
|||||||
}
|
}
|
||||||
type = BUILTIN_TYPE(klass);
|
type = BUILTIN_TYPE(klass);
|
||||||
if (type == T_CLASS || type == T_ICLASS || type == T_MODULE) {
|
if (type == T_CLASS || type == T_ICLASS || type == T_MODULE) {
|
||||||
VALUE name = rb_class_path_no_cache(klass);
|
VALUE name = rb_class_path(klass);
|
||||||
const char *classname, *filename;
|
const char *classname, *filename;
|
||||||
const char *methodname = rb_id2name(id);
|
const char *methodname = rb_id2name(id);
|
||||||
if (methodname && (filename = rb_source_location_cstr(&args->line_no)) != 0) {
|
if (methodname && (filename = rb_source_location_cstr(&args->line_no)) != 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user