OSDN Git Service

ruby-1.9.1-rc1
[splhack/AndroidRuby.git] / lib / ruby-1.9.1-rc1 / blockinlining.c
1 /**********************************************************************
2
3   blockinlining.c -
4
5   $Author: ko1 $
6
7   Copyright (C) 2004-2007 Koichi Sasada
8
9 **********************************************************************/
10
11 #include "ruby/ruby.h"
12 #include "vm_core.h"
13
14 static VALUE
15 iseq_special_block(rb_iseq_t *iseq, void *builder)
16 {
17 #if OPT_BLOCKINLINING
18     VALUE parent = Qfalse;
19     VALUE iseqval;
20
21     if (iseq->argc > 1 || iseq->arg_simple == 0) {
22         /* argument check */
23         return 0;
24     }
25
26     if (iseq->cached_special_block_builder) {
27         if (iseq->cached_special_block_builder == builder) {
28             return iseq->cached_special_block;
29         }
30         else {
31             return 0;
32         }
33     }
34     else {
35         iseq->cached_special_block_builder = (void *)1;
36     }
37     
38     if (iseq->parent_iseq) {
39         parent = iseq->parent_iseq->self;
40     }
41     iseqval = rb_iseq_new_with_bopt(iseq->node, iseq->name, iseq->filename,
42                                       parent, iseq->type,
43                                       GC_GUARDED_PTR(builder));
44     if (0) {
45         printf("%s\n", RSTRING_PTR(ruby_iseq_disasm(iseqval)));
46     }
47     iseq->cached_special_block = iseqval;
48     iseq->cached_special_block_builder = builder;
49     return iseqval;
50 #else
51     return 0;
52 #endif
53 }
54
55 static NODE *
56 new_block(NODE * head, NODE * tail)
57 {
58     head = NEW_BLOCK(head);
59     tail = NEW_BLOCK(tail);
60     head->nd_next = tail;
61     return head;
62 }
63
64 static NODE *
65 new_ary(NODE * head, NODE * tail)
66 {
67     head = NEW_ARRAY(head);
68     head->nd_next = tail;
69     return head;
70 }
71
72 static NODE *
73 new_assign(NODE * lnode, NODE * rhs)
74 {
75     switch (nd_type(lnode)) {
76       case NODE_LASGN:{
77           return NEW_NODE(NODE_LASGN, lnode->nd_vid, rhs, lnode->nd_cnt);
78           /* NEW_LASGN(lnode->nd_vid, rhs); */
79       }
80       case NODE_GASGN:{
81           return NEW_GASGN(lnode->nd_vid, rhs);
82       }
83       case NODE_DASGN:{
84           return NEW_DASGN(lnode->nd_vid, rhs);
85       }
86       case NODE_ATTRASGN:{
87           NODE *args = 0;
88           if (lnode->nd_args) {
89               args = NEW_ARRAY(lnode->nd_args->nd_head);
90               args->nd_next = NEW_ARRAY(rhs);
91               args->nd_alen = 2;
92           }
93           else {
94               args = NEW_ARRAY(rhs);
95           }
96
97           return NEW_ATTRASGN(lnode->nd_recv,
98                               lnode->nd_mid,
99                               args);
100       }
101       default:
102         rb_bug("unimplemented (block inlining): %s", ruby_node_name(nd_type(lnode)));
103     }
104     return 0;
105 }
106
107 static NODE *
108 build_Integer_times_node(rb_iseq_t *iseq, NODE * node, NODE * lnode,
109                          VALUE param_vars, VALUE local_vars)
110 {
111     /* Special Block for Integer#times
112        {|e, _self|
113        _e = e
114        while(e < _self)
115        e = _e
116        redo_point:
117        BODY
118        next_point:
119        _e = _e.succ
120        end
121        }
122
123        {|e, _self|
124        while(e < _self)
125        BODY
126        next_point:
127        e = e.succ
128        end
129        }
130      */
131     ID _self;
132     CONST_ID(_self, "#_self");
133     if (iseq->argc == 0) {
134         ID e;
135         CONST_ID(e, "#e");
136         rb_ary_push(param_vars, ID2SYM(e));
137         rb_ary_push(param_vars, ID2SYM(_self));
138         iseq->argc += 2;
139
140         node =
141             NEW_WHILE(NEW_CALL
142                       (NEW_DVAR(e), idLT, new_ary(NEW_DVAR(_self), 0)),
143                       new_block(NEW_OPTBLOCK(node),
144                                 NEW_DASGN(e,
145                                           NEW_CALL(NEW_DVAR(e), idSucc, 0))),
146                       Qundef);
147     }
148     else {
149         ID _e;
150         ID e = SYM2ID(rb_ary_entry(param_vars, 0));
151         NODE *assign;
152
153         CONST_ID(_e, "#_e");
154         rb_ary_push(param_vars, ID2SYM(_self));
155         rb_ary_push(local_vars, ID2SYM(_e));
156         iseq->argc++;
157
158         if (nd_type(lnode) == NODE_DASGN_CURR) {
159             assign = NEW_DASGN(e, NEW_DVAR(_e));
160         }
161         else {
162             assign = new_assign(lnode, NEW_DVAR(_e));
163         }
164
165         node =
166             new_block(NEW_DASGN(_e, NEW_DVAR(e)),
167                       NEW_WHILE(NEW_CALL
168                                 (NEW_DVAR(_e), idLT,
169                                  new_ary(NEW_DVAR(_self), 0)),
170                                 new_block(assign,
171                                           new_block(NEW_OPTBLOCK(node),
172                                                     NEW_DASGN(_e,
173                                                               NEW_CALL
174                                                               (NEW_DVAR(_e),
175                                                                idSucc, 0)))),
176                                 Qundef));
177     }
178     return node;
179 }
180
181 VALUE
182 invoke_Integer_times_special_block(VALUE num)
183 {
184     rb_thread_t *th = GET_THREAD();
185     rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
186
187     if (orig_block && BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
188         VALUE tsiseqval = iseq_special_block(orig_block->iseq,
189                                              build_Integer_times_node);
190         rb_iseq_t *tsiseq;
191         VALUE argv[2], val;
192
193         if (tsiseqval) {
194             rb_block_t block = *orig_block;
195             GetISeqPtr(tsiseqval, tsiseq);
196             block.iseq = tsiseq;
197             th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
198             argv[0] = INT2FIX(0);
199             argv[1] = num;
200             val = rb_yield_values(2, argv);
201             if (val == Qundef) {
202                 return num;
203             }
204             else {
205                 return val;
206             }
207         }
208     }
209     return Qundef;
210 }
211
212 static NODE *
213 build_Range_each_node(rb_iseq_t *iseq, NODE * node, NODE * lnode,
214                       VALUE param_vars, VALUE local_vars, ID mid)
215 {
216     /* Special Block for Range#each
217        {|e, _last|
218        _e = e
219        while _e < _last
220        e = _e
221        next_point:
222        BODY
223        redo_point:
224        _e = _e.succ
225        end
226        }
227        {|e, _last|
228        while e < _last
229        BODY
230        redo_point:
231        e = e.succ
232        end
233        }
234      */
235     ID _last;
236     CONST_ID(_last, "#_last");
237     if (iseq->argc == 0) {
238         ID e;
239         CONST_ID(e, "#e");
240         rb_ary_push(param_vars, ID2SYM(e));
241         rb_ary_push(param_vars, ID2SYM(_last));
242         iseq->argc += 2;
243
244         node =
245             NEW_WHILE(NEW_CALL(NEW_DVAR(e), mid, new_ary(NEW_DVAR(_last), 0)),
246                       new_block(NEW_OPTBLOCK(node),
247                                 NEW_DASGN(e,
248                                           NEW_CALL(NEW_DVAR(e), idSucc, 0))),
249                       Qundef);
250     }
251     else {
252         ID _e;
253         ID e = SYM2ID(rb_ary_entry(param_vars, 0));
254         NODE *assign;
255
256         CONST_ID(_e, "#_e");
257         rb_ary_push(param_vars, ID2SYM(_last));
258         rb_ary_push(local_vars, ID2SYM(_e));
259         iseq->argc++;
260
261         if (nd_type(lnode) == NODE_DASGN_CURR) {
262             assign = NEW_DASGN(e, NEW_DVAR(_e));
263         }
264         else {
265             assign = new_assign(lnode, NEW_DVAR(_e));
266         }
267
268         node =
269             new_block(NEW_DASGN(_e, NEW_DVAR(e)),
270                       NEW_WHILE(NEW_CALL
271                                 (NEW_DVAR(_e), mid,
272                                  new_ary(NEW_DVAR(_last), 0)),
273                                 new_block(assign,
274                                           new_block(NEW_OPTBLOCK(node),
275                                                     NEW_DASGN(_e,
276                                                               NEW_CALL
277                                                               (NEW_DVAR(_e),
278                                                                idSucc, 0)))),
279                                 Qundef));
280     }
281     return node;
282 }
283
284 static NODE *
285 build_Range_each_node_LE(rb_iseq_t *iseq, NODE * node, NODE * lnode,
286                          VALUE param_vars, VALUE local_vars)
287 {
288     return build_Range_each_node(iseq, node, lnode,
289                                  param_vars, local_vars, idLE);
290 }
291
292 static NODE *
293 build_Range_each_node_LT(rb_iseq_t *iseq, NODE * node, NODE * lnode,
294                          VALUE param_vars, VALUE local_vars)
295 {
296     return build_Range_each_node(iseq, node, lnode,
297                                  param_vars, local_vars, idLT);
298 }
299
300 VALUE
301 invoke_Range_each_special_block(VALUE range,
302                                 VALUE beg, VALUE end, int excl)
303 {
304     rb_thread_t *th = GET_THREAD();
305     rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
306
307     if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
308         void *builder =
309             excl ? build_Range_each_node_LT : build_Range_each_node_LE;
310         VALUE tsiseqval = iseq_special_block(orig_block->iseq, builder);
311         rb_iseq_t *tsiseq;
312         VALUE argv[2];
313
314         if (tsiseqval) {
315             VALUE val;
316             rb_block_t block = *orig_block;
317             GetISeqPtr(tsiseqval, tsiseq);
318             block.iseq = tsiseq;
319             th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
320             argv[0] = beg;
321             argv[1] = end;
322             val = rb_yield_values(2, argv);
323             if (val == Qundef) {
324                 return range;
325             }
326             else {
327                 return val;
328             }
329         }
330     }
331     return Qundef;
332 }
333
334
335 static NODE *
336 build_Array_each_node(rb_iseq_t *iseq, NODE * node, NODE * lnode,
337                       VALUE param_vars, VALUE local_vars)
338 {
339     /* Special block for Array#each
340        ary.each{|e|
341        BODY
342        }
343        =>
344        {|e, _self|
345        _i = 0
346        while _i < _self.length
347        e = _self[_i]
348        redo_point:
349        BODY
350        next_point:
351        _i = _i.succ
352        end
353        }
354
355        ary.each{
356        BODY
357        }
358        =>
359        {|_i, _self|
360        _i = 0
361        while _i < _self.length
362        redo_point:
363        BODY
364        next_point:
365        _i = _i.succ
366        end
367        }
368      */
369
370     ID _self, _i;
371
372     CONST_ID(_self, "#_self");
373     CONST_ID(_i, "#_i");
374     if (iseq->argc == 0) {
375         ID _e;
376         CONST_ID(_e, "#_e");
377         rb_ary_push(param_vars, ID2SYM(_e));
378         rb_ary_push(param_vars, ID2SYM(_self));
379         iseq->argc += 2;
380         rb_ary_push(local_vars, ID2SYM(_i));
381
382         node =
383             new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))),
384                       NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT,
385                                          new_ary(NEW_CALL
386                                                  (NEW_DVAR(_self), idLength,
387                                                   0), 0)),
388                                 new_block(NEW_OPTBLOCK(node),
389                                           NEW_DASGN(_i,
390                                                     NEW_CALL(NEW_DVAR(_i),
391                                                              idSucc, 0))),
392                                 Qundef));
393     }
394     else {
395         ID e = SYM2ID(rb_ary_entry(param_vars, 0));
396         NODE *assign;
397
398         rb_ary_push(param_vars, ID2SYM(_self));
399         iseq->argc++;
400         rb_ary_push(local_vars, ID2SYM(_i));
401
402         if (nd_type(lnode) == NODE_DASGN_CURR) {
403             assign = NEW_DASGN(e,
404                                NEW_CALL(NEW_DVAR(_self), idAREF,
405                                         new_ary(NEW_DVAR(_i), 0)));
406         }
407         else {
408             assign = new_assign(lnode,
409                                 NEW_CALL(NEW_DVAR(_self), idAREF,
410                                          new_ary(NEW_DVAR(_i), 0)));
411         }
412
413         node =
414             new_block(NEW_DASGN(_i, NEW_LIT(INT2FIX(0))),
415                       NEW_WHILE(NEW_CALL(NEW_DVAR(_i), idLT,
416                                          new_ary(NEW_CALL
417                                                  (NEW_DVAR(_self), idLength,
418                                                   0), 0)), new_block(assign,
419                                                                      new_block
420                                                                      (NEW_OPTBLOCK
421                                                                       (node),
422                                                                       NEW_DASGN
423                                                                       (_i,
424                                                                        NEW_CALL
425                                                                        (NEW_DVAR
426                                                                         (_i),
427                                                                         idSucc,
428                                                                         0)))),
429                                 Qundef));
430     }
431     return node;
432 }
433
434 VALUE
435 invoke_Array_each_special_block(VALUE ary)
436 {
437     rb_thread_t *th = GET_THREAD();
438     rb_block_t *orig_block = GC_GUARDED_PTR_REF(th->cfp->lfp[0]);
439
440     if (BUILTIN_TYPE(orig_block->iseq) != T_NODE) {
441         VALUE tsiseqval = iseq_special_block(orig_block->iseq,
442                                              build_Array_each_node);
443         rb_iseq_t *tsiseq;
444         VALUE argv[2];
445
446         if (tsiseqval) {
447             VALUE val;
448             rb_block_t block = *orig_block;
449             GetISeqPtr(tsiseqval, tsiseq);
450             block.iseq = tsiseq;
451             th->cfp->lfp[0] = GC_GUARDED_PTR(&block);
452             argv[0] = 0;
453             argv[1] = ary;
454             val = rb_yield_values(2, argv);
455             if (val == Qundef) {
456                 return ary;
457             }
458             else {
459                 return val;
460             }
461         }
462     }
463     return Qundef;
464 }