Project

General

Profile

Feature #15765 ยป 0001-Eagerly-name-modules-and-classes.patch

alanwu (Alan Wu), 04/12/2019 04:09 AM

View differences:

class.c
537 537
    VALUE obj = rb_class_boot(super);
538 538
    ID id = rb_intern(name);
539 539

  
540
    rb_name_class(obj, id);
541 540
    rb_const_set((rb_cObject ? rb_cObject : obj), id, obj);
542 541
    return obj;
543 542
}
......
550 549
    rb_gc_register_mark_object(rb_cObject);
551 550

  
552 551
    /* resolve class name ASAP for order-independence */
553
    rb_class_name(rb_cObject);
552
    rb_set_class_path_string(rb_cObject, rb_cObject, rb_fstring_lit("Object"));
554 553

  
555 554
    rb_cModule = boot_defclass("Module", rb_cObject);
556 555
    rb_cClass =  boot_defclass("Class",  rb_cModule);
......
665 664
    }
666 665
    klass = rb_define_class_id(id, super);
667 666
    rb_vm_add_root_module(id, klass);
668
    rb_name_class(klass, id);
669 667
    rb_const_set(rb_cObject, id, klass);
670 668
    rb_class_inherited(super, klass);
671 669

  
......
759 757
    VALUE mdl;
760 758

  
761 759
    mdl = rb_module_new();
762
    rb_name_class(mdl, id);
763 760

  
764 761
    return mdl;
765 762
}
gc.c
9738 9738
	    snprintf(buff, buff_size, "%s (temporary internal)", buff);
9739 9739
	}
