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