diff options
| -rw-r--r-- | doc/opcode.md | 1 | ||||
| -rw-r--r-- | include/mruby/ops.h | 1 | ||||
| -rw-r--r-- | mrbgems/mruby-compiler/core/codegen.c | 130 | ||||
| -rw-r--r-- | src/codedump.c | 6 | ||||
| -rw-r--r-- | src/vm.c | 7 |
5 files changed, 95 insertions, 50 deletions
diff --git a/doc/opcode.md b/doc/opcode.md index f6e3b7604..2a0363f55 100644 --- a/doc/opcode.md +++ b/doc/opcode.md @@ -98,6 +98,7 @@ sign) of operands. | `OP_ARRAY2` | `BBB` | `R(a) = ary_new(R(b),R(b+1)..R(b+c))` | | `OP_ARYCAT` | `B` | `ary_cat(R(a),R(a+1))` | | `OP_ARYPUSH` | `B` | `ary_push(R(a),R(a+1))` | +| `OP_ARYPUSH_N` | `BB` | `ary_push(R(a),R(a+1)..R(a+b))` | | `OP_ARYDUP` | `B` | `R(a) = ary_dup(R(a))` | | `OP_AREF` | `BBB` | `R(a) = R(b)[c]` | | `OP_ASET` | `BBB` | `R(a)[c] = R(b)` | diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 49b624ecb..8fe9e5df7 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -86,6 +86,7 @@ OPCODE(ARRAY, BB) /* R(a) = ary_new(R(a),R(a+1)..R(a+b)) */ OPCODE(ARRAY2, BBB) /* R(a) = ary_new(R(b),R(b+1)..R(b+c)) */ OPCODE(ARYCAT, B) /* ary_cat(R(a),R(a+1)) */ OPCODE(ARYPUSH, B) /* ary_push(R(a),R(a+1)) */ +OPCODE(ARYPUSH_N, BB) /* ary_push(R(a),R(a+1)..R(a+b)) */ OPCODE(ARYDUP, B) /* R(a) = ary_dup(R(a)) */ OPCODE(AREF, BBB) /* R(a) = R(b)[c] */ OPCODE(ASET, BBB) /* R(a)[c] = R(b) */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index d47661d65..6ba5de2b1 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -1483,59 +1483,75 @@ attrsym(codegen_scope *s, mrb_sym a) } #define CALL_MAXARGS 127 +#define GEN_LIT_ARY_MAX 255 static int -gen_values(codegen_scope *s, node *t, int val, int extra) +gen_values(codegen_scope *s, node *t, int val, int extra, int limit) { int n = 0; - int is_splat; + int first = 1; + + if (limit == 0) limit = GEN_LIT_ARY_MAX; + + if (!val) { + while (t) { + codegen(s, t->car, NOVAL); + n++; + t = t->cdr; + } + return n; + } while (t) { - is_splat = nint(t->car->car) == NODE_SPLAT; /* splat mode */ - if ( - n+extra >= CALL_MAXARGS - 1 /* need to subtract one because vm.c expects an array if n == CALL_MAXARGS */ - || is_splat) { - if (val) { - if (is_splat && n == 0 && nint(t->car->cdr->car) == NODE_ARRAY) { - codegen(s, t->car->cdr, VAL); - pop(); - t = t->cdr; + int is_splat = nint(t->car->car) == NODE_SPLAT; + + if (is_splat || n+extra >= limit-1) { /* flush stack */ + pop_n(n); + if (first) { + if (n == 0) { + genop_1(s, OP_LOADNIL, cursp()); } else { - pop_n(n); - if (n == 0 && is_splat) { - genop_1(s, OP_LOADNIL, cursp()); - } - else { - genop_2(s, OP_ARRAY, cursp(), n); - } - } - while (t) { - push(); - codegen(s, t->car, VAL); - pop(); pop(); - if (nint(t->car->car) == NODE_SPLAT) { - genop_1(s, OP_ARYCAT, cursp()); - } - else { - genop_1(s, OP_ARYPUSH, cursp()); - } - t = t->cdr; + genop_2(s, OP_ARRAY, cursp(), n); } + push(); + first = 0; } - else { - while (t) { - codegen(s, t->car, NOVAL); - t = t->cdr; + else if (n > 0) { + if (n == 1) { + genop_1(s, OP_ARYPUSH, cursp()); + } + else { + genop_2(s, OP_ARYPUSH_N, cursp(), n); } + push(); } - return -1; + n = 0; } - /* normal (no splat) mode */ codegen(s, t->car, val); - n++; + if (is_splat) { + pop(); pop(); + genop_1(s, OP_ARYCAT, cursp()); + push(); + } + else { + n++; + } t = t->cdr; } + if (!first) { + pop(); + if (n > 0) { + pop_n(n); + if (n == 1) { + genop_1(s, OP_ARYPUSH, cursp()); + } + else { + genop_2(s, OP_ARYPUSH_N, cursp(), n); + } + } + return -1; /* variable length */ + } return n; } @@ -1554,7 +1570,7 @@ gen_call(codegen_scope *s, node *tree, mrb_sym name, int sp, int val, int safe) } tree = tree->cdr->cdr->car; if (tree) { - n = gen_values(s, tree->car, VAL, sp?1:0); + n = gen_values(s, tree->car, VAL, sp?1:0, CALL_MAXARGS); if (n < 0) { n = noop = sendv = 1; push(); @@ -1777,7 +1793,7 @@ static void gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) { if (val) { - int i = 0, j = 0; + int i = 0, j = 0, gen = 0; while (tree) { switch (nint(tree->car->car)) { @@ -1805,6 +1821,19 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) push(); j--; } + if (i > GEN_LIT_ARY_MAX) { + pop_n(i); + if (gen) { + pop(); + genop_2(s, OP_ARYPUSH_N, cursp(), i); + } + else { + genop_2(s, OP_ARRAY, cursp(), i); + gen = 1; + } + push(); + i = 0; + } tree = tree->cdr; } if (j > 0) { @@ -1813,7 +1842,13 @@ gen_literal_array(codegen_scope *s, node *tree, mrb_bool sym, int val) gen_intern(s); } pop_n(i); - genop_2(s, OP_ARRAY, cursp(), i); + if (gen) { + pop(); + genop_2(s, OP_ARYPUSH_N, cursp(), i); + } + else { + genop_2(s, OP_ARRAY, cursp(), i); + } push(); } else { @@ -2353,15 +2388,12 @@ codegen(codegen_scope *s, node *tree, int val) { int n; - n = gen_values(s, tree, val, 0); - if (n >= 0) { - if (val) { + n = gen_values(s, tree, val, 0, 0); + if (val) { + if (n >= 0) { pop_n(n); genop_2(s, OP_ARRAY, cursp(), n); - push(); } - } - else if (val) { push(); } } @@ -2561,7 +2593,7 @@ codegen(codegen_scope *s, node *tree, int val) idx = new_sym(s, nsym(n->cdr->car)); base = cursp()-1; if (n->cdr->cdr->car) { - nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1); + nargs = gen_values(s, n->cdr->cdr->car->car, VAL, 1, CALL_MAXARGS); if (nargs >= 0) { callargs = nargs; } @@ -2694,7 +2726,7 @@ codegen(codegen_scope *s, node *tree, int val) if (tree) { node *args = tree->car; if (args) { - n = gen_values(s, args, VAL, 0); + n = gen_values(s, args, VAL, 0, CALL_MAXARGS); if (n < 0) { n = noop = sendv = 1; push(); @@ -2775,7 +2807,7 @@ codegen(codegen_scope *s, node *tree, int val) if (ainfo < 0) codegen_error(s, "invalid yield (SyntaxError)"); push(); if (tree) { - n = gen_values(s, tree, VAL, 0); + n = gen_values(s, tree, VAL, 0, CALL_MAXARGS); if (n < 0) { n = sendv = 1; push(); diff --git a/src/codedump.c b/src/codedump.c index 87faa589c..3128d7467 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -428,13 +428,17 @@ codedump(mrb_state *mrb, const mrb_irep *irep) print_lv_ab(mrb, irep, a, b); break; CASE(OP_ARYCAT, B): - printf("OP_ARYCAT\tR%d\t", a); + printf("OP_ARYCAT\tR%d\tR%d\t", a, a+1); print_lv_a(mrb, irep, a); break; CASE(OP_ARYPUSH, B): printf("OP_ARYPUSH\tR%d\t", a); print_lv_a(mrb, irep, a); break; + CASE(OP_ARYPUSH_N, BB): + printf("OP_ARYPUSH_N\tR%d\t%d\t", a, b); + print_lv_a(mrb, irep, a); + break; CASE(OP_ARYDUP, B): printf("OP_ARYDUP\tR%d\t", a); print_lv_a(mrb, irep, a); @@ -2551,6 +2551,13 @@ RETRY_TRY_BLOCK: NEXT; } + CASE(OP_ARYPUSH_N, BB) { + for (mrb_int i=0; i<b; i++) { + mrb_ary_push(mrb, regs[a], regs[a+i+1]); + } + NEXT; + } + CASE(OP_ARYDUP, B) { mrb_value ary = regs[a]; if (mrb_array_p(ary)) { |
