ops.h: add `OP_ARYPUSH_N` instruction.
Add n elements at once. Reduces instructions for huge array
initialization. In addition, `gen_value` function in `codegen.c` was
refactored and clarified.
MODIFY
doc/opcode.md
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)` |

MODIFY
include/mruby/ops.h
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) */

MODIFY
mrbgems/mruby-compiler/core/codegen.c
mrbgems/mruby-compiler/core/codegen.c
@@ -1483,58 +1483,74 @@ 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) {
- 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();
+ codegen(s, t->car, NOVAL);
+ n++;
t = t->cdr;
}
- else {
+ return n;
+ }
+
+ while (t) {
+ int is_splat = nint(t->car->car) == NODE_SPLAT;
+
+ if (is_splat || n+extra >= limit-1) { /* flush stack */
pop_n(n);
- if (n == 0 && is_splat) {
+ if (first) {
+ if (n == 0) {
genop_1(s, OP_LOADNIL, cursp());
}
else {
genop_2(s, OP_ARRAY, cursp(), n);
}
+ push();
+ first = 0;
+ }
+ else if (n > 0) {
+ if (n == 1) {
+ genop_1(s, OP_ARYPUSH, cursp());
+ }
+ else {
+ genop_2(s, OP_ARYPUSH_N, cursp(), n);
}
- while (t) {
push();
- codegen(s, t->car, VAL);
+ }
+ n = 0;
+ }
+ codegen(s, t->car, val);
+ if (is_splat) {
pop(); pop();
- if (nint(t->car->car) == NODE_SPLAT) {
genop_1(s, OP_ARYCAT, cursp());
+ push();
}
else {
- genop_1(s, OP_ARYPUSH, cursp());
+ n++;
}
t = t->cdr;
}
+ if (!first) {
+ pop();
+ if (n > 0) {
+ pop_n(n);
+ if (n == 1) {
+ genop_1(s, OP_ARYPUSH, cursp());
}
else {
- while (t) {
- codegen(s, t->car, NOVAL);
- t = t->cdr;
- }
+ genop_2(s, OP_ARYPUSH_N, cursp(), n);
}
- return -1;
}
- /* normal (no splat) mode */
- codegen(s, t->car, val);
- n++;
- t = t->cdr;
+ 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);
+ 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) {
+ 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();

MODIFY
src/codedump.c
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);

MODIFY
src/vm.c
src/vm.c
@@ -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)) {

ops.h: add `OP_ARYPUSH_N` instruction.

Add n elements at once. Reduces instructions for huge array
initialization. In addition, `gen_value` function in `codegen.c` was
refactored and clarified.