9740 9740
	else {
9741
	    VALUE class_path = rb_class_path_cached(RBASIC(obj)->klass);
9741
	    VALUE class_path = rb_class_path(RBASIC(obj)->klass);
9742 9742
	    if (!NIL_P(class_path)) {
9743 9743
		snprintf(buff, buff_size, "%s (%s)", buff, RSTRING_PTR(class_path));
9744 9744
	    }
......
9787 9787
          case T_CLASS:
9788 9788
          case T_MODULE:
9789 9789
            {
9790
                VALUE class_path = rb_class_path_cached(obj);
9790
                VALUE class_path = rb_class_path(obj);
9791 9791
                if (!NIL_P(class_path)) {
9792 9792
                    snprintf(buff, buff_size, "%s %s", buff, RSTRING_PTR(class_path));
9793 9793
                }
......
9795 9795
            }
9796 9796
          case T_ICLASS:
9797 9797
            {
9798
                VALUE class_path = rb_class_path_cached(RBASIC_CLASS(obj));
9798
                VALUE class_path = rb_class_path(RBASIC_CLASS(obj));
9799 9799
                if (!NIL_P(class_path)) {
9800 9800
                    snprintf(buff, buff_size, "%s src:%s", buff, RSTRING_PTR(class_path));
9801 9801
                }
include/ruby/intern.h
942 942
void rb_set_class_path_string(VALUE, VALUE, VALUE);
943 943
VALUE rb_path_to_class(VALUE);
944 944
VALUE rb_path2class(const char*);
945
void rb_name_class(VALUE, ID);
946 945
VALUE rb_class_name(VALUE);
947 946
VALUE rb_autoload_load(VALUE, ID);
948 947
VALUE rb_autoload_p(VALUE, ID);
spec/ruby/core/module/name_spec.rb
18 18
    m::N.name.should =~ /#<Module:0x[0-9a-f]+>::N/
19 19
  end
20 20

  
21
  it "changes when the module is reachable through a constant path" do
22
    m = Module.new
23
    module m::N; end
24
    m::N.name.should =~ /#<Module:0x[0-9a-f]+>::N/
25
    ModuleSpecs::Anonymous::WasAnnon = m::N
26
    m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon"
27
  end
28

  
29
  it "is set after it is removed from a constant" do
30
    module ModuleSpecs
31
      module ModuleToRemove
32
      end
33

  
34
      mod = ModuleToRemove
35
      remove_const(:ModuleToRemove)
36
      mod.name.should == "ModuleSpecs::ModuleToRemove"
37
    end
38
  end
39

  
40
  it "is set after it is removed from a constant under an anonymous module" do
41
    m = Module.new
42
    module m::Child; end
43
    child = m::Child
44
    m.send(:remove_const, :Child)
45
    child.name.should =~ /#<Module:0x[0-9a-f]+>::Child/
46
  end
47

  
21 48
  it "is set when opened with the module keyword" do
22 49
    ModuleSpecs.name.should == "ModuleSpecs"
23 50
  end
......
40 67
    m.name.should == "ModuleSpecs::Anonymous::B"
41 68
  end
42 69

  
70
  it "is not modified when assigned to a different anonymous module" do
71
    m = Module.new
72
    module m::M; end
73
    first_name = m::M.name.dup
74
    module m::N; end
75
    m::N::F = m::M
76
    m::M.name.should == first_name
77
  end
78

  
43 79
  # http://bugs.ruby-lang.org/issues/6067
44 80
  it "is set with a conditional assignment to a nested constant" do
45 81
    eval("ModuleSpecs::Anonymous::F ||= Module.new")
variable.c
25 25
#include "transient_heap.h"
26 26

  
27 27
static struct rb_id_table *rb_global_tbl;
28
static ID autoload, classpath, tmp_classpath, classid;
28
static ID autoload, classpath, tmp_classpath;
29 29
static VALUE autoload_featuremap; /* feature => autoload_i */
30 30

  
31 31
static void check_before_mod_set(VALUE, ID, VALUE, const char *);
......
59 59
    classpath = rb_intern_const("__classpath__");
60 60
    /* __tmp_classpath__: temporary class path which contains anonymous names */
61 61
    tmp_classpath = rb_intern_const("__tmp_classpath__");
62
    /* __classid__: name given to class/module under an anonymous namespace */
63
    classid = rb_intern_const("__classid__");
64 62
}
65 63

  
66 64
static inline bool
......
73 71
    return false;
74 72
}
75 73

  
76
struct fc_result {
77
    ID name, preferred;
78
    VALUE klass;
79
    VALUE path;
80
    VALUE track;
81
    struct fc_result *prev;
82
};
83

  
84
static VALUE
85
fc_path(struct fc_result *fc, ID name)
86
{
87
    VALUE path, tmp;
88

  
89
    path = rb_id2str(name);
90
    while (fc) {
91
	st_data_t n;
92
	if (fc->track == rb_cObject) break;
93
	if (RCLASS_IV_TBL(fc->track) &&
94
	    st_lookup(RCLASS_IV_TBL(fc->track), (st_data_t)classpath, &n)) {
95
	    tmp = rb_str_dup((VALUE)n);
96
	    rb_str_cat2(tmp, "::");
97
	    rb_str_append(tmp, path);
98
	    path = tmp;
99
	    break;
100
	}
101
	tmp = rb_str_dup(rb_id2str(fc->name));
102
	rb_str_cat2(tmp, "::");
103
	rb_str_append(tmp, path);
104
	path = tmp;
105
	fc = fc->prev;
106
    }
107
    OBJ_FREEZE(path);
108
    return path;
109
}
110

  
111
static enum rb_id_table_iterator_result
112
fc_i(ID key, VALUE v, void *a)
113
{
114
    rb_const_entry_t *ce = (rb_const_entry_t *)v;
115
    struct fc_result *res = a;
116
    VALUE value = ce->value;
117
    if (!rb_is_const_id(key)) return ID_TABLE_CONTINUE;
118

  
119
    if (value == res->klass && (!res->preferred || key == res->preferred)) {
120
	res->path = fc_path(res, key);
121
	return ID_TABLE_STOP;
122
    }
123
    if (rb_namespace_p(value)) {
124
	if (!RCLASS_CONST_TBL(value)) return ID_TABLE_CONTINUE;
125
	else {
126
	    struct fc_result arg;
127
	    struct fc_result *list;
128

  
129
	    list = res;
130
	    while (list) {
131
		if (list->track == value) return ID_TABLE_CONTINUE;
132
		list = list->prev;
133
	    }
134

  
135
	    arg.name = key;
136
	    arg.preferred = res->preferred;
137
	    arg.path = 0;
138
	    arg.klass = res->klass;
139
	    arg.track = value;
140
	    arg.prev = res;
141
	    rb_id_table_foreach(RCLASS_CONST_TBL(value), fc_i, &arg);
142
	    if (arg.path) {
143
		res->path = arg.path;
144
		return ID_TABLE_STOP;
145
	    }
146
	}
147
    }
148
    return ID_TABLE_CONTINUE;
149
}
150

  
151
/**
152
 * Traverse constant namespace and find +classpath+ for _klass_.  If
153
 * _preferred_ is not 0, choice the path whose base name is set to it.
154
 * If +classpath+ is found, the hidden instance variable __classpath__
155
 * is set to the found path, and __tmp_classpath__ is removed.
156
 * The path is frozen.
157
 */
