Skip to content

Commit

Permalink
Optimize for variable-length-arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
miura1729 committed Mar 7, 2015
1 parent f32393a commit c584ec1
Show file tree
Hide file tree
Showing 2 changed files with 180 additions and 1 deletion.
5 changes: 5 additions & 0 deletions src/codegen.c
Expand Up @@ -639,6 +639,11 @@ lambda_body(codegen_scope *s, node *tree, int blk)
| ((ra & 1) << 5)
| (pa & 0x1f);
genop(s, MKOP_Ax(OP_ENTER, a));
if (ra) {
size_t ppos = s->irep->plen;
s->irep->pool[ppos] = mrb_fixnum_value(0);
s->irep->plen++;
}
pos = new_label(s);
for (i=0; i<oa; i++) {
new_label(s);
Expand Down
176 changes: 175 additions & 1 deletion src/vm.c
Expand Up @@ -723,6 +723,144 @@ argnum_error(mrb_state *mrb, mrb_int num)

#define CALL_MAXARGS 127

int
mrb_check_export_reps(mrb_state *mrb, mrb_irep *irep, mrb_int drno, int level)
{
int i;
mrb_code *pc;
mrb_code ins;
for (i = 0; i < irep->rlen; i++) {
if (mrb_check_export_reps(mrb, irep->reps[i], drno, level + 1)) {
return 1;
}
}

for (i = 0, pc = irep->iseq; i < irep->ilen; i++, pc++) {
ins = *pc;
//disasm_once(mrb, irep, ins);
switch(GET_OPCODE(ins)) {
case OP_GETUPVAR:
case OP_SETUPVAR:
if (GETARG_B(ins) == drno && GETARG_C(ins) == level) {
return 1;
}
break;

default:
break;
}
}

return 0;
}

int
mrb_patch_irep_var2fix(mrb_state *mrb, mrb_irep *irep, mrb_int drno)
{
int i;
mrb_code *oiseq = irep->iseq;
mrb_code *pc;
mrb_code ins;
mrb_int tdrno = drno;

for (i = 0; i < irep->rlen; i++) {
if (mrb_check_export_reps(mrb, irep->reps[i], drno, 0)) {
return 0;
}
}

irep->iseq = (mrb_code*)mrb_malloc(mrb, sizeof(mrb_code)*irep->ilen);
for (i = 0, pc = oiseq; i < irep->ilen; i++, pc++) {
ins = *pc;
irep->iseq[i] = ins;

if (GET_OPCODE(ins) == OP_ARRAY &&
GET_OPCODE(*(pc + 1)) == OP_MOVE &&
GETARG_B(*(pc + 1)) == drno &&
GET_OPCODE(*(pc + 2)) == OP_ARYCAT &&
GET_OPCODE(*(pc + 3)) == OP_SEND &&
GETARG_C(*(pc + 3)) == 127) {

if (GETARG_C(ins) == 0) {
irep->iseq[i++] = MKOP_A(OP_NOP, 0);
pc++;
ins = *pc;
irep->iseq[i++] = MKOP_AB(OP_MOVE, GETARG_A(ins) - 1, GETARG_B(ins));
pc++;
irep->iseq[i++] = MKOP_A(OP_NOP, 0);
pc++;
ins = *pc;
irep->iseq[i] = MKOP_ABC(OP_SEND, GETARG_A(ins), GETARG_B(ins), 1);
}
else {
mrb_free(mrb, irep->iseq);
irep->iseq = oiseq;
return 0;
}
}

if (GET_OPCODE(ins) == OP_MOVE) {
if (GETARG_B(ins) == drno) {
tdrno = GETARG_A(ins);
}
else if (GETARG_A(ins) == drno) {
mrb_free(mrb, irep->iseq);
irep->iseq = oiseq;
return 0;
}
}

if (GET_OPCODE(ins) == OP_RETURN) {
if ( GETARG_A(ins) == tdrno
|| GETARG_A(ins) == drno) {
mrb_free(mrb, irep->iseq);
irep->iseq = oiseq;
return 0;
}
}

if (GET_OPCODE(ins) == OP_SEND &&
(GETARG_A(ins) == tdrno ||
(GETARG_C(ins) == 1 && GETARG_A(ins) + 1 == tdrno))) {
if (GETARG_C(ins) == 127) {
irep->iseq[i] = MKOP_ABC(OP_SEND, GETARG_A(ins), GETARG_B(ins), 1);
}
else if (strcmp(mrb_sym2name(mrb, irep->syms[GETARG_B(ins)]), "__svalue") == 0) {
irep->iseq[i] = MKOP_A(OP_NOP, 0);
}
else if (strcmp(mrb_sym2name(mrb, irep->syms[GETARG_B(ins)]), "size") == 0) {
irep->iseq[i] = MKOP_AB(OP_LOADI, tdrno, 1);
}
else if (strcmp(mrb_sym2name(mrb, irep->syms[GETARG_B(ins)]), "[]") == 0) {
irep->iseq[i] = MKOP_A(OP_NOP, 0);
}
else {
mrb_free(mrb, irep->iseq);
irep->iseq = oiseq;
return 0;
}
}
else {
switch (GET_OPCODE(ins)) {
case OP_SEND:
case OP_ARRAY:
case OP_HASH:
case OP_ADD:
case OP_SUB:
if (GETARG_A(ins) <= tdrno &&
tdrno <= GETARG_A(ins) + GETARG_C(ins)) {
mrb_free(mrb, irep->iseq);
irep->iseq = oiseq;
return 0;
}
break;
}
}
}

return 1;
}

MRB_API mrb_value
mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep)
{
Expand Down Expand Up @@ -1418,7 +1556,43 @@ mrb_context_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int
}
if (r) {
rnum = argc-m1-o-m2;
regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
if (rnum == 1) {
int ipos = 0;
mrb_irep *nirep = (mrb_irep *)mrb_fixnum(irep->pool[ipos]);
struct RProc *p;

if (nirep == NULL) {
mrb_irep *cirep = mrb_add_irep(mrb);
*cirep = *irep;
if (mrb_patch_irep_var2fix(mrb, cirep, m1 + o + 1)) {
p = mrb_proc_new(mrb, cirep);
p->flags = proc->flags;
p->body.irep->refcnt++;
p->target_class = proc->target_class;
p->env = proc->env;
irep->pool[ipos] = mrb_fixnum_value((mrb_int)cirep);
mrb->c->ci->proc = proc = p;
irep = cirep;
pc = cirep->iseq;
}
else {
regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
}
}
else {
p = mrb_proc_new(mrb, nirep);
p->flags = proc->flags;
p->body.irep->refcnt++;
p->target_class = proc->target_class;
p->env = proc->env;
mrb->c->ci->proc = proc = p;
irep = nirep;
pc = nirep->iseq;
}
}
else {
regs[m1+o+1] = mrb_ary_new_from_values(mrb, rnum, argv+m1+o);
}
}
if (m2) {
if (argc-m2 > m1) {
Expand Down

0 comments on commit c584ec1

Please sign in to comment.