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

« back to all changes in this revision

Viewing changes to yarvcore.c

  • 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
 
 
3
 
  yarvcore.h - 
4
 
 
5
 
  $Author: ko1 $
6
 
  $Date: 2007-05-28 04:12:43 +0900 (月, 28  5月 2007) $
7
 
  created at: 04/01/01 01:17:22 JST
8
 
 
9
 
  Copyright (C) 2004-2006 Koichi Sasada
10
 
 
11
 
**********************************************************************/
12
 
 
13
 
#include "ruby.h"
14
 
#include "node.h"
15
 
#include "yarvcore.h"
16
 
#include "gc.h"
17
 
 
18
 
 
19
 
VALUE rb_cVM;
20
 
VALUE rb_cThread;
21
 
 
22
 
VALUE symIFUNC;
23
 
VALUE symCFUNC;
24
 
 
25
 
ID idPLUS;
26
 
ID idMINUS;
27
 
ID idMULT;
28
 
ID idDIV;
29
 
ID idMOD;
30
 
ID idLT;
31
 
ID idLTLT;
32
 
ID idLE;
33
 
ID idGT;
34
 
ID idGE;
35
 
ID idEq;
36
 
ID idEqq;
37
 
ID idBackquote;
38
 
ID idEqTilde;
39
 
ID idThrowState;
40
 
ID idAREF;
41
 
ID idASET;
42
 
ID idIntern;
43
 
ID idMethodMissing;
44
 
ID idLength;
45
 
ID idLambda;
46
 
ID idGets;
47
 
ID idSucc;
48
 
ID idEach;
49
 
ID idRangeEachLT;
50
 
ID idRangeEachLE;
51
 
ID idArrayEach;
52
 
ID idTimes;
53
 
ID idEnd;
54
 
ID idBitblt;
55
 
ID idAnswer;
56
 
ID idSvarPlaceholder;
57
 
ID idSend;
58
 
ID id__send__;
59
 
ID id__send;
60
 
ID idFuncall;
61
 
ID id__send_bang;
62
 
 
63
 
/* from Ruby 1.9 eval.c */
64
 
#ifdef HAVE_STDARG_PROTOTYPES
65
 
#include <stdarg.h>
66
 
#define va_init_list(a,b) va_start(a,b)
67
 
#else
68
 
#include <varargs.h>
69
 
#define va_init_list(a,b) va_start(a)
70
 
#endif
71
 
 
72
 
/************/
73
 
/* YARVCore */
74
 
/************/
75
 
 
76
 
rb_thread_t *ruby_current_thread = 0;
77
 
rb_vm_t *ruby_current_vm = 0;
78
 
static VALUE ruby_vm_list = Qnil;
79
 
 
80
 
RUBY_EXTERN int ruby_nerrs;
81
 
 
82
 
static NODE *
83
 
compile_string(VALUE str, VALUE file, VALUE line)
84
 
{
85
 
    NODE *node;
86
 
    node = rb_compile_string(StringValueCStr(file), str, NUM2INT(line));
87
 
 
88
 
    if (ruby_nerrs > 0) {
89
 
        ruby_nerrs = 0;
90
 
        rb_exc_raise(GET_THREAD()->errinfo);    /* TODO: check err */
91
 
    }
92
 
    return node;
93
 
}
94
 
 
95
 
static VALUE
96
 
yarvcore_eval_iseq(VALUE iseq)
97
 
{
98
 
    return rb_thread_eval(GET_THREAD(), iseq);
99
 
}
100
 
 
101
 
static VALUE
102
 
th_compile_from_node(rb_thread_t *th, NODE * node, VALUE file)
103
 
{
104
 
    VALUE iseq;
105
 
    if (th->base_block) {
106
 
        iseq = rb_iseq_new(node,
107
 
                             th->base_block->iseq->name,
108
 
                             file,
109
 
                             th->base_block->iseq->self,
110
 
                             ISEQ_TYPE_EVAL);
111
 
    }
112
 
    else {
113
 
        iseq = rb_iseq_new(node, rb_str_new2("<main>"), file,
114
 
                             Qfalse, ISEQ_TYPE_TOP);
115
 
    }
116
 
    return iseq;
117
 
}
118
 
 
119
 
VALUE
120
 
th_compile(rb_thread_t *th, VALUE str, VALUE file, VALUE line)
121
 
{
122
 
    NODE *node = (NODE *) compile_string(str, file, line);
123
 
    return th_compile_from_node(th, (NODE *) node, file);
124
 
}
125
 
 
126
 