158
static VALUE
159
find_class_path(VALUE klass, ID preferred)
160
{
161
    struct fc_result arg;
162

  
163
    arg.preferred = preferred;
164
    arg.name = 0;
165
    arg.path = 0;
166
    arg.klass = klass;
167
    arg.track = rb_cObject;
168
    arg.prev = 0;
169
    if (RCLASS_CONST_TBL(rb_cObject)) {
170
	rb_id_table_foreach(RCLASS_CONST_TBL(rb_cObject), fc_i, &arg);
171
    }
172
    if (arg.path) {
173
	st_data_t tmp = tmp_classpath;
174
	if (!RCLASS_IV_TBL(klass)) {
175
	    RCLASS_IV_TBL(klass) = st_init_numtable();
176
	}
177
	rb_class_ivar_set(klass, classpath, arg.path);
178

  
179
	st_delete(RCLASS_IV_TBL(klass), &tmp, 0);
180
	return arg.path;
181
    }
182
    return Qnil;
183
}
184

  
185 74
/**
186 75
 * Returns +classpath+ of _klass_, if it is named, or +nil+ for
187
 * anonymous +class+/+module+.  The last part of named +classpath+ is
188
 * never anonymous, but anonymous +class+/+module+ names may be
189
 * contained.  If the path is "permanent", that means it has no
190
 * anonymous names, <code>*permanent</code> is set to 1.
76
 * anonymous +class+/+module+. A named +classpath+ may contain
77
 * an anonymous component, but the last component is guaranteed
78
 * to not be anonymous. <code>*permanent</code> is set to 1
79
 * if +classpath+ has no anonymous components. There is no builtin
80
 * Ruby level APIs that can change a permanent +classpath+.
191 81
 */
192 82
static VALUE
193 83
classname(VALUE klass, int *permanent)
194 84
{
195
    VALUE path = Qnil;
85
    st_table *ivtbl;
196 86
    st_data_t n;
197 87

  
198
    if (!klass) klass = rb_cObject;
199
    *permanent = 1;
200
    if (RCLASS_IV_TBL(klass)) {
201
	if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classpath, &n)) {
202
	    ID cid = 0;
203
	    if (st_lookup(RCLASS_IV_TBL(klass), (st_data_t)classid, &n)) {
204
		VALUE cname = (VALUE)n;
205
		cid = rb_check_id(&cname);
206
		if (cid) path = find_class_path(klass, cid);
207
	    }
208
	    if (NIL_P(path)) {
209
		path = find_class_path(klass, (ID)0);
210
	    }
211
	    if (NIL_P(path)) {
212
		if (!cid) {
213
		    return Qnil;
214
		}
215
		if (!st_lookup(RCLASS_IV_TBL(klass), (st_data_t)tmp_classpath, &n)) {
216
		    path = rb_id2str(cid);
217
		    return path;
218
		}
219
		*permanent = 0;
220
		path = (VALUE)n;
221
		return path;
222
	    }
223
	}
224
	else {
225
	    path = (VALUE)n;
226
	}
227
	if (!RB_TYPE_P(path, T_STRING)) {
228
	    rb_bug("class path is not set properly");
229
	}
