~ubuntu-branches/ubuntu/intrepid/ruby1.9/intrepid-updates

« back to all changes in this revision

Viewing changes to eval_method.h

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Klose
  • Date: 2007-09-04 16:01:17 UTC
  • mfrom: (1.1.8 upstream)
  • Revision ID: james.westby@ubuntu.com-20070904160117-i15zckg2nhxe9fyw
Tags: 1.9.0+20070830-2ubuntu1
* Sync from Debian; remaining changes:
  - Add -g to CFLAGS.
* Fixes build failure on ia64.
* Fixes build failure with gcc-4.2 on lpia.
* Robustify check for target_os, fixing build failure on lpia.
* Set Ubuntu maintainer address.

Show diffs side-by-side

added added

removed removed

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