VALUE
127
 
yarvcore_eval_parsed(NODE *node, VALUE file)
128
 
{
129
 
    VALUE iseq = th_compile_from_node(GET_THREAD(), node, file);
130
 
    return yarvcore_eval_iseq(iseq);
131
 
}
132
 
 
133
 
VALUE
134
 
yarvcore_eval(VALUE self, VALUE str, VALUE file, VALUE line)
135
 
{
136
 
    NODE *node;
137
 
    node = compile_string(str, file, line);
138
 
    return yarvcore_eval_parsed(node, file);
139
 
}
140
 
 
141
 
/******/
142
 
/* VM */
143
 
/******/
144
 
 
145
 
void native_thread_cleanup(void *);
146
 
 
147
 
static void
148
 
vm_free(void *ptr)
149
 
{
150
 
    FREE_REPORT_ENTER("vm");
151
 
    if (ptr) {
152
 
        rb_vm_t *vmobj = ptr;
153
 
 
154
 
        st_free_table(vmobj->living_threads);
155
 
        /* TODO: MultiVM Instance */
156
 
        /* VM object should not be cleaned by GC */
157
 
        /* ruby_xfree(ptr); */
158
 
        /* ruby_current_vm = 0; */
159
 
    }
160
 
    FREE_REPORT_LEAVE("vm");
161
 
}
162
 
 
163
 
static int
164
 
vm_mark_each_thread_func(st_data_t key, st_data_t value, st_data_t dummy)
165
 
{
166
 
    VALUE thval = (VALUE)key;
167
 
    rb_gc_mark(thval);
168
 
    return ST_CONTINUE;
169
 
}
170
 
 
171
 
static void
172
 
mark_event_hooks(rb_event_hook_t *hook)
173
 
{
174
 
    while (hook) {
175
 
        rb_gc_mark(hook->data);
176
 
        hook = hook->next;
177
 
    }
178
 
}
179
 
 
180
 
static void
181
 
vm_mark(void *ptr)
182
 
{
183
 
    MARK_REPORT_ENTER("vm");
184
 
    GC_INFO("-------------------------------------------------\n");
185
 
    if (ptr) {
186
 
        rb_vm_t *vm = ptr;
187
 
        if (vm->living_threads) {
188
 
            st_foreach(vm->living_threads, vm_mark_each_thread_func, 0);
189
 
        }
190
 
        MARK_UNLESS_NULL(vm->thgroup_default);
191
 
        MARK_UNLESS_NULL(vm->mark_object_ary);
192
 
        MARK_UNLESS_NULL(vm->last_status);
193
 
        MARK_UNLESS_NULL(vm->loaded_features);
194
 
 
195
 
        if (vm->loading_table) {
196
 
            rb_mark_tbl(vm->loading_table);
197
 
        }
198
 
 
199
 
        mark_event_hooks(vm->event_hooks);
200
 
    }
201
 
 
202
 
    MARK_REPORT_LEAVE("vm");
203
 
}
204
 
 
205
 
void
206
 
rb_vm_mark(void *ptr)
207
 
{
208
 
    vm_mark(ptr);
209
 
}
210
 
 
211
 
static void
212
 
vm_init2(rb_vm_t *vm)
213
 
{
214
 
    MEMZERO(vm, rb_vm_t, 1);
215
 
}
216
 
 
217
 
/**********/
218
 
/* Thread */
219
 
/**********/
220
 
 
221
 
static void
222
 
thread_free(void *ptr)
223
 
{
224
 
    rb_thread_t *th;
225
 
    FREE_REPORT_ENTER("thread");
226
 
 
227
 
    if (ptr) {
228
 
        th = ptr;
229
 
        FREE_UNLESS_NULL(th->stack);
230
 
 
231
 
        if (th->local_storage) {
232
 
            st_free_table(th->local_storage);
233
 
        }
234
 
 
235
 
#if USE_VALUE_CACHE
236
 
        {
237
 
            VALUE *ptr = th->value_cache_ptr;
238
 
            while (*ptr) {
239
 
                VALUE v = *ptr;
240
 
                RBASIC(v)->flags = 0;
241
 
                RBASIC(v)->klass = 0;
242
 
                ptr++;
243
 
            }
244
 
        }
245
 
#endif
246
 
 
247
 
        if (th->vm->main_thread == th) {
248
 
            GC_INFO("main thread\n");
249
 
        }
250
 
        else {
251
 
            ruby_xfree(ptr);
252
 
        }
253
 
    }
254
 
    FREE_REPORT_LEAVE("thread");
255
 
}
256
 
 
257
 
void yarv_machine_stack_mark(rb_thread_t *th);
258
 
 
259
 
static void
260
 
thread_mark(void *ptr)
261
 
{
262
 
    rb_thread_t *th = NULL;
263
 
    MARK_REPORT_ENTER("thread");
264
 
    if (ptr) {
265
 
        th = ptr;
266
 
        if (th->stack) {
267
 
            VALUE *p = th->stack;
268
 
            VALUE *sp = th->cfp->sp + th->mark_stack_len;
269
 
            rb_control_frame_t *cfp = th->cfp;
270
 
            rb_control_frame_t *limit_cfp =
271
 
              (void *)(th->stack + th->stack_size);
272
 
 
273
 
            while (p < sp) {
274
 
                rb_gc_mark(*p++);
275
 
            }
276
 
            while (cfp != limit_cfp) {
277
 
                rb_gc_mark(cfp->proc);
278
 
                cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
279
 
            }
280
 
        }
281
 
 
282
 
        /* mark ruby objects */
283
 
        MARK_UNLESS_NULL(th->first_proc);
284
 
        MARK_UNLESS_NULL(th->first_args);
285
 
 
286
 
        MARK_UNLESS_NULL(th->thgroup);
287
 
        MARK_UNLESS_NULL(th->value);
288
 
        MARK_UNLESS_NULL(th->errinfo);
289
 
        MARK_UNLESS_NULL(th->local_svar);
290
 
        MARK_UNLESS_NULL(th->top_self);
291
 
        MARK_UNLESS_NULL(th->top_wrapper);
292
 
        MARK_UNLESS_NULL(th->fiber);
293
 
        MARK_UNLESS_NULL(th->root_fiber);
294
 
 
295
 
        rb_mark_tbl(th->local_storage);
296
 
 
297
 
        if (GET_THREAD() != th && th->machine_stack_start && th->machine_stack_end) {
298
 
            yarv_machine_stack_mark(th);
299
 
            rb_gc_mark_locations((VALUE *)&th->machine_regs,
300
 
                                 (VALUE *)(&th->machine_regs) +
301
 
                                 sizeof(th->machine_regs) / sizeof(VALUE));
302
 
        }
303
 
 
304
 
        mark_event_hooks(th->event_hooks);
305
 
    }
306
 
 
307
 
    MARK_UNLESS_NULL(th->stat_insn_usage);
308
 
    MARK_REPORT_LEAVE("thread");
309
 
}
310
 
 
311
 
void
312
 
rb_thread_mark(void *ptr)
313
 
{
314
 
    thread_mark(ptr);
315
 
}
316
 
 
317
 
static VALUE
318
 
thread_alloc(VALUE klass)
319
 
{
320
 
    VALUE volatile obj;
321
 
    rb_thread_t *th;
322
 
    obj = Data_Make_Struct(klass, rb_thread_t,
323
 
                           thread_mark, thread_free, th);
324
 
    return obj;
325
 
}
326
 
 
327
 
static void
328
 
th_init2(rb_thread_t *th)
329
 
{
330
 
    MEMZERO(th, rb_thread_t, 1);
331
 
 
332
 
    /* allocate thread stack */
333
 
    th->stack = ALLOC_N(VALUE, RUBY_VM_THREAD_STACK_SIZE);
334
 
 
335
 
    th->stack_size = RUBY_VM_THREAD_STACK_SIZE;
336
 
    th->cfp = (void *)(th->stack + th->stack_size);
337
 
    th->cfp--;
338
 
 
339
 
    th->cfp->pc = 0;
340
 
    th->cfp->sp = th->stack + 1;
341
 
    th->cfp->bp = 0;
342
 
    th->cfp->lfp = th->stack;
343
 
    *th->cfp->lfp = 0;
344
 
    th->cfp->dfp = th->stack;
345
 
    th->cfp->self = Qnil;
346
 
    th->cfp->magic = 0;
347
 
    th->cfp->iseq = 0;
348
 
    th->cfp->proc = 0;
349
 
    th->cfp->block_iseq = 0;
350
 
 
351
 
    th->status = THREAD_RUNNABLE;
352
 
    th->errinfo = Qnil;
353
 
 
354
 
#if USE_VALUE_CACHE
355
 
    th->value_cache_ptr = &th->value_cache[0];
356
 
#endif
357
 
}
358
 
 
359
 
static void
360
 
th_init(rb_thread_t *th)
361
 
{
362
 
    th_init2(th);
363
 
}
364
 
 
365
 
