418 |
418 |
static int iseq_setup(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
|
419 |
419 |
static int iseq_optimize(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
|
420 |
420 |
static int iseq_insns_unification(rb_iseq_t *iseq, LINK_ANCHOR *anchor);
|
|
421 |
static int iseq_optimize_tailcall(rb_iseq_t *iseq);
|
421 |
422 |
|
422 |
423 |
static int iseq_set_local_table(rb_iseq_t *iseq, const ID *tbl);
|
423 |
424 |
static int iseq_set_exception_local_table(rb_iseq_t *iseq);
|
... | ... | |
1129 |
1130 |
debugs("[compile step 4.3 (set_optargs_table)] \n");
|
1130 |
1131 |
if (!iseq_set_optargs_table(iseq)) return COMPILE_NG;
|
1131 |
1132 |
|
|
1133 |
/* dirty hack: it have to look through catch table */
|
|
1134 |
if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization &&
|
|
1135 |
ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization)
|
|
1136 |
iseq_optimize_tailcall(iseq);
|
|
1137 |
|
1132 |
1138 |
debugs("[compile step 5 (iseq_translate_threaded_code)] \n");
|
1133 |
1139 |
if (!rb_iseq_translate_threaded_code(iseq)) return COMPILE_NG;
|
1134 |
1140 |
|
... | ... | |
1996 |
2002 |
}
|
1997 |
2003 |
|
1998 |
2004 |
static int
|
1999 |
|
iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list, const int do_tailcallopt)
|
|
2005 |
iseq_peephole_optimize(rb_iseq_t *iseq, LINK_ELEMENT *list)
|
2000 |
2006 |
{
|
2001 |
2007 |
INSN *iobj = (INSN *)list;
|
2002 |
2008 |
again:
|
... | ... | |
2212 |
2218 |
}
|
2213 |
2219 |
}
|
2214 |
2220 |
|
2215 |
|
if (do_tailcallopt &&
|
2216 |
|
(iobj->insn_id == BIN(send) ||
|
2217 |
|
iobj->insn_id == BIN(opt_aref_with) ||
|
2218 |
|
iobj->insn_id == BIN(opt_aset_with) ||
|
2219 |
|
iobj->insn_id == BIN(invokesuper))) {
|
2220 |
|
/*
|
2221 |
|
* send ...
|
2222 |
|
* leave
|
2223 |
|
* =>
|
2224 |
|
* send ..., ... | VM_CALL_TAILCALL, ...
|
2225 |
|
* leave # unreachable
|
2226 |
|
*/
|
2227 |
|
INSN *piobj = NULL;
|
2228 |
|
if (iobj->link.next) {
|
2229 |
|
LINK_ELEMENT *next = iobj->link.next;
|
2230 |
|
do {
|
2231 |
|
if (next->type != ISEQ_ELEMENT_INSN) {
|
2232 |
|
next = next->next;
|
2233 |
|
continue;
|
2234 |
|
}
|
2235 |
|
switch (INSN_OF(next)) {
|
2236 |
|
case BIN(nop):
|
2237 |
|
/*case BIN(trace):*/
|
2238 |
|
next = next->next;
|
2239 |
|
break;
|
2240 |
|
case BIN(leave):
|
2241 |
|
piobj = iobj;
|
2242 |
|
default:
|
2243 |
|
next = NULL;
|
2244 |
|
break;
|
2245 |
|
}
|
2246 |
|
} while (next);
|
2247 |
|
}
|
2248 |
|
|
2249 |
|
if (piobj) {
|
2250 |
|
struct rb_call_info *ci = (struct rb_call_info *)piobj->operands[0];
|
2251 |
|
if (piobj->insn_id == BIN(send) || piobj->insn_id == BIN(invokesuper)) {
|
2252 |
|
if (piobj->operands[2] == 0) { /* no blockiseq */
|
2253 |
|
ci->flag |= VM_CALL_TAILCALL;
|
2254 |
|
}
|
2255 |
|
}
|
2256 |
|
else {
|
2257 |
|
ci->flag |= VM_CALL_TAILCALL;
|
2258 |
|
}
|
2259 |
|
}
|
2260 |
|
}
|
2261 |
2221 |
return COMPILE_OK;
|
2262 |
2222 |
}
|
2263 |
2223 |
|
... | ... | |
2339 |
2299 |
{
|
2340 |
2300 |
LINK_ELEMENT *list;
|
2341 |
2301 |
const int do_peepholeopt = ISEQ_COMPILE_DATA(iseq)->option->peephole_optimization;
|
2342 |
|
const int do_tailcallopt = ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization;
|
2343 |
2302 |
const int do_si = ISEQ_COMPILE_DATA(iseq)->option->specialized_instruction;
|
2344 |
2303 |
const int do_ou = ISEQ_COMPILE_DATA(iseq)->option->operands_unification;
|
2345 |
2304 |
list = FIRST_ELEMENT(anchor);
|
... | ... | |
2347 |
2306 |
while (list) {
|
2348 |
2307 |
if (list->type == ISEQ_ELEMENT_INSN) {
|
2349 |
2308 |
if (do_peepholeopt) {
|
2350 |
|
iseq_peephole_optimize(iseq, list, do_tailcallopt);
|
|
2309 |
iseq_peephole_optimize(iseq, list);
|
2351 |
2310 |
}
|
2352 |
2311 |
if (do_si) {
|
2353 |
2312 |
iseq_specialized_instruction(iseq, (INSN *)list);
|
... | ... | |
3648 |
3607 |
return Qnil;
|
3649 |
3608 |
}
|
3650 |
3609 |
|
|
3610 |
static int
|
|
3611 |
iseq_optimize_tailcall(rb_iseq_t *iseq)
|
|
3612 |
{
|
|
3613 |
unsigned int i;
|
|
3614 |
VALUE *encoded = (VALUE *)iseq->body->iseq_encoded;
|
|
3615 |
const struct iseq_catch_table *table = iseq->body->catch_table;
|
|
3616 |
char *cmap;
|
|
3617 |
|
|
3618 |
/* rescue block can't tail call because of errinfo */
|
|
3619 |
if (iseq->body->type == ISEQ_TYPE_RESCUE || iseq->body->type == ISEQ_TYPE_ENSURE)
|
|
3620 |
return COMPILE_OK;
|
|
3621 |
|
|
3622 |
cmap = xcalloc(1, iseq->body->iseq_size);
|
|
3623 |
|
|
3624 |
if (table) {
|
|
3625 |
for (i = table->size; i-- > 0; ) {
|
|
3626 |
const struct iseq_catch_table_entry *entry = &table->entries[i];
|
|
3627 |
memset(cmap + entry->start, 1, entry->end - entry->start);
|
|
3628 |
}
|
|
3629 |
}
|
|
3630 |
|
|
3631 |
/*
|
|
3632 |
* send ...
|
|
3633 |
* leave
|
|
3634 |
* =>
|
|
3635 |
* send ..., ... | VM_CALL_TAILCALL, ...
|
|
3636 |
* leave # unreachable
|
|
3637 |
*/
|
|
3638 |
for (i = 0; i < iseq->body->iseq_size; ) {
|
|
3639 |
int insn = (int)encoded[i];
|
|
3640 |
int len = insn_len(insn);
|
|
3641 |
if (i + len >= iseq->body->iseq_size) break;
|
|
3642 |
|
|
3643 |
if (!cmap[i] && BIN(leave) == (int)encoded[i + len]) {
|
|
3644 |
struct rb_call_info *ci = (struct rb_call_info *)encoded[i + 1];
|
|
3645 |
switch (insn) {
|
|
3646 |
case BIN(invokesuper):
|
|
3647 |
case BIN(send):
|
|
3648 |
if (encoded[i + 3]) break; /* with block */
|
|
3649 |
case BIN(opt_aref_with):
|
|
3650 |
case BIN(opt_aset_with):
|
|
3651 |
case BIN(opt_send_without_block):
|
|
3652 |
case BIN(opt_length):
|
|
3653 |
case BIN(opt_size):
|
|
3654 |
case BIN(opt_empty_p):
|
|
3655 |
case BIN(opt_succ):
|
|
3656 |
case BIN(opt_not):
|
|
3657 |
case BIN(opt_plus):
|
|
3658 |
case BIN(opt_minus):
|
|
3659 |
case BIN(opt_mult):
|
|
3660 |
case BIN(opt_div):
|
|
3661 |
case BIN(opt_mod):
|
|
3662 |
case BIN(opt_eq):
|
|
3663 |
case BIN(opt_neq):
|
|
3664 |
case BIN(opt_lt):
|
|
3665 |
case BIN(opt_le):
|
|
3666 |
case BIN(opt_gt):
|
|
3667 |
case BIN(opt_ge):
|
|
3668 |
case BIN(opt_ltlt):
|
|
3669 |
case BIN(opt_aref):
|
|
3670 |
case BIN(opt_aset):
|
|
3671 |
ci->flag |= VM_CALL_TAILCALL;
|
|
3672 |
}
|
|
3673 |
}
|
|
3674 |
i += len;
|
|
3675 |
}
|
|
3676 |
|
|
3677 |
xfree(cmap);
|
|
3678 |
return COMPILE_OK;
|
|
3679 |
}
|
|
3680 |
|
3651 |
3681 |
/**
|
3652 |
3682 |
compile each node
|
3653 |
3683 |
|
... | ... | |
4318 |
4348 |
ADD_INSNL(ret, line, jump, label_miss);
|
4319 |
4349 |
ADD_LABEL(ret, label_hit);
|
4320 |
4350 |
COMPILE(ret, "resbody body", resq->nd_body);
|
4321 |
|
if (ISEQ_COMPILE_DATA(iseq)->option->tailcall_optimization) {
|
4322 |
|
ADD_INSN(ret, line, nop);
|
4323 |
|
}
|
4324 |
4351 |
ADD_INSN(ret, line, leave);
|
4325 |
4352 |
ADD_LABEL(ret, label_miss);
|
4326 |
4353 |
resq = resq->nd_head;
|