230
	return path;
88
    *permanent = 0;
89
    if (!RCLASS_EXT(klass)) return Qnil;
90
    if (!(ivtbl = RCLASS_IV_TBL(klass))) return Qnil;
91
    if (st_lookup(ivtbl, (st_data_t)classpath, &n)) {
92
        *permanent = 1;
93
        return (VALUE)n;
231 94
    }
232
    return find_class_path(klass, (ID)0);
95
    if (st_lookup(ivtbl, (st_data_t)tmp_classpath, &n)) return (VALUE)n;
96
    return Qnil;
233 97
}
234 98

  
235 99
/*
......
268 132
    return path;
269 133
}
270 134

  
271
typedef VALUE (*path_cache_func)(VALUE obj, VALUE name);
135
typedef VALUE (*fallback_func)(VALUE obj, VALUE name);
272 136

  
273 137
static VALUE
274
rb_tmp_class_path(VALUE klass, int *permanent, path_cache_func cache_path)
138
rb_tmp_class_path(VALUE klass, int *permanent, fallback_func fallback)
275 139
{
276 140
    VALUE path = classname(klass, permanent);
277
    st_data_t n = (st_data_t)path;
278 141

  
279 142
    if (!NIL_P(path)) {
280 143
	return path;
281 144
    }
282
    if (RCLASS_IV_TBL(klass) && st_lookup(RCLASS_IV_TBL(klass),
283
					  (st_data_t)tmp_classpath, &n)) {
284
	*permanent = 0;
285
	return (VALUE)n;
286
    }
287 145
    else {
288 146
	if (RB_TYPE_P(klass, T_MODULE)) {
289 147
	    if (rb_obj_class(klass) == rb_cModule) {
......
291 149
	    }
292 150
	    else {
293 151
		int perm;
294
		path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, cache_path);
152
		path = rb_tmp_class_path(RBASIC(klass)->klass, &perm, fallback);
295 153
	    }
296 154
	}
297 155
	*permanent = 0;
298
	return cache_path(klass, path);
156
	return fallback(klass, path);
299 157
    }
300 158
}
301 159

  
302
static VALUE
303
ivar_cache(VALUE obj, VALUE name)
304
{
305
    return rb_ivar_set(obj, tmp_classpath, make_temporary_path(obj, name));
306
}
307

  
308 160
VALUE
309 161
rb_class_path(VALUE klass)
310 162
{
311 163
    int permanent;
312
    VALUE path = rb_tmp_class_path(klass, &permanent, ivar_cache);
313
    if (!NIL_P(path)) path = rb_str_dup(path);
314
    return path;
315
}
316

  
317
static VALUE
318
null_cache(VALUE obj, VALUE name)
319
{
320
    return make_temporary_path(obj, name);
321
}
322

  
323
VALUE
324
rb_class_path_no_cache(VALUE klass)
325
{
326
    int permanent;
327
    VALUE path = rb_tmp_class_path(klass, &permanent, null_cache);
164
    VALUE path = rb_tmp_class_path(klass, &permanent, make_temporary_path);
328 165
    if (!NIL_P(path)) path = rb_str_dup(path);
329 166
    return path;
330 167
}
......
332 169
VALUE
333 170
rb_class_path_cached(VALUE klass)
334 171
{
335
    st_table *ivtbl;
336
    st_data_t n;
337

  
338
    if (!RCLASS_EXT(klass)) return Qnil;
339
    if (!(ivtbl = RCLASS_IV_TBL(klass))) return Qnil;
340
    if (st_lookup(ivtbl, (st_data_t)classpath, &n)) return (VALUE)n;
341
    if (st_lookup(ivtbl, (st_data_t)tmp_classpath, &n)) return (VALUE)n;
342
    return Qnil;
172
    int permanent;
173
    return classname(klass, &permanent);
343 174
}
344 175

  
345 176
static VALUE
346
never_cache(VALUE obj, VALUE name)
177
no_fallback(VALUE obj, VALUE name)
347 178
{
348 179
    return name;
349 180
}
......
352 183
rb_search_class_path(VALUE klass)
353 184
{
354 185
    int permanent;
355
    return rb_tmp_class_path(klass, &permanent, never_cache);
186
    return rb_tmp_class_path(klass, &permanent, no_fallback);
187
}
188

  
189
static VALUE
190
save_temporary_path(VALUE obj, VALUE name)
191
{
192
    return rb_ivar_set(obj, tmp_classpath, make_temporary_path(obj, name));
356 193
}
357 194

  
358 195
void
......
366 203
    }
367 204
    else {
368 205
	int permanent;
369
	str = rb_str_dup(rb_tmp_class_path(under, &permanent, ivar_cache));
206
	str = rb_str_dup(rb_tmp_class_path(under, &permanent, save_temporary_path));
370 207
	rb_str_cat2(str, "::");
371 208
	rb_str_append(str, name);
372 209
	OBJ_FREEZE(str);
373 210
	if (!permanent) {
374 211
	    pathid = tmp_classpath;
375
	    rb_ivar_set(klass, classid, rb_str_intern(name));
376 212
	}
377 213
    }
378 214
    rb_ivar_set(klass, pathid, str);
......
389 225
    }
390 226
    else {
391 227
	int permanent;
392
	str = rb_str_dup(rb_tmp_class_path(under, &permanent, ivar_cache));
228
	str = rb_str_dup(rb_tmp_class_path(under, &permanent, save_temporary_path));
393 229
	rb_str_cat2(str, "::");
394 230
	rb_str_cat2(str, name);
395 231
	if (!permanent) {
396 232
	    pathid = tmp_classpath;
397
	    rb_ivar_set(klass, classid, rb_str_intern(rb_str_new_cstr(name)));
398 233
	}
399 234
    }
400 235
    OBJ_FREEZE(str);
......
449 284
    return rb_path_to_class(rb_str_new_cstr(path));
450 285
}
451 286

  
452
void
453
rb_name_class(VALUE klass, ID id)
454
{
455
    rb_ivar_set(klass, classid, ID2SYM(id));
456
}
457

  
458 287
VALUE
459 288
rb_class_name(VALUE klass)
460 289
{
......
465 294
rb_class2name(VALUE klass)
466 295
{
467 296
    int permanent;
468
    VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, ivar_cache);
297
    VALUE path = rb_tmp_class_path(rb_class_real(klass), &permanent, make_temporary_path);
469 298
    if (NIL_P(path)) return NULL;
470 299
    return RSTRING_PTR(path);
471 300
}
......
2833 2662
    rb_check_frozen(klass);
2834 2663
}
2835 2664

  
2665
static VALUE
2666
build_const_path(VALUE head, ID tail)
2667
{
2668
    VALUE path = rb_str_dup(head);
2669
    rb_str_cat2(path, "::");
2670
    rb_str_append(path, rb_id2str(tail));
2671
    OBJ_FREEZE(path);
2672
    return path;
2673
}
2674

  
2675
static void finalize_classpath_for_children(VALUE named_namespace);
2676

  
2677
static enum rb_id_table_iterator_result
2678
finalize_classpath_i(ID id, VALUE v, void *payload)
2679
{
2680
    rb_const_entry_t *ce = (rb_const_entry_t *)v;
2681
    VALUE value = ce->value;
2682
    int has_permanent_classpath;
2683
    VALUE parental_path = *((VALUE *) payload);
2684
    if (!rb_is_const_id(id)) {
2685
        return ID_TABLE_CONTINUE;
2686
    }
2687
    if (!rb_namespace_p(value)) {
2688
        return ID_TABLE_CONTINUE;
2689
    }
2690
    classname(value, &has_permanent_classpath);
2691
    if (has_permanent_classpath) {
2692
        return ID_TABLE_CONTINUE;
2693
    }
2694
    rb_ivar_set(value, classpath, build_const_path(parental_path, id));
2695
    if (RCLASS_IV_TBL(value)) {
2696
        st_data_t tmp = tmp_classpath;
2697
        st_delete(RCLASS_IV_TBL(value), &tmp, 0);
2698
    }
2699
    finalize_classpath_for_children(value);
2700

  
2701
    return ID_TABLE_CONTINUE;
2702
}
2703

  
2704
/*
2705
 * Assign permanent classpaths to all namespaces that are directly or indirectly
2706
 * nested under +named_namespace+. +named_namespace+ must have a permanent
2707
 * classpath.
2708
 */
