1:
2:
3:
4:
5:
6: #define CACHE_SIZE 0x800
7: #define CACHE_MASK 0x7ff
8: #define EXPR1(c,m) ((((c)>>3)^(m))&CACHE_MASK)
9:
10: struct cache_entry {
11: ID mid;
12: ID mid0;
13: VALUE klass;
14: NODE *method;
15: };
16:
17: static struct cache_entry cache[CACHE_SIZE];
18: static int ruby_running = 0;
19:
20: void
21: rb_clear_cache(void)
22: {
23: struct cache_entry *ent, *end;
24:
25: rb_vm_change_state();
26:
27: if (!ruby_running)
28: return;
29: ent = cache;
30: end = ent + CACHE_SIZE;
31: while (ent < end) {
32: ent->mid = 0;
33: ent++;
34: }
35: }
36:
37: static void
38: rb_clear_cache_for_undef(VALUE klass, ID id)
39: {
40: struct cache_entry *ent, *end;
41:
42: rb_vm_change_state();
43:
44: if (!ruby_running)
45: return;
46: ent = cache;
47: end = ent + CACHE_SIZE;
48: while (ent < end) {
49: if (ent->method && ent->method->nd_clss == klass && ent->mid == id) {
50: ent->mid = 0;
51: }
52: ent++;
53: }
54: }
55:
56: static void
57: rb_clear_cache_by_id(ID id)
58: {
59: struct cache_entry *ent, *end;
60:
61: rb_vm_change_state();
62:
63: if (!ruby_running)
64: return;
65: ent = cache;
66: end = ent + CACHE_SIZE;
67: while (ent < end) {
68: if (ent->mid == id) {
69: ent->mid = 0;
70: }
71: ent++;
72: }
73: }
74:
75: void
76: rb_clear_cache_by_class(VALUE klass)
77: {
78: struct cache_entry *ent, *end;
79:
80: rb_vm_change_state();
81:
82: if (!ruby_running)
83: return;
84: ent = cache;
85: end = ent + CACHE_SIZE;
86: while (ent < end) {
87: if ((ent->klass == klass) ||
88: (ent->method && ent->method->nd_clss == klass)) {
89: ent->mid = 0;
90: }
91: ent++;
92: }
93: }
94:
95: void
96: rb_add_method(VALUE klass, ID mid, NODE * node, int noex)
97: {
98: NODE *body;
99:
100: if (NIL_P(klass)) {
101: klass = rb_cObject;
102: }
103: if (rb_safe_level() >= 4 && (klass == rb_cObject || !OBJ_TAINTED(klass))) {
104: rb_raise(rb_eSecurityError, "Insecure: can't define method");
105: }
106: if (!FL_TEST(klass, FL_SINGLETON) &&
107: node && nd_type(node) != NODE_ZSUPER &&
108: (mid == rb_intern("initialize") || mid == rb_intern("initialize_copy"))) {
109: noex = NOEX_PRIVATE | noex;
110: }
111: else if (FL_TEST(klass, FL_SINGLETON) && node
112: && nd_type(node) == NODE_CFUNC && mid == rb_intern("allocate")) {
113: rb_warn
114: ("defining %s.allocate is deprecated; use rb_define_alloc_func()",
115: rb_class2name(rb_iv_get(klass, "__attached__")));
116: mid = ID_ALLOCATOR;
117: }
118: if (OBJ_FROZEN(klass)) {
119: rb_error_frozen("class/module");
120: }
121: rb_clear_cache_by_id(mid);
122:
123:
124:
125:
126:
127:
128:
129:
130:
131:
132:
133:
134: if (node) {
135: body = NEW_FBODY(NEW_METHOD(node, klass, NOEX_WITH_SAFE(noex)), 0);
136: }
137: else {
138: body = 0;
139: }
140:
141: {
142:
143: st_data_t data;
144: NODE *old_node;
145:
146: if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) {
147: old_node = (NODE *)data;
148: if (old_node) {
149: if (nd_type(old_node->nd_body->nd_body) == NODE_CFUNC) {
150: rb_vm_check_redefinition_opt_method(old_node);
151: }
152: if (RTEST(ruby_verbose) && node && old_node->nd_cnt == 0 && old_node->nd_body) {
153: rb_warning("method redefined; discarding old %s", rb_id2name(mid));
154: }
155: }
156: if (klass == rb_cObject && node && node->nd_mid == init) {
157: rb_warn("redefining Object#initialize may cause infinite loop");
158: }
159: }
160:
161: if (mid == object_id || mid == __send__) {
162: if (node && nd_type(node) == RUBY_VM_METHOD_NODE) {
163: rb_warn("redefining `%s' may cause serious problem",
164: rb_id2name(mid));
165: }
166: }
167: }
168:
169: st_insert(RCLASS_M_TBL(klass), mid, (st_data_t) body);
170:
171: if (node && mid != ID_ALLOCATOR && ruby_running) {
172: if (FL_TEST(klass, FL_SINGLETON)) {
173: rb_funcall(rb_iv_get(klass, "__attached__"), singleton_added, 1,
174: ID2SYM(mid));
175: }
176: else {
177: rb_funcall(klass, added, 1, ID2SYM(mid));
178: }
179: }
180: }
181:
182: void
183: rb_define_alloc_func(VALUE klass, VALUE (*func) _((VALUE)))
184: {
185: Check_Type(klass, T_CLASS);
186: rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, NEW_CFUNC(func, 0),
187: NOEX_PRIVATE);
188: }
189:
190: void
191: rb_undef_alloc_func(VALUE klass)
192: {
193: Check_Type(klass, T_CLASS);
194: rb_add_method(CLASS_OF(klass), ID_ALLOCATOR, 0, NOEX_UNDEF);
195: }
196:
197: rb_alloc_func_t
198: rb_get_alloc_func(VALUE klass)
199: {
200: NODE *n;
201: Check_Type(klass, T_CLASS);
202: n = rb_method_node(CLASS_OF(klass), ID_ALLOCATOR);
203: if (!n) return 0;
204: if (nd_type(n) != NODE_METHOD) return 0;
205: n = n->nd_body;
206: if (nd_type(n) != NODE_CFUNC) return 0;
207: return (rb_alloc_func_t)n->nd_cfnc;
208: }
209:
210: static NODE *
211: search_method(VALUE klass, ID id, VALUE *klassp)
212: {
213: st_data_t body;
214:
215: if (!klass) {
216: return 0;
217: }
218:
219: while (!st_lookup(RCLASS_M_TBL(klass), id, &body)) {
220: klass = RCLASS_SUPER(klass);
221: if (!klass)
222: return 0;
223: }
224:
225: if (klassp) {
226: *klassp = klass;
227: }
228:
229: return (NODE *)body;
230: }
231:
232:
233:
234:
235:
236:
237:
238:
239:
240: NODE *
241: rb_get_method_body(VALUE klass, ID id, ID *idp)
242: {
243: NODE *volatile fbody, *body;
244: NODE *method;
245:
246: if ((fbody = search_method(klass, id, 0)) == 0 || !fbody->nd_body) {
247:
248: struct cache_entry *ent;
249: ent = cache + EXPR1(klass, id);
250: ent->klass = klass;
251: ent->mid = ent->mid0 = id;
252: ent->method = 0;
253: return 0;
254: }
255:
256: method = fbody->nd_body;
257:
258: if (ruby_running) {
259:
260: struct cache_entry *ent;
261: ent = cache + EXPR1(klass, id);
262: ent->klass = klass;
263: ent->mid = id;
264: ent->mid0 = fbody->nd_oid;
265: ent->method = body = method;
266: }
267: else {
268: body = method;
269: }
270:
271: if (idp) {
272: *idp = fbody->nd_oid;
273: }
274:
275: return body;
276: }
277:
278: NODE *
279: rb_method_node(VALUE klass, ID id)
280: {
281: struct cache_entry *ent;
282:
283: ent = cache + EXPR1(klass, id);
284: if (ent->mid == id && ent->klass == klass && ent->method) {
285: return ent->method;
286: }
287:
288: return rb_get_method_body(klass, id, 0);
289: }
290:
291: static void
292: remove_method(VALUE klass, ID mid)
293: {
294: st_data_t data;
295: NODE *body = 0;
296:
297: if (klass == rb_cObject) {
298: rb_secure(4);
299: }
300: if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
301: rb_raise(rb_eSecurityError, "Insecure: can't remove method");
302: }
303: if (OBJ_FROZEN(klass))
304: rb_error_frozen("class/module");
305: if (mid == object_id || mid == __send__ || mid == init) {
306: rb_warn("removing `%s' may cause serious problem", rb_id2name(mid));
307: }
308: if (st_lookup(RCLASS_M_TBL(klass), mid, &data)) {
309: body = (NODE *)data;
310: if (!body || !body->nd_body) body = 0;
311: else {
312: st_delete(RCLASS_M_TBL(klass), &mid, &data);
313: }
314: }
315: if (!body) {
316: rb_name_error(mid, "method `%s' not defined in %s",
317: rb_id2name(mid), rb_class2name(klass));
318: }
319:
320: if (nd_type(body->nd_body->nd_body) == NODE_CFUNC) {
321: rb_vm_check_redefinition_opt_method(body);
322: }
323:
324: rb_clear_cache_for_undef(klass, mid);
325: if (FL_TEST(klass, FL_SINGLETON)) {
326: rb_funcall(rb_iv_get(klass, "__attached__"), singleton_removed, 1,
327: ID2SYM(mid));
328: }
329: else {
330: rb_funcall(klass, removed, 1, ID2SYM(mid));
331: }
332: }
333:
334: void
335: rb_remove_method(VALUE klass, const char *name)
336: {
337: remove_method(klass, rb_intern(name));
338: }
339:
340:
341:
342:
343:
344:
345:
346:
347:
348: static VALUE
349: rb_mod_remove_method(int argc, VALUE *argv, VALUE mod)
350: {
351: int i;
352:
353: for (i = 0; i < argc; i++) {
354: remove_method(mod, rb_to_id(argv[i]));
355: }
356: return mod;
357: }
358:
359: #undef rb_disable_super
360: #undef rb_enable_super
361:
362: void
363: rb_disable_super(VALUE klass, const char *name)
364: {
365:
366: }
367:
368: void
369: rb_enable_super(VALUE klass, const char *name)
370: {
371: rb_warning("rb_enable_super() is obsolete");
372: }
373:
374: static void
375: rb_export_method(VALUE klass, ID name, ID noex)
376: {
377: NODE *fbody;
378: VALUE origin;
379:
380: if (klass == rb_cObject) {
381: rb_secure(4);
382: }
383: fbody = search_method(klass, name, &origin);
384: if (!fbody && TYPE(klass) == T_MODULE) {
385: fbody = search_method(rb_cObject, name, &origin);
386: }
387: if (!fbody || !fbody->nd_body) {
388: rb_print_undef(klass, name, 0);
389: }
390: if (fbody->nd_body->nd_noex != noex) {
391: if (klass == origin) {
392: fbody->nd_body->nd_noex = noex;
393: }
394: else {
395: rb_add_method(klass, name, NEW_ZSUPER(), noex);
396: }
397: }
398: }
399:
400: int
401: rb_method_boundp(VALUE klass, ID id, int ex)
402: {
403: NODE *method;
404:
405: if ((method = rb_method_node(klass, id)) != 0) {
406: if (ex && (method->nd_noex & NOEX_PRIVATE)) {
407: return Qfalse;
408: }
409: return Qtrue;
410: }
411: return Qfalse;
412: }
413:
414: void
415: rb_attr(VALUE klass, ID id, int read, int write, int ex)
416: {
417: const char *name;
418: ID attriv;
419: int noex;
420:
421: if (!ex) {
422: noex = NOEX_PUBLIC;
423: }
424: else {
425: if (SCOPE_TEST(NOEX_PRIVATE)) {
426: noex = NOEX_PRIVATE;
427: rb_warning((SCOPE_CHECK(NOEX_MODFUNC)) ?
428: "attribute accessor as module_function" :
429: "private attribute?");
430: }
431: else if (SCOPE_TEST(NOEX_PROTECTED)) {
432: noex = NOEX_PROTECTED;
433: }
434: else {
435: noex = NOEX_PUBLIC;
436: }
437: }
438:
439: if (!rb_is_local_id(id) && !rb_is_const_id(id)) {
440: rb_name_error(id, "invalid attribute name `%s'", rb_id2name(id));
441: }
442: name = rb_id2name(id);
443: if (!name) {
444: rb_raise(rb_eArgError, "argument needs to be symbol or string");
445: }
446: attriv = rb_intern_str(rb_sprintf("@%s", name));
447: if (read) {
448: rb_add_method(klass, id, NEW_IVAR(attriv), noex);
449: }
450: if (write) {
451: rb_add_method(klass, rb_id_attrset(id), NEW_ATTRSET(attriv), noex);
452: }
453: }
454:
455: void
456: rb_undef(VALUE klass, ID id)
457: {
458: VALUE origin;
459: NODE *body;
460:
461: if (ruby_cbase() == rb_cObject && klass == rb_cObject) {
462: rb_secure(4);
463: }
464: if (rb_safe_level() >= 4 && !OBJ_TAINTED(klass)) {
465: rb_raise(rb_eSecurityError, "Insecure: can't undef `%s'",
466: rb_id2name(id));
467: }
468: rb_frozen_class_p(klass);
469: if (id == object_id || id == __send__ || id == init) {
470: rb_warn("undefining `%s' may cause serious problem", rb_id2name(id));
471: }
472: body = search_method(klass, id, &origin);
473: if (!body || !body->nd_body) {
474: char *s0 = " class";
475: VALUE c = klass;
476:
477: if (FL_TEST(c, FL_SINGLETON)) {
478: VALUE obj = rb_iv_get(klass, "__attached__");
479:
480: switch (TYPE(obj)) {
481: case T_MODULE:
482: case T_CLASS:
483: c = obj;
484: s0 = "";
485: }
486: }
487: else if (TYPE(c) == T_MODULE) {
488: s0 = " module";
489: }
490: rb_name_error(id, "undefined method `%s' for%s `%s'",
491: rb_id2name(id), s0, rb_class2name(c));
492: }
493:
494: rb_add_method(klass, id, 0, NOEX_PUBLIC);
495:
496: if (FL_TEST(klass, FL_SINGLETON)) {
497: rb_funcall(rb_iv_get(klass, "__attached__"),
498: singleton_undefined, 1, ID2SYM(id));
499: }
500: else {
501: rb_funcall(klass, undefined, 1, ID2SYM(id));
502: }
503: }
504:
505:
506:
507:
508:
509:
510:
511:
512:
513:
514:
515:
516:
517:
518:
519:
520:
521:
522:
523:
524:
525:
526:
527:
528:
529:
530:
531:
532:
533:
534:
535:
536:
537:
538:
539:
540:
541:
542:
543:
544:
545:
546:
547:
548: static VALUE
549: rb_mod_undef_method(int argc, VALUE *argv, VALUE mod)
550: {
551: int i;
552: for (i = 0; i < argc; i++) {
553: rb_undef(mod, rb_to_id(argv[i]));
554: }
555: return mod;
556: }
557:
558: void
559: rb_alias(VALUE klass, ID name, ID def)
560: {
561: NODE *orig_fbody, *node;
562: VALUE singleton = 0;
563: st_data_t data;
564:
565: rb_frozen_class_p(klass);
566: if (klass == rb_cObject) {
567: rb_secure(4);
568: }
569: orig_fbody = search_method(klass, def, 0);
570: if (!orig_fbody || !orig_fbody->nd_body) {
571: if (TYPE(klass) == T_MODULE) {
572: orig_fbody = search_method(rb_cObject, def, 0);
573: }
574: }
575: if (!orig_fbody || !orig_fbody->nd_body) {
576: rb_print_undef(klass, def, 0);
577: }
578: if (FL_TEST(klass, FL_SINGLETON)) {
579: singleton = rb_iv_get(klass, "__attached__");
580: }
581:
582: orig_fbody->nd_cnt++;
583:
584: if (st_lookup(RCLASS_M_TBL(klass), name, &data)) {
585: node = (NODE *)data;
586: if (node) {
587: if (RTEST(ruby_verbose) && node->nd_cnt == 0 && node->nd_body) {
588: rb_warning("discarding old %s", rb_id2name(name));
589: }
590: if (nd_type(node->nd_body->nd_body) == NODE_CFUNC) {
591: rb_vm_check_redefinition_opt_method(node);
592: }
593: }
594: }
595:
596: st_insert(RCLASS_M_TBL(klass), name,
597: (st_data_t) NEW_FBODY(
598: NEW_METHOD(orig_fbody->nd_body->nd_body,
599: orig_fbody->nd_body->nd_clss,
600: NOEX_WITH_SAFE(orig_fbody->nd_body->nd_noex)), def));
601:
602: rb_clear_cache_by_id(name);
603:
604: if (!ruby_running) return;
605:
606: if (singleton) {
607: rb_funcall(singleton, singleton_added, 1, ID2SYM(name));
608: }
609: else {
610: rb_funcall(klass, added, 1, ID2SYM(name));
611: }
612: }
613:
614:
615:
616:
617:
618: