GitHub

@@ -797,6 +797,97 @@ get_int_operand(codegen_scope *s, struct mrb_insn_data *data, mrb_int *n)

797797

}

798798

}

799799800+

static int new_lit_str2(codegen_scope *s, const char *str1, mrb_int len1, const char *str2, mrb_int len2);

801+802+

static void

803+

realloc_pool_str(codegen_scope *s, mrb_irep_pool *p, mrb_int len)

804+

{

805+

char *str;

806+

if ((p->tt & 3) == IREP_TT_SSTR) {

807+

str = codegen_realloc(s, NULL, len+1);

808+

}

809+

else {

810+

str = (char*)p->u.str;

811+

str = codegen_realloc(s, str, len+1);

812+

}

813+

p->tt = len<<2 | IREP_TT_STR;

814+

str[len] = '\0';

815+

p->u.str = (const char*)str;

816+

}

817+818+

static void

819+

free_pool_str(codegen_scope *s, mrb_irep_pool *p)

820+

{

821+

if ((p->tt & 3) != IREP_TT_SSTR) {

822+

codegen_realloc(s, (char*)p->u.str, 0);

823+

}

824+

p->u.str = NULL;

825+

s->irep->plen--;

826+

}

827+828+

static void

829+

merge_op_string(codegen_scope *s, uint16_t dst, uint16_t b1, uint16_t b2, const mrb_code *pc)

830+

{

831+

int used = 0;

832+

const mrb_code *i = s->iseq;

833+834+

/* scan OP_STRING that refers b1 or b2 */

835+

mrb_assert(pc < s->iseq + s->icapa);

836+

while (i<pc) {

837+

struct mrb_insn_data data = mrb_decode_insn(i);

838+

if (data.insn == OP_STRING) {

839+

if (data.b == b1) used |= 1;

840+

else if (data.b == b2) used |= 2;

841+

}

842+

switch (i[0]) {

843+

case OP_EXT1:

844+

i += mrb_insn_size1[i[1]] + 1;

845+

break;

846+

case OP_EXT2:

847+

i += mrb_insn_size2[i[1]] + 1;

848+

break;

849+

case OP_EXT3:

850+

i += mrb_insn_size3[i[1]] + 1;

851+

break;

852+

default:

853+

i += mrb_insn_size[i[0]];

854+

break;

855+

}

856+

}

857+858+

mrb_irep_pool *p1 = &s->pool[b1];

859+

mrb_irep_pool *p2 = &s->pool[b2];

860+

mrb_int len1 = p1->tt>>2;

861+

mrb_int len2 = p2->tt>>2;

862+

int off;

863+864+

switch (used) {

865+

case 0: /* both pools are free */

866+

case 2: /* b2 is referenced */

867+

/* overwrite p1; free b2 if possible */

868+

off = b1;

869+

realloc_pool_str(s, p1, len1+len2);

870+

memcpy((void*)p1->u.str+len1, (void*)p2->u.str, len2);

871+

if (used == 0 && b2+1 == s->irep->plen) {

872+

free_pool_str(s, p2);

873+

}

874+

break;

875+

case 1: /* b1 is referenced */

876+

/* overwrite p2 */

877+

off = b2;

878+

realloc_pool_str(s, p2, len1+len2);

879+

memmove((void*)p2->u.str+len1, (void*)p2->u.str, len2);

880+

memcpy((void*)p2->u.str, p1->u.str, len1);

881+

break;

882+

case 3: /* both b1&b2 are referenced */

883+

/* create new pool */

884+

off = new_lit_str2(s, p1->u.str, len1, p2->u.str, len2);

885+

break;

886+

}

887+

s->pc = addr_pc(s, pc);

888+

genop_2(s, OP_STRING, dst, off);

889+

}

890+800891

static void

801892

gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst)

802893

{

@@ -811,6 +902,13 @@ gen_addsub(codegen_scope *s, uint8_t op, uint16_t dst)

811902812903

if (!get_int_operand(s, &data, &n)) {

813904

/* not integer immediate */

905+

if (op == OP_ADD && data.insn == OP_STRING) {

906+

struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr));

907+

if (data0.insn == OP_STRING) {

908+

merge_op_string(s, dst, data0.b, data.b, data0.addr);

909+

return;

910+

}

911+

}

814912

goto normal;

815913

}

816914

struct mrb_insn_data data0 = mrb_decode_insn(mrb_prev_pc(s, data.addr));

@@ -2269,26 +2367,6 @@ gen_blkmove(codegen_scope *s, uint16_t ainfo, int lv)

22692367

push();

22702368

}

227123692272-

static int

2273-

opt_str_add(codegen_scope *s, node *tree)

2274-

{

2275-

/* optimize */

2276-

if (no_optimize(s)) return 0;

2277-

/* receiver is a string */

2278-

if (!tree->car || nint(tree->car->car) != NODE_STR) return 0;

2279-

/* + call */

2280-

if (!tree->cdr || nsym(tree->cdr->car) != MRB_OPSYM_2(s->mrb, add)) return 0;

2281-

/* valid arguments */

2282-

if (!tree->cdr->cdr || tree->cdr->cdr->cdr) return FALSE;

2283-

/* takes 1 argument */

2284-

if (!tree->cdr->cdr->car->car && tree->cdr->cdr->car->car->cdr) return 0;

2285-

/* valid 1st arguments */

2286-

if (!tree->cdr->cdr->car->car->car) return 0;

2287-

if (nint(tree->cdr->cdr->car->car->car->car) == NODE_STR) return 1;

2288-

// if (nint(tree->cdr->cdr->car->car->car->car) == NODE_CALL) return 2;

2289-

return 0;

2290-

}

2291-22922370

static void

22932371

codegen(codegen_scope *s, node *tree, int val)

22942372

{

@@ -2701,17 +2779,6 @@ codegen(codegen_scope *s, node *tree, int val)

27012779

break;

2702278027032781

case NODE_CALL:

2704-

if (opt_str_add(s, tree)) {

2705-

if (val) {

2706-

node *n1 = tree->car->cdr;

2707-

node *n2 = tree->cdr->cdr->car->car->car->cdr;

2708-

int off = new_lit_str2(s, (char*)n1->car, nint(n1->cdr), (char*)n2->car, nint(n2->cdr));

2709-

genop_2(s, OP_STRING, cursp(), off);

2710-

push();

2711-

}

2712-

break;

2713-

}

2714-

/* fall through */

27152782

case NODE_FCALL:

27162783

gen_call(s, tree, val, 0);

27172784

break;

Read the original on github.com ↗