extern VALUE ruby_top_self;
366
 
 
367
 
static VALUE
368
 
ruby_thread_init(VALUE self)
369
 
{
370
 
    rb_thread_t *th;
371
 
    rb_vm_t *vm = GET_THREAD()->vm;
372
 
    GetThreadPtr(self, th);
373
 
 
374
 
    th_init(th);
375
 
    th->self = self;
376
 
    th->vm = vm;
377
 
 
378
 
    th->top_wrapper = 0;
379
 
    th->top_self = ruby_top_self;
380
 
    return self;
381
 
}
382
 
 
383
 
VALUE
384
 
rb_thread_alloc(VALUE klass)
385
 
{
386
 
    VALUE self = thread_alloc(klass);
387
 
    ruby_thread_init(self);
388
 
    return self;
389
 
}
390
 
 
391
 
/********************************************************************/
392
 
 
393
 
VALUE insns_name_array(void);
394
 
extern VALUE *rb_gc_stack_start;
395
 
 
396
 
static VALUE
397
 
sdr(void)
398
 
{
399
 
    yarv_bug();
400
 
    return Qnil;
401
 
}
402
 
 
403
 
static VALUE
404
 
nsdr(void)
405
 
{
406
 
    VALUE ary = rb_ary_new();
407
 
#if HAVE_BACKTRACE
408
 
#include <execinfo.h>
409
 
#define MAX_NATIVE_TRACE 1024
410
 
    static void *trace[MAX_NATIVE_TRACE];
411
 
    int n = backtrace(trace, MAX_NATIVE_TRACE);
412
 
    char **syms = backtrace_symbols(trace, n);
413
 
    int i;
414
 
 
415
 
    if (syms == 0) {
416
 
        rb_memerror();
417
 
    }
418
 
 
419
 
    for (i=0; i<n; i++) {
420
 
        rb_ary_push(ary, rb_str_new2(syms[i]));
421
 
    }
422
 
    free(syms);
423
 
#endif
424
 
    return ary;
425
 
}
426
 
 
427
 
static char *yarv_options = ""
428
 
#if   OPT_DIRECT_THREADED_CODE
429
 
    "[direct threaded code] "
430
 
#elif OPT_TOKEN_THREADED_CODE
431
 
    "[token threaded code] "
432
 
#elif OPT_CALL_THREADED_CODE
433
 
    "[call threaded code] "
434
 
#endif
435
 
 
436
 
#if OPT_BASIC_OPERATIONS
437
 
    "[optimize basic operation] "
438
 
#endif
439
 
#if OPT_STACK_CACHING
440
 
    "[stack caching] "
441
 
#endif
442
 
#if OPT_OPERANDS_UNIFICATION
443
 
    "[operands unification] "
444
 
#endif
445
 
#if OPT_INSTRUCTIONS_UNIFICATION
446
 
    "[instructions unification] "
447
 
#endif
448
 
#if OPT_INLINE_METHOD_CACHE
449
 
    "[inline method cache] "
450
 
#endif
451
 
#if OPT_BLOCKINLINING
452
 
    "[block inlining] "
453
 
#endif
454
 
    ;
455
 
 
456
 
void yarv_init_redefined_flag(void);
457
 
 
458
 
void
459
 
Init_VM(void)
460
 
{
461
 
    /* ::VM */
462
 
    rb_cVM = rb_define_class("VM", rb_cObject);
463
 
    rb_undef_alloc_func(rb_cVM);
464
 
 
465
 
    /* Env */
466
 
    rb_cEnv = rb_define_class_under(rb_cVM, "Env", rb_cObject);
467
 
    rb_undef_alloc_func(rb_cEnv);
468
 
 
469
 
    /* ::Thread */
470
 
    rb_cThread = rb_define_class("Thread", rb_cObject);
471
 
    rb_undef_alloc_func(rb_cThread);
472
 
    rb_define_method(rb_cThread, "initialize", ruby_thread_init, 0);
473
 
 
474
 
    /* ::VM::USAGE_ANALISYS_* */
475
 
    rb_define_const(rb_cVM, "USAGE_ANALISYS_INSN", rb_hash_new());
476
 
    rb_define_const(rb_cVM, "USAGE_ANALISYS_REGS", rb_hash_new());
477
 
    rb_define_const(rb_cVM, "USAGE_ANALISYS_INSN_BIGRAM", rb_hash_new());
478
 
    rb_define_const(rb_cVM, "OPTS", rb_str_new2(yarv_options));
479
 
 
480
 
    /* ::VM::InsnNameArray */
481
 
    rb_define_const(rb_cVM, "InsnNameArray", insns_name_array());
482
 
 
483
 
    /* ::VM::eval() */
484
 
    rb_define_singleton_method(rb_cVM, "eval", yarvcore_eval, 3);
485
 
 
486
 
    /* debug functions ::VM::SDR(), ::VM::NSDR() */
487
 
    rb_define_singleton_method(rb_cVM, "SDR", sdr, 0);
488
 
    rb_define_singleton_method(rb_cVM, "NSDR", nsdr, 0);
489
 
 
490
 
    /* Symbols */
491
 
    symIFUNC = ID2SYM(rb_intern("<IFUNC>"));
492
 
    symCFUNC = ID2SYM(rb_intern("<CFUNC>"));
493
 
 
494
 
    /* IDs */
495
 
    idPLUS = rb_intern("+");
496
 
    idMINUS = rb_intern("-");
497
 
    idMULT = rb_intern("*");
498
 
    idDIV = rb_intern("/");
499
 
    idMOD = rb_intern("%");
500
 
    idLT = rb_intern("<");
501
 
    idLTLT = rb_intern("<<");
502
 
    idLE = rb_intern("<=");
503
 
    idGT = rb_intern(">");
504
 
    idGE = rb_intern(">=");
505
 
    idEq = rb_intern("==");
506
 
    idEqq = rb_intern("===");
507
 
    idBackquote = rb_intern("`");
508
 
    idEqTilde = rb_intern("=~");
509
 
 
510
 
    idAREF = rb_intern("[]");
511
 
    idASET = rb_intern("[]=");
512
 
 
513
 
    idEach = rb_intern("each");
514
 
    idTimes = rb_intern("times");
515
 
    idLength = rb_intern("length");
516
 
    idLambda = rb_intern("lambda");
517
 
    idIntern = rb_intern("intern");
518
 
    idGets = rb_intern("gets");
519
 
    idSucc = rb_intern("succ");
520
 
    idEnd = rb_intern("end");
521
 
    idRangeEachLT = rb_intern("Range#each#LT");
522
 
    idRangeEachLE = rb_intern("Range#each#LE");
523
 
    idArrayEach = rb_intern("Array#each");
524
 
    idMethodMissing = rb_intern("method_missing");
525
 
 
526
 
    idThrowState = rb_intern("#__ThrowState__");
527
 
 
528
 
    idBitblt = rb_intern("bitblt");
529
 
    idAnswer = rb_intern("the_answer_to_life_the_universe_and_everything");
530
 
    idSvarPlaceholder = rb_intern("#svar");
531
 
 
532
 
    idSend = rb_intern("send");
533
 
    id__send__ = rb_intern("__send__");
534
 
    id__send = rb_intern("__send");
535
 
    idFuncall = rb_intern("funcall");
536
 
    id__send_bang = rb_intern("__send!");
537
 
 
538
 
    /* VM bootstrap: phase 2 */
539
 
    {
540
 
        rb_vm_t *vm = ruby_current_vm;
541
 
        rb_thread_t *th = GET_THREAD();
542
 
 
543
 
        /* create vm object */
544
 
        vm->self = Data_Wrap_Struct(rb_cVM, vm_mark, vm_free, vm);
545
 
 
546
 
        /* create main thread */
547
 
        th->self = Data_Wrap_Struct(rb_cThread, thread_mark, thread_free, th);
548
 
 
549
 
        vm->main_thread = th;
550
 
        vm->running_thread = th;
551
 
        th->vm = vm;
552
 
        th->top_wrapper = 0;
553
 
        th->top_self = ruby_top_self;
554
 
        rb_thread_set_current(th);
555
 
 
556
 
        vm->living_threads = st_init_numtable();
557
 
        st_insert(vm->living_threads, th->self, (st_data_t) th->thread_id);
558
 
    }
559
 
    yarv_init_redefined_flag();
560
 
}
561
 
 
562
 
void
563
 
Init_yarv(void)
564
 
{
565
 
    /* VM bootstrap: phase 1 */
566
 
    rb_vm_t *vm = ALLOC(rb_vm_t);
567
 
    rb_thread_t *th = ALLOC(rb_thread_t);
568
 
 
569
 
    vm_init2(vm);
570
 
    ruby_current_vm = vm;
571
 
 
572
 
    th_init2(th);
573
 
    th->vm = vm;
574
 
    th->machine_stack_start = rb_gc_stack_start;
575
 
    rb_thread_set_current_raw(th);
576
 
}
577