2709
static void
2710
finalize_classpath_for_children(VALUE named_namespace)
2711
{
2712
    struct rb_id_table *const_table = RCLASS_CONST_TBL(named_namespace);
2713

  
2714
    if (const_table) {
2715
        int permanent;
2716
        VALUE parental_path = classname(named_namespace, &permanent);
2717
        VM_ASSERT(RB_TYPE_P(parental_path, T_STRING));
2718
        VM_ASSERT(permanent);
2719
        rb_id_table_foreach(const_table, finalize_classpath_i, &parental_path);
2720
    }
2721
}
2722

  
2836 2723
void
2837 2724
rb_const_set(VALUE klass, ID id, VALUE val)
2838 2725
{
......
2865 2752
     * and avoid order-dependency on const_tbl
2866 2753
     */
2867 2754
    if (rb_cObject && rb_namespace_p(val)) {
2868
	if (NIL_P(rb_class_path_cached(val))) {
2755
        int val_path_permanent;
2756
        VALUE val_path = classname(val, &val_path_permanent);
2757
        if (NIL_P(val_path) || !val_path_permanent) {
2869 2758
	    if (klass == rb_cObject) {
2870 2759
		rb_ivar_set(val, classpath, rb_id2str(id));
2871
		rb_name_class(val, id);
2760
                finalize_classpath_for_children(val);
2872 2761
	    }
2873 2762
	    else {
2874
		VALUE path;
2875
		ID pathid;
2876
		st_data_t n;
2877
		st_table *ivtbl = RCLASS_IV_TBL(klass);
2878
		if (ivtbl &&
2879
		    (st_lookup(ivtbl, (st_data_t)(pathid = classpath), &n) ||
2880
		     st_lookup(ivtbl, (st_data_t)(pathid = tmp_classpath), &n))) {
2881
		    path = rb_str_dup((VALUE)n);
2882
		    rb_str_append(rb_str_cat2(path, "::"), rb_id2str(id));
2883
		    OBJ_FREEZE(path);
2884
		    rb_ivar_set(val, pathid, path);
2885
		    rb_name_class(val, id);
2763
                int parental_path_permanent;
2764
                VALUE parental_path = classname(klass, &parental_path_permanent);
2765
                if (!NIL_P(parental_path)) {
2766
                    if (parental_path_permanent && !val_path_permanent) {
2767
                        rb_ivar_set(val, classpath, build_const_path(parental_path, id));
2768
                        finalize_classpath_for_children(val);
2769
                    } else if (!parental_path_permanent && NIL_P(val_path)) {
2770
                        rb_ivar_set(val, tmp_classpath, build_const_path(parental_path, id));
2771
                    }
2886 2772
		}
2887 2773
	    }
2888 2774
	}
vm.c
374 374
    ruby_vm_const_missing_count +=1;
375 375
}
376 376

  
377
VALUE rb_class_path_no_cache(VALUE _klass);
378

  
379 377
MJIT_FUNC_EXPORTED int
380 378
rb_dtrace_setup(rb_execution_context_t *ec, VALUE klass, ID id,
381 379
		struct ruby_dtrace_method_hook_args *args)
......
395 393
    }
396 394
    type = BUILTIN_TYPE(klass);
397 395
    if (type == T_CLASS || type == T_ICLASS || type == T_MODULE) {
398
	VALUE name = rb_class_path_no_cache(klass);
396
	VALUE name = rb_class_path(klass);
399 397
	const char *classname, *filename;
400 398
	const char *methodname = rb_id2name(id);
401 399
	if (methodname && (filename = rb_source_location_cstr(&args->line_no)) != 0) {
402
-