From 5a3e014e4914dbd6421dbbd81e889cd6952e924b Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Fri, 5 Jun 2020 07:43:40 +0900 Subject: Constify `irep` members. - `pool` - `syms` - `reps` --- src/state.c | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) (limited to 'src/state.c') diff --git a/src/state.c b/src/state.c index 790f7ca13..323532363 100644 --- a/src/state.c +++ b/src/state.c @@ -107,12 +107,14 @@ void mrb_free_symtbl(mrb_state *mrb); void mrb_irep_incref(mrb_state *mrb, mrb_irep *irep) { + if (irep->flags & MRB_IREP_NO_FREE) return; irep->refcnt++; } void mrb_irep_decref(mrb_state *mrb, mrb_irep *irep) { + if (irep->flags & MRB_IREP_NO_FREE) return; irep->refcnt--; if (irep->refcnt == 0) { mrb_irep_free(mrb, irep); @@ -122,12 +124,14 @@ mrb_irep_decref(mrb_state *mrb, mrb_irep *irep) void mrb_irep_cutref(mrb_state *mrb, mrb_irep *irep) { - mrb_irep *tmp; + mrb_irep **reps; int i; + if (irep->flags & MRB_IREP_NO_FREE) return; + reps = (mrb_irep**)irep->reps; for (i=0; irlen; i++) { - tmp = irep->reps[i]; - irep->reps[i] = NULL; + mrb_irep *tmp = reps[i]; + reps[i] = NULL; if (tmp) mrb_irep_decref(mrb, tmp); } } @@ -137,6 +141,7 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) { int i; + if (irep->flags & MRB_IREP_NO_FREE) return; if (!(irep->flags & MRB_ISEQ_NO_FREE)) mrb_free(mrb, (void*)irep->iseq); if (irep->pool) for (i=0; iplen; i++) { @@ -150,16 +155,16 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) } #endif } - mrb_free(mrb, irep->pool); - mrb_free(mrb, irep->syms); + mrb_free(mrb, (void*)irep->pool); + mrb_free(mrb, (void*)irep->syms); if (irep->reps) { for (i=0; irlen; i++) { if (irep->reps[i]) - mrb_irep_decref(mrb, irep->reps[i]); + mrb_irep_decref(mrb, (mrb_irep*)irep->reps[i]); } + mrb_free(mrb, (void*)irep->reps); } - mrb_free(mrb, irep->reps); - mrb_free(mrb, irep->lv); + mrb_free(mrb, (void*)irep->lv); mrb_debug_info_free(mrb, irep->debug_info); mrb_free(mrb, irep); } -- cgit v1.2.3 From d428fa0c4acfe4f70ab534d420052c193bd83281 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 9 Jun 2020 14:39:38 +0900 Subject: Replace entire `irep->pool`. Changes: - `pool format is completely replaced - supported types: `STR`, `INT32`, `INT64`, `FLOAT` - `FLOAT` may be replaced by binary representation in the future - insert `NUL` after string literals in `mrb` files - `irep->pool` no longer store values in `mrb_value` - instead it stores in `mrb_pool_value` - less allocation - `mrb_irep` can be stored in ROM --- include/mruby/boxing_nan.h | 2 - include/mruby/boxing_no.h | 4 -- include/mruby/boxing_word.h | 5 -- include/mruby/dump.h | 19 ------ include/mruby/irep.h | 26 +++++-- include/mruby/string.h | 10 +-- mrbgems/mruby-compiler/core/codegen.c | 62 ++++++++++++----- src/codedump.c | 37 ++++++---- src/dump.c | 123 ++++++++++++++++++++-------------- src/etc.c | 11 --- src/load.c | 77 ++++++++++++++------- src/state.c | 16 ++--- src/string.c | 26 ------- src/vm.c | 43 +++++++----- 14 files changed, 251 insertions(+), 210 deletions(-) (limited to 'src/state.c') diff --git a/include/mruby/boxing_nan.h b/include/mruby/boxing_nan.h index fae3b7630..4b44bba8a 100644 --- a/include/mruby/boxing_nan.h +++ b/include/mruby/boxing_nan.h @@ -51,8 +51,6 @@ typedef struct mrb_value { }; } mrb_value; -#define mrb_float_pool(mrb,f) mrb_float_value(mrb,f) - #define mrb_tt(o) ((enum mrb_vtype)(((o).value.ttt & 0xfc000)>>14)-1) #define mrb_type(o) (enum mrb_vtype)((uint32_t)0xfff00000 < (o).value.ttt ? mrb_tt(o) : MRB_TT_FLOAT) #define mrb_ptr(o) ((void*)((((uintptr_t)0x3fffffffffff)&((uintptr_t)((o).value.p)))<<2)) diff --git a/include/mruby/boxing_no.h b/include/mruby/boxing_no.h index 7573428e6..23b48c6f8 100644 --- a/include/mruby/boxing_no.h +++ b/include/mruby/boxing_no.h @@ -24,10 +24,6 @@ typedef struct mrb_value { enum mrb_vtype tt; } mrb_value; -#ifndef MRB_WITHOUT_FLOAT -#define mrb_float_pool(mrb,f) mrb_float_value(mrb,f) -#endif - #define mrb_ptr(o) (o).value.p #define mrb_cptr(o) mrb_ptr(o) #ifndef MRB_WITHOUT_FLOAT diff --git a/include/mruby/boxing_word.h b/include/mruby/boxing_word.h index 1b7815b7f..56202a420 100644 --- a/include/mruby/boxing_word.h +++ b/include/mruby/boxing_word.h @@ -90,11 +90,6 @@ typedef union mrb_value { MRB_API mrb_value mrb_word_boxing_cptr_value(struct mrb_state*, void*); #ifndef MRB_WITHOUT_FLOAT MRB_API mrb_value mrb_word_boxing_float_value(struct mrb_state*, mrb_float); -MRB_API mrb_value mrb_word_boxing_float_pool(struct mrb_state*, mrb_float); -#endif - -#ifndef MRB_WITHOUT_FLOAT -#define mrb_float_pool(mrb,f) mrb_word_boxing_float_pool(mrb,f) #endif #define mrb_ptr(o) (o).value.p diff --git a/include/mruby/dump.h b/include/mruby/dump.h index 384521c45..bad27fdf5 100644 --- a/include/mruby/dump.h +++ b/include/mruby/dump.h @@ -127,16 +127,6 @@ uint32_to_bin(uint32_t l, uint8_t *bin) return sizeof(uint32_t); } -static inline size_t -uint32l_to_bin(uint32_t l, uint8_t *bin) -{ - bin[3] = (l >> 24) & 0xff; - bin[2] = (l >> 16) & 0xff; - bin[1] = (l >> 8) & 0xff; - bin[0] = l & 0xff; - return sizeof(uint32_t); -} - static inline uint32_t bin_to_uint32(const uint8_t *bin) { @@ -146,15 +136,6 @@ bin_to_uint32(const uint8_t *bin) (uint32_t)bin[3]; } -static inline uint32_t -bin_to_uint32l(const uint8_t *bin) -{ - return (uint32_t)bin[3] << 24 | - (uint32_t)bin[2] << 16 | - (uint32_t)bin[1] << 8 | - (uint32_t)bin[0]; -} - static inline uint16_t bin_to_uint16(const uint8_t *bin) { diff --git a/include/mruby/irep.h b/include/mruby/irep.h index 9d30f2797..359fb6796 100644 --- a/include/mruby/irep.h +++ b/include/mruby/irep.h @@ -16,11 +16,29 @@ MRB_BEGIN_DECL enum irep_pool_type { - IREP_TT_STRING, - IREP_TT_FIXNUM, - IREP_TT_FLOAT, + IREP_TT_STR = 0, /* string (need free) */ + IREP_TT_SSTR = 2, /* string (static) */ + IREP_TT_INT32 = 1, /* 32bit integer */ + IREP_TT_INT64 = 3, /* 64bit integer */ + IREP_TT_FLOAT = 5, /* float (double/float) */ }; +#define IREP_TT_NFLAG 1 /* number (non string) flag */ +#define IREP_TT_SFLAG 2 /* static string flag */ +#define IREP_TT_SFLAG 2 /* static string flag */ + +typedef struct mrb_pool_value { + uint32_t tt; /* packed type and length (for string) */ + union { + const char *str; + int32_t i32; +#ifdef MRB_INT64 + int64_t i64; +#endif + mrb_float f; + } u; +} mrb_pool_value; + struct mrb_lvinfo { /* local variable info (name, idx) */ mrb_sym name; uint16_t r; @@ -33,7 +51,7 @@ typedef struct mrb_irep { uint8_t flags; const mrb_code *iseq; - const mrb_value *pool; + const mrb_pool_value *pool; const mrb_sym *syms; const struct mrb_irep **reps; diff --git a/include/mruby/string.h b/include/mruby/string.h index 93c94ef5d..0f1b762c1 100644 --- a/include/mruby/string.h +++ b/include/mruby/string.h @@ -92,9 +92,6 @@ struct RStringEmbed { # define RSTR_COPY_ASCII_FLAG(dst, src) (void)0 #endif -#define RSTR_POOL_P(s) ((s)->flags & MRB_STR_POOL) -#define RSTR_SET_POOL_FLAG(s) ((s)->flags |= MRB_STR_POOL) - /** * Returns a pointer from a Ruby string */ @@ -112,13 +109,11 @@ MRB_API mrb_int mrb_str_strlen(mrb_state*, struct RString*); #define MRB_STR_FSHARED 2 #define MRB_STR_NOFREE 4 #define MRB_STR_EMBED 8 /* type flags up to here */ -#define MRB_STR_POOL 16 /* status flags from here */ -#define MRB_STR_ASCII 32 +#define MRB_STR_ASCII 16 #define MRB_STR_EMBED_LEN_SHIFT 6 #define MRB_STR_EMBED_LEN_BIT 5 #define MRB_STR_EMBED_LEN_MASK (((1 << MRB_STR_EMBED_LEN_BIT) - 1) << MRB_STR_EMBED_LEN_SHIFT) -#define MRB_STR_TYPE_MASK (MRB_STR_POOL - 1) - +#define MRB_STR_TYPE_MASK 15 void mrb_gc_free_str(mrb_state*, struct RString*); @@ -447,7 +442,6 @@ MRB_API int mrb_str_cmp(mrb_state *mrb, mrb_value str1, mrb_value str2); */ MRB_API char *mrb_str_to_cstr(mrb_state *mrb, mrb_value str); -mrb_value mrb_str_pool(mrb_state *mrb, const char *s, mrb_int len, mrb_bool nofree); uint32_t mrb_str_hash(mrb_state *mrb, mrb_value str); mrb_value mrb_str_dump(mrb_state *mrb, mrb_value str); diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index f8561c0e7..0000e6dbe 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -70,7 +70,7 @@ typedef struct scope { uint32_t icapa; mrb_irep *irep; - mrb_value *pool; + mrb_pool_value *pool; mrb_sym *syms; mrb_irep **reps; uint32_t pcapa, scapa, rcapa; @@ -554,17 +554,17 @@ static inline int new_lit(codegen_scope *s, mrb_value val) { int i; - mrb_value *pv; + mrb_pool_value *pv; switch (mrb_type(val)) { case MRB_TT_STRING: for (i=0; iirep->plen; i++) { mrb_int len; pv = &s->pool[i]; - - if (!mrb_string_p(*pv)) continue; - if ((len = RSTRING_LEN(*pv)) != RSTRING_LEN(val)) continue; - if (memcmp(RSTRING_PTR(*pv), RSTRING_PTR(val), len) == 0) + if (pv->tt & IREP_TT_NFLAG) continue; + len = pv->tt>>2; + if (RSTRING_LEN(val) != len) continue; + if (memcmp(pv->u.str, RSTRING_PTR(val), len) == 0) return i; } break; @@ -573,8 +573,9 @@ new_lit(codegen_scope *s, mrb_value val) for (i=0; iirep->plen; i++) { mrb_float f1, f2; pv = &s->pool[i]; - if (!mrb_float_p(*pv)) continue; - f1 = mrb_float(*pv); + if (pv->tt != IREP_TT_FLOAT) continue; + pv = &s->pool[i]; + f1 = pv->u.f; f2 = mrb_float(val); if (f1 == f2 && !signbit(f1) == !signbit(f2)) return i; } @@ -582,9 +583,17 @@ new_lit(codegen_scope *s, mrb_value val) #endif case MRB_TT_FIXNUM: for (i=0; iirep->plen; i++) { + mrb_int v = mrb_fixnum(val); pv = &s->pool[i]; - if (!mrb_fixnum_p(*pv)) continue; - if (mrb_fixnum(*pv) == mrb_fixnum(val)) return i; + if (pv->tt == IREP_TT_INT32) { + if (v == pv->u.i32) return i; + } +#ifdef MRB_INT64 + else if (pv->tt == IREP_TT_INT64) { + if (v == pv->u.i64) return i; + } + continue; +#endif } break; default: @@ -594,7 +603,7 @@ new_lit(codegen_scope *s, mrb_value val) if (s->irep->plen == s->pcapa) { s->pcapa *= 2; - s->pool = (mrb_value *)codegen_realloc(s, s->pool, sizeof(mrb_value)*s->pcapa); + s->pool = (mrb_pool_value*)codegen_realloc(s, s->pool, sizeof(mrb_pool_value)*s->pcapa); } pv = &s->pool[s->irep->plen]; @@ -602,18 +611,35 @@ new_lit(codegen_scope *s, mrb_value val) switch (mrb_type(val)) { case MRB_TT_STRING: - *pv = mrb_str_pool(s->mrb, RSTRING_PTR(val), RSTRING_LEN(val), RSTR_NOFREE_P(RSTRING(val))); + if (RSTR_NOFREE_P(RSTRING(val))) { + pv->tt = (RSTRING_LEN(val)<<2) | IREP_TT_SSTR; + pv->u.str = RSTRING_PTR(val); + } + else { + char *p; + mrb_int len = RSTRING_LEN(val); + pv->tt = (len<<2) | IREP_TT_STR; + p = (char*)codegen_realloc(s, NULL, len+1); + memcpy(p, RSTRING_PTR(val), len); + p[len] = '\0'; + pv->u.str = p; + } break; #ifndef MRB_WITHOUT_FLOAT case MRB_TT_FLOAT: -#ifdef MRB_WORD_BOXING - *pv = mrb_float_pool(s->mrb, mrb_float(val)); + pv->tt = IREP_TT_FLOAT; + pv->u.f = mrb_float(val); break; -#endif #endif case MRB_TT_FIXNUM: - *pv = val; +#ifdef MRB_INT64 + pv->tt = IREP_TT_INT64; + pv->u.i64 = mrb_fixnum(val); +#else + pv->tt = IREP_TT_INT32; + pv->u.i32 = mrb_fixnum(val); +#endif break; default: @@ -3045,7 +3071,7 @@ scope_new(mrb_state *mrb, codegen_scope *prev, node *nlv) s->irep->iseq = NULL; s->pcapa = 32; - s->pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*s->pcapa); + s->pool = (mrb_pool_value*)mrb_malloc(mrb, sizeof(mrb_pool_value)*s->pcapa); s->irep->plen = 0; s->scapa = 256; @@ -3110,7 +3136,7 @@ scope_finish(codegen_scope *s) irep->iseq = (const mrb_code *)codegen_realloc(s, s->iseq, sizeof(mrb_code)*s->pc); irep->ilen = s->pc; } - irep->pool = (const mrb_value*)codegen_realloc(s, s->pool, sizeof(mrb_value)*irep->plen); + irep->pool = (const mrb_pool_value*)codegen_realloc(s, s->pool, sizeof(mrb_pool_value)*irep->plen); irep->syms = (const mrb_sym*)codegen_realloc(s, s->syms, sizeof(mrb_sym)*irep->slen); irep->reps = (const mrb_irep**)codegen_realloc(s, s->reps, sizeof(mrb_irep*)*irep->rlen); if (s->filename_sym) { diff --git a/src/codedump.c b/src/codedump.c index 14cca8553..fd73f3104 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -115,10 +115,21 @@ codedump(mrb_state *mrb, const mrb_irep *irep) print_lv_ab(mrb, irep, a, b); break; CASE(OP_LOADL, BB): - { - mrb_value v = irep->pool[b]; - mrb_value s = mrb_inspect(mrb, v); - printf("OP_LOADL\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); + switch (irep->pool[b].tt) { + case IREP_TT_FLOAT: + printf("OP_LOADL\tR%d\tL(%d)\t; %f", a, b, (double)irep->pool[b].u.f); + break; + case IREP_TT_INT32: + printf("OP_LOADL\tR%d\tL(%d)\t; %" PRId32, a, b, irep->pool[b].u.i32); + break; +#ifdef MRB_INT64 + case IREP_TT_INT64: + printf("OP_LOADL\tR%d\tL(%d)\t; %" PRId64, a, b, irep->pool[b].u.i64); + break; +#endif + default: + printf("OP_LOADL\tR%d\tL(%d)\t", a, b); + break; } print_lv_a(mrb, irep, a); break; @@ -404,10 +415,11 @@ codedump(mrb_state *mrb, const mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_STRING, BB): - { - mrb_value v = irep->pool[b]; - mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); - printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, RSTRING_PTR(s)); + if ((irep->pool[b].tt & IREP_TT_NFLAG) == 0) { + printf("OP_STRING\tR%d\tL(%d)\t; %s", a, b, irep->pool[b].u.str); + } + else { + printf("OP_STRING\tR%d\tL(%d)\t", a, b); } print_lv_a(mrb, irep, a); break; @@ -453,10 +465,11 @@ codedump(mrb_state *mrb, const mrb_irep *irep) print_lv_a(mrb, irep, a); break; CASE(OP_ERR, B): - { - mrb_value v = irep->pool[a]; - mrb_value s = mrb_str_dump(mrb, mrb_str_new(mrb, RSTRING_PTR(v), RSTRING_LEN(v))); - printf("OP_ERR\t%s\n", RSTRING_PTR(s)); + if ((irep->pool[a].tt & IREP_TT_NFLAG) == 0) { + printf("OP_ERR\t%s\n", irep->pool[a].u.str); + } + else { + printf("OP_ERR\tL(%d)\n", a); } break; CASE(OP_EPUSH, B): diff --git a/src/dump.c b/src/dump.c index 093e4c256..a1c539e50 100644 --- a/src/dump.c +++ b/src/dump.c @@ -90,14 +90,12 @@ write_iseq_block(mrb_state *mrb, const mrb_irep *irep, uint8_t *buf, uint8_t fla #ifndef MRB_WITHOUT_FLOAT static mrb_value -float_to_str(mrb_state *mrb, mrb_value flt) +float_to_str(mrb_state *mrb, mrb_float f) { - mrb_float f = mrb_float(flt); - if (isinf(f)) { return f < 0 ? mrb_str_new_lit(mrb, "I") : mrb_str_new_lit(mrb, "i"); } - return mrb_float_to_str(mrb, flt, MRB_FLOAT_FMT); + return mrb_float_to_str(mrb, mrb_float_value(mrb, f), MRB_FLOAT_FMT); } #endif @@ -106,45 +104,50 @@ get_pool_block_size(mrb_state *mrb, const mrb_irep *irep) { int pool_no; size_t size = 0; - mrb_value str; - size += sizeof(uint32_t); /* plen */ - size += irep->plen * (sizeof(uint8_t) + sizeof(uint16_t)); /* len(n) */ + size += sizeof(uint16_t); /* plen */ + size += irep->plen * sizeof(uint8_t); /* len(n) */ for (pool_no = 0; pool_no < irep->plen; pool_no++) { int ai = mrb_gc_arena_save(mrb); - switch (mrb_type(irep->pool[pool_no])) { - case MRB_TT_FIXNUM: - str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10); + switch (irep->pool[pool_no].tt) { + case IREP_TT_INT64: +#ifdef MRB_INT64 { - mrb_int len = RSTRING_LEN(str); - mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); - size += (size_t)len; + int64_t i = irep->pool[pool_no].u.i64; + + if (i < INT32_MIN || INT32_MAX < i) + size += 8; + else + size += 4; } break; +#else + /* fall through */ +#endif + case IREP_TT_INT32: + size += 4; /* 32bits = 4bytes */ + break; + case IREP_TT_FLOAT: #ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: - str = float_to_str(mrb, irep->pool[pool_no]); { + mrb_value str = float_to_str(mrb, irep->pool[pool_no].u.f); mrb_int len = RSTRING_LEN(str); mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); size += (size_t)len; } - break; #endif + break; - case MRB_TT_STRING: + default: /* packed IREP_TT_STRING */ { - mrb_int len = RSTRING_LEN(irep->pool[pool_no]); + mrb_int len = irep->pool[pool_no].tt >> 1; /* unpack length */ mrb_assert_int_fit(mrb_int, len, size_t, SIZE_MAX); - size += (size_t)len; + size += (size_t)len+1; } break; - - default: - break; } mrb_gc_arena_restore(mrb, ai); } @@ -157,48 +160,64 @@ write_pool_block(mrb_state *mrb, const mrb_irep *irep, uint8_t *buf) { int pool_no; uint8_t *cur = buf; - uint16_t len; - mrb_value str; - const char *char_ptr; + int len; + const char *ptr; - cur += uint32_to_bin(irep->plen, cur); /* number of pool */ + cur += uint16_to_bin(irep->plen, cur); /* number of pool */ for (pool_no = 0; pool_no < irep->plen; pool_no++) { int ai = mrb_gc_arena_save(mrb); - switch (mrb_type(irep->pool[pool_no])) { - case MRB_TT_FIXNUM: - cur += uint8_to_bin(IREP_TT_FIXNUM, cur); /* data type */ - str = mrb_fixnum_to_str(mrb, irep->pool[pool_no], 10); + switch (irep->pool[pool_no].tt) { +#ifdef MRB_INT64 + case IREP_TT_INT64: + { + int64_t i = irep->pool[pool_no].u.i64; + if (i < INT32_MIN || INT32_MAX < i) { + cur += uint8_to_bin(IREP_TT_INT64, cur); /* data type */ + cur += uint32_to_bin((uint32_t)((i>>32) & 0xffffffff), cur); /* i64 hi */ + cur += uint32_to_bin((uint32_t)((i ) & 0xffffffff), cur); /* i64 lo */ + } + else { + cur += uint8_to_bin(IREP_TT_INT32, cur); /* data type */ + cur += uint32_to_bin(irep->pool[pool_no].u.i32, cur); /* i32 */ + } + } + break; +#endif + case IREP_TT_INT32: + cur += uint8_to_bin(IREP_TT_INT32, cur); /* data type */ + cur += uint32_to_bin(irep->pool[pool_no].u.i32, cur); /* i32 */ break; -#ifndef MRB_WITHOUT_FLOAT - case MRB_TT_FLOAT: + case IREP_TT_FLOAT: cur += uint8_to_bin(IREP_TT_FLOAT, cur); /* data type */ - str = float_to_str(mrb, irep->pool[pool_no]); - break; +#ifndef MRB_WITHOUT_FLOAT + { + mrb_value str = float_to_str(mrb, irep->pool[pool_no].u.f); + ptr = RSTRING_PTR(str); + len = RSTRING_LEN(str); + mrb_assert_int_fit(mrb_int, len, uint16_t, UINT16_MAX); + cur += uint16_to_bin((uint16_t)len, cur); /* data length */ + memcpy(cur, ptr, (size_t)len); + cur += len; + } +#else + cur += uint16_to_bin(0, cur); /* zero length */ #endif - - case MRB_TT_STRING: - cur += uint8_to_bin(IREP_TT_STRING, cur); /* data type */ - str = irep->pool[pool_no]; break; - default: - continue; - } - - char_ptr = RSTRING_PTR(str); - { - mrb_int tlen = RSTRING_LEN(str); - mrb_assert_int_fit(mrb_int, tlen, uint16_t, UINT16_MAX); - len = (uint16_t)tlen; + default: /* string */ + cur += uint8_to_bin(IREP_TT_STR, cur); /* data type */ + ptr = irep->pool[pool_no].u.str; + len = irep->pool[pool_no].tt>>2; + mrb_assert_int_fit(mrb_int, len, uint16_t, UINT16_MAX); + cur += uint16_to_bin((uint16_t)len, cur); /* data length */ + memcpy(cur, ptr, (size_t)len); + cur += len; + *cur++ = '\0'; + break; } - - cur += uint16_to_bin(len, cur); /* data length */ - memcpy(cur, char_ptr, (size_t)len); - cur += len; - mrb_gc_arena_restore(mrb, ai); } diff --git a/src/etc.c b/src/etc.c index 74b9ab03b..99cdc0157 100644 --- a/src/etc.c +++ b/src/etc.c @@ -158,17 +158,6 @@ mrb_word_boxing_float_value(mrb_state *mrb, mrb_float f) MRB_SET_FROZEN_FLAG(v.value.bp); return v; } - -MRB_API mrb_value -mrb_word_boxing_float_pool(mrb_state *mrb, mrb_float f) -{ - struct RFloat *nf = (struct RFloat *)mrb_malloc(mrb, sizeof(struct RFloat)); - nf->tt = MRB_TT_FLOAT; - nf->c = mrb->float_class; - nf->f = f; - MRB_SET_FROZEN_FLAG(nf); - return mrb_obj_value(nf); -} #endif /* MRB_WITHOUT_FLOAT */ #endif /* MRB_WORD_BOXING */ diff --git a/src/load.c b/src/load.c index d47027350..39644c34b 100644 --- a/src/load.c +++ b/src/load.c @@ -73,10 +73,10 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag uint16_t tt, pool_data_len, snl; int plen; struct RData *irep_obj = mrb_data_object_alloc(mrb, mrb->object_class, NULL, &tempirep_type); - mrb_value *pool; + mrb_pool_value *pool; mrb_sym *syms; + mrb_int ai = mrb_gc_arena_save(mrb); mrb_irep *irep = mrb_add_irep(mrb); - int ai = mrb_gc_arena_save(mrb); irep_obj->data = irep; @@ -120,51 +120,81 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag } /* POOL BLOCK */ - plen = bin_to_uint32(src); /* number of pool */ - src += sizeof(uint32_t); + plen = bin_to_uint16(src); /* number of pool */ + src += sizeof(uint16_t); if (plen > 0) { if (SIZE_ERROR_MUL(plen, sizeof(mrb_value))) { return NULL; } - irep->pool = pool = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value) * plen); + irep->pool = pool = (mrb_pool_value*)mrb_calloc(mrb, sizeof(mrb_pool_value), plen); for (i = 0; i < plen; i++) { - const char *s; mrb_bool st = (flags & FLAG_SRC_MALLOC)==0; tt = *src++; /* pool TT */ - pool_data_len = bin_to_uint16(src); /* pool data length */ - src += sizeof(uint16_t); - s = (const char*)src; - src += pool_data_len; switch (tt) { /* pool data */ - case IREP_TT_FIXNUM: { - mrb_value num = mrb_str_len_to_inum(mrb, s, pool_data_len, 10, FALSE); -#ifdef MRB_WITHOUT_FLOAT - pool[i] = num; + case IREP_TT_INT32: + { + mrb_int v = (int32_t)bin_to_uint32(src); + src += sizeof(uint32_t); +#ifdef MRB_INT64 + pool[i].tt = IREP_TT_INT64; + pool[i].u.i64 = (int64_t)v; #else - pool[i] = mrb_float_p(num)? mrb_float_pool(mrb, mrb_float(num)) : num; + pool[i].tt = IREP_TT_INT32; + pool[i].u.i32 = v; #endif } break; + case IREP_TT_INT64: +#ifdef MRB_INT64 + { + uint64_t i = bin_to_uint32(src); + src += sizeof(uint32_t); + i <<= 32; + i |= bin_to_uint32(src); + src += sizeof(uint32_t); + pool[i].u.i64 = (int64_t)i; + } +#else + return NULL; /* INT64 not supported on MRB_INT32 */ +#endif + break; -#ifndef MRB_WITHOUT_FLOAT case IREP_TT_FLOAT: - pool[i] = mrb_float_pool(mrb, str_to_double(mrb, s, pool_data_len)); +#ifndef MRB_WITHOUT_FLOAT + pool[i].tt = tt; + pool_data_len = bin_to_uint16(src); /* pool data length */ + src += sizeof(uint16_t); + pool[i].u.f = str_to_double(mrb, (const char*)src, pool_data_len); + src += pool_data_len; break; +#else + return NULL; /* MRB_WITHOUT_FLOAT */ #endif - case IREP_TT_STRING: - pool[i] = mrb_str_pool(mrb, s, pool_data_len, st); + case IREP_TT_STR: + pool_data_len = bin_to_uint16(src); /* pool data length */ + src += sizeof(uint16_t); + if (st) { + pool[i].tt = (pool_data_len<<2) | IREP_TT_SSTR; + pool[i].u.str = (const char*)src; + } + else { + char *p; + pool[i].tt = (pool_data_len<<2) | IREP_TT_STR; + p = (char*)mrb_malloc(mrb, pool_data_len+1); + memcpy(p, src, pool_data_len+1); + pool[i].u.str = (const char*)p; + } + src += pool_data_len + 1; break; default: /* should not happen */ - pool[i] = mrb_nil_value(); - break; + return NULL; } - irep->plen++; - mrb_gc_arena_restore(mrb, ai); + irep->plen = i+1; } } @@ -193,7 +223,6 @@ read_irep_record_1(mrb_state *mrb, const uint8_t *bin, size_t *len, uint8_t flag syms[i] = mrb_intern_static(mrb, (char *)src, snl); } src += snl + 1; - mrb_gc_arena_restore(mrb, ai); } } diff --git a/src/state.c b/src/state.c index 323532363..7a1283fa6 100644 --- a/src/state.c +++ b/src/state.c @@ -144,18 +144,14 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) if (irep->flags & MRB_IREP_NO_FREE) return; if (!(irep->flags & MRB_ISEQ_NO_FREE)) mrb_free(mrb, (void*)irep->iseq); - if (irep->pool) for (i=0; iplen; i++) { - if (mrb_string_p(irep->pool[i])) { - mrb_gc_free_str(mrb, RSTRING(irep->pool[i])); - mrb_free(mrb, mrb_obj_ptr(irep->pool[i])); + if (irep->pool) { + for (i=0; iplen; i++) { + if ((irep->pool[i].tt & 3) == IREP_TT_STR) { + mrb_free(mrb, (void*)irep->pool[i].u.str); + } } -#if defined(MRB_WORD_BOXING) && !defined(MRB_WITHOUT_FLOAT) - else if (mrb_float_p(irep->pool[i])) { - mrb_free(mrb, mrb_obj_ptr(irep->pool[i])); - } -#endif + mrb_free(mrb, (void*)irep->pool); } - mrb_free(mrb, (void*)irep->pool); mrb_free(mrb, (void*)irep->syms); if (irep->reps) { for (i=0; irlen; i++) { diff --git a/src/string.c b/src/string.c index 97795221c..73e514f41 100644 --- a/src/string.c +++ b/src/string.c @@ -583,9 +583,6 @@ str_share(mrb_state *mrb, struct RString *orig, struct RString *s) else if (RSTR_FSHARED_P(orig)) { str_init_fshared(orig, s, orig->as.heap.aux.fshared); } - else if (mrb_frozen_p(orig) && !RSTR_POOL_P(orig)) { - str_init_fshared(orig, s, orig); - } else { if (orig->as.heap.aux.capa > orig->as.heap.len) { orig->as.heap.ptr = (char *)mrb_realloc(mrb, orig->as.heap.ptr, len+1); @@ -596,29 +593,6 @@ str_share(mrb_state *mrb, struct RString *orig, struct RString *s) } } -mrb_value -mrb_str_pool(mrb_state *mrb, const char *p, mrb_int len, mrb_bool nofree) -{ - struct RString *s = (struct RString *)mrb_malloc(mrb, sizeof(struct RString)); - - s->tt = MRB_TT_STRING; - s->c = mrb->string_class; - s->flags = 0; - - if (RSTR_EMBEDDABLE_P(len)) { - str_init_embed(s, p, len); - } - else if (nofree) { - str_init_nofree(s, p, len); - } - else { - str_init_normal(mrb, s, p, len); - } - RSTR_SET_POOL_FLAG(s); - MRB_SET_FROZEN_FLAG(s); - return mrb_obj_value(s); -} - mrb_value mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len) { diff --git a/src/vm.c b/src/vm.c index 064086fb9..c3fa12d3d 100644 --- a/src/vm.c +++ b/src/vm.c @@ -966,7 +966,7 @@ mrb_vm_exec(mrb_state *mrb, struct RProc *proc, const mrb_code *pc) /* mrb_assert(MRB_PROC_CFUNC_P(proc)) */ const mrb_code *pc0 = pc; const mrb_irep *irep = proc->body.irep; - const mrb_value *pool = irep->pool; + const mrb_pool_value *pool = irep->pool; const mrb_sym *syms = irep->syms; mrb_code insn; int ai = mrb_gc_arena_save(mrb); @@ -1013,17 +1013,25 @@ RETRY_TRY_BLOCK: } CASE(OP_LOADL, BB) { -#ifdef MRB_WORD_BOXING - mrb_value val = pool[b]; -#ifndef MRB_WITHOUT_FLOAT - if (mrb_float_p(val)) { - val = mrb_float_value(mrb, mrb_float(val)); - } + switch (pool[b].tt) { /* number */ + case IREP_TT_INT32: + regs[a] = mrb_fixnum_value((mrb_int)pool[b].u.i32); + break; +#ifdef MRB_INT64 + case IREP_TT_INT64: + regs[a] = mrb_fixnum_value((mrb_int)pool[b].u.i64); + break; #endif - regs[a] = val; -#else - regs[a] = pool[b]; +#ifndef MRB_WITHOUT_FLOAT + case IREP_TT_FLOAT: + regs[a] = mrb_float_value(mrb, pool[b].u.f); + break; #endif + default: + /* should not happen (tt:string) */ + regs[a] = mrb_nil_value(); + break; + } NEXT; } @@ -2499,9 +2507,13 @@ RETRY_TRY_BLOCK: } CASE(OP_STRING, BB) { - mrb_value str = mrb_str_dup(mrb, pool[b]); - - regs[a] = str; + size_t len = pool[b].tt >> 2; + if (pool[b].tt & IREP_TT_SFLAG) { + regs[a] = mrb_str_new_static(mrb, pool[b].u.str, len); + } + else { + regs[a] = mrb_str_new(mrb, pool[b].u.str, len); + } mrb_gc_arena_restore(mrb, ai); NEXT; } @@ -2703,10 +2715,11 @@ RETRY_TRY_BLOCK: } CASE(OP_ERR, B) { - mrb_value msg = mrb_str_dup(mrb, pool[a]); + size_t len = pool[a].tt >> 2; mrb_value exc; - exc = mrb_exc_new_str(mrb, E_LOCALJUMP_ERROR, msg); + mrb_assert((pool[a].tt&IREP_TT_NFLAG)==0); + exc = mrb_exc_new(mrb, E_LOCALJUMP_ERROR, pool[a].u.str, len); ERR_PC_SET(mrb); mrb_exc_set(mrb, exc); goto L_RAISE; -- cgit v1.2.3 From c1f112c49a597da8478516261f0812bc073f6cd8 Mon Sep 17 00:00:00 2001 From: dearblue Date: Sat, 18 Jul 2020 19:05:12 +0900 Subject: Replace global jump with catch handler implementation When a global jump occurs, look at the catch handler table to determine where to jump. In that case, `pc` already shows the following instruction, but since the table shows `begin_offset ... end_offset`, the comparison is done with `begin_offset < pc && pc <= end_offset`. If there is a corresponding handler, move `pc` to `handler.target_offset` and continue running the VM. When a global jump across `ensure` is made by `return`, `break`, `next`, `redo` and `retry`, the extended `RBreak` object saves and restores the C-level execution position. This extended `RBreak` can have tag information, which makes it a pseudo coroutine (the "tag" mimics CRuby). The implementation of pseudo coroutines by `RBreak` is summarized by `CHECKPOINT_RESTORE ... CHECKPOINT_MAIN ... CHECKPOINT_END` and `throw_tagged_break` / `unwind_ensure` macros. The restart of processing is branched by `RBREAK_TAG_FOREACH(DISPATCH_CHECKPOINTS)`. - Not only `rescue` blocks but also `ensure` blocks are now sandwiched between `OP_EXCEPT` and `OP_RAISEIF`. - Remove the function `ecall()`. It is no longer necessary to re-enter the VM to perform an "ensure block". This will resolves #1888. - Added instruction `OP_JUW` (Jump while UnWind). It jumps unconditionally like `OP_JMP`, but searches the catch handler table and executes the ensure block. Since it searches the catch handler table, it is much heavier than `OP_JMP`. --- doc/opcode.md | 1 + include/mruby.h | 8 - include/mruby/error.h | 33 ++++ include/mruby/ops.h | 1 + mrbgems/mruby-compiler/core/codegen.c | 91 ++++----- mrbgems/mruby-os-memsize/src/memsize.c | 2 - src/codedump.c | 3 + src/gc.c | 8 - src/state.c | 2 - src/vm.c | 339 +++++++++++++++++++++++---------- 10 files changed, 311 insertions(+), 177 deletions(-) (limited to 'src/state.c') diff --git a/doc/opcode.md b/doc/opcode.md index 385bf9468..abdee704f 100644 --- a/doc/opcode.md +++ b/doc/opcode.md @@ -62,6 +62,7 @@ sign) of operands. | OP_JMPIF | BS | if R(a) pc=b | | OP_JMPNOT | BS | if !R(a) pc=b | | OP_JMPNIL | BS | if R(a)==nil pc=b | +| OP_JUW | S | unwind_and_jump_to(a) | | OP_EXCEPT | B | R(a) = exc | | OP_RESCUE | BB | R(b) = R(a).isa?(R(b)) | | OP_RAISEIF | B | raise(R(a)) if R(a) | diff --git a/include/mruby.h b/include/mruby.h index c9425e8a7..9f1d1aa30 100644 --- a/include/mruby.h +++ b/include/mruby.h @@ -149,8 +149,6 @@ typedef struct { mrb_sym mid; const struct RProc *proc; mrb_value *stackent; - uint16_t ridx; - uint16_t epos; struct REnv *env; const mrb_code *pc; /* return address */ const mrb_code *err; /* error position */ @@ -177,11 +175,6 @@ struct mrb_context { mrb_callinfo *ci; mrb_callinfo *cibase, *ciend; - uint16_t *rescue; /* exception handler stack */ - uint16_t rsize; - struct RProc **ensure; /* ensure handler stack */ - uint16_t esize, eidx; - enum mrb_fiber_state status : 4; mrb_bool vmexec : 1; struct RFiber *fib; @@ -301,7 +294,6 @@ typedef struct mrb_state { mrb_atexit_func *atexit_stack; #endif uint16_t atexit_stack_len; - uint16_t ecall_nest; /* prevent infinite recursive ecall() */ } mrb_state; /** diff --git a/include/mruby/error.h b/include/mruby/error.h index 72f6c5f3d..67a0a539e 100644 --- a/include/mruby/error.h +++ b/include/mruby/error.h @@ -66,6 +66,39 @@ mrb_break_value_set(struct RBreak *brk, mrb_value val) #define mrb_break_proc_get(brk) ((brk)->proc) #define mrb_break_proc_set(brk, p) ((brk)->proc = p) +#define RBREAK_TAG_FOREACH(f) \ + f(RBREAK_TAG_BREAK, 0) \ + f(RBREAK_TAG_BREAK_UPPER, 1) \ + f(RBREAK_TAG_BREAK_INTARGET, 2) \ + f(RBREAK_TAG_RETURN_BLOCK, 3) \ + f(RBREAK_TAG_RETURN, 4) \ + f(RBREAK_TAG_RETURN_TOPLEVEL, 5) \ + f(RBREAK_TAG_JUMP, 6) \ + f(RBREAK_TAG_STOP, 7) + +#define RBREAK_TAG_DEFINE(tag, i) tag = i, +enum { + RBREAK_TAG_FOREACH(RBREAK_TAG_DEFINE) +}; +#undef RBREAK_TAG_DEFINE + +#define RBREAK_TAG_BIT 3 +#define RBREAK_TAG_BIT_OFF 8 +#define RBREAK_TAG_MASK (~(~UINT32_C(0) << RBREAK_TAG_BIT)) + +static inline uint32_t +mrb_break_tag_get(struct RBreak *brk) +{ + return (brk->flags >> RBREAK_TAG_BIT_OFF) & RBREAK_TAG_MASK; +} + +static inline void +mrb_break_tag_set(struct RBreak *brk, uint32_t tag) +{ + brk->flags &= ~(RBREAK_TAG_MASK << RBREAK_TAG_BIT_OFF); + brk->flags |= (tag & RBREAK_TAG_MASK) << RBREAK_TAG_BIT_OFF; +} + /** * Protect * diff --git a/include/mruby/ops.h b/include/mruby/ops.h index 8ff44088e..770e54f3d 100644 --- a/include/mruby/ops.h +++ b/include/mruby/ops.h @@ -49,6 +49,7 @@ OPCODE(JMP, S) /* pc=a */ OPCODE(JMPIF, BS) /* if R(a) pc=b */ OPCODE(JMPNOT, BS) /* if !R(a) pc=b */ OPCODE(JMPNIL, BS) /* if R(a)==nil pc=b */ +OPCODE(JUW, S) /* unwind_and_jump_to(a) */ OPCODE(EXCEPT, B) /* R(a) = exc */ OPCODE(RESCUE, BB) /* R(b) = R(a).isa?(R(b)) */ OPCODE(RAISEIF, B) /* raise(R(a)) if R(a) */ diff --git a/mrbgems/mruby-compiler/core/codegen.c b/mrbgems/mruby-compiler/core/codegen.c index 7911ecb36..b3ce388a9 100644 --- a/mrbgems/mruby-compiler/core/codegen.c +++ b/mrbgems/mruby-compiler/core/codegen.c @@ -40,7 +40,6 @@ enum looptype { struct loopinfo { enum looptype type; int pc0, pc1, pc2, pc3, acc; - int ensure_level; struct loopinfo *prev; }; @@ -61,7 +60,6 @@ typedef struct scope { mrb_bool mscope:1; struct loopinfo *loop; - int ensure_level; mrb_sym filename_sym; uint16_t lineno; @@ -1465,16 +1463,19 @@ codegen(codegen_scope *s, node *tree, int val) { int noexc, exend, pos1, pos2, tmp; struct loopinfo *lp; + int catch_entry, begin, end; if (tree->car == NULL) goto exit; lp = loop_push(s, LOOP_BEGIN); lp->pc0 = new_label(s); - lp->pc1 = genjmp(s, OP_ONERR, 0); + catch_entry = catch_hander_new(s); + begin = s->pc; codegen(s, tree->car, VAL); pop(); lp->type = LOOP_RESCUE; + end = s->pc; noexc = genjmp(s, OP_JMP, 0); - dispatch(s, lp->pc1); + catch_hander_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc); tree = tree->cdr; exend = 0; pos1 = 0; @@ -1539,7 +1540,6 @@ codegen(codegen_scope *s, node *tree, int val) pop(); tree = tree->cdr; dispatch(s, noexc); - genop_1(s, OP_POPERR, 1); if (tree->car) { codegen(s, tree->car, val); } @@ -1555,14 +1555,22 @@ codegen(codegen_scope *s, node *tree, int val) if (!tree->cdr || !tree->cdr->cdr || (nint(tree->cdr->cdr->car) == NODE_BEGIN && tree->cdr->cdr->cdr)) { + int catch_entry, begin, end, target; int idx; - s->ensure_level++; - idx = scope_body(s, tree->cdr, NOVAL); - genop_1(s, OP_EPUSH, idx); + catch_entry = catch_hander_new(s); + begin = s->pc; codegen(s, tree->car, val); - s->ensure_level--; - genop_1(s, OP_EPOP, 1); + end = target = s->pc; + push(); + idx = cursp(); + genop_1(s, OP_EXCEPT, idx); + push(); + codegen(s, tree->cdr->cdr, NOVAL); + pop(); + genop_1(s, OP_RAISEIF, idx); + pop(); + catch_hander_set(s, catch_entry, MRB_CATCH_ENSURE, begin, end, target); } else { /* empty ensure ignored */ codegen(s, tree->car, val); @@ -2024,18 +2032,20 @@ codegen(codegen_scope *s, node *tree, int val) if ((len == 2 && name[0] == '|' && name[1] == '|') && (nint(tree->car->car) == NODE_CONST || nint(tree->car->car) == NODE_CVAR)) { - int onerr, noexc, exc; + int catch_entry, begin, end; + int noexc, exc; struct loopinfo *lp; - onerr = genjmp(s, OP_ONERR, 0); lp = loop_push(s, LOOP_BEGIN); - lp->pc1 = onerr; + lp->pc0 = new_label(s); + catch_entry = catch_hander_new(s); + begin = s->pc; exc = cursp(); codegen(s, tree->car, VAL); - lp->type = LOOP_RESCUE; - genop_1(s, OP_POPERR, 1); + end = s->pc; noexc = genjmp(s, OP_JMP, 0); - dispatch(s, onerr); + lp->type = LOOP_RESCUE; + catch_hander_set(s, catch_entry, MRB_CATCH_RESCUE, begin, end, s->pc); genop_1(s, OP_EXCEPT, exc); genop_1(s, OP_LOADF, exc); dispatch(s, noexc); @@ -2288,11 +2298,8 @@ codegen(codegen_scope *s, node *tree, int val) raise_error(s, "unexpected next"); } else if (s->loop->type == LOOP_NORMAL) { - if (s->ensure_level > s->loop->ensure_level) { - genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); - } codegen(s, tree, NOVAL); - genjmp(s, OP_JMP, s->loop->pc0); + genjmp(s, OP_JUW, s->loop->pc0); } else { if (tree) { @@ -2312,10 +2319,7 @@ codegen(codegen_scope *s, node *tree, int val) raise_error(s, "unexpected redo"); } else { - if (s->ensure_level > s->loop->ensure_level) { - genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); - } - genjmp(s, OP_JMP, s->loop->pc2); + genjmp(s, OP_JUW, s->loop->pc2); } if (val) push(); break; @@ -2323,32 +2327,16 @@ codegen(codegen_scope *s, node *tree, int val) case NODE_RETRY: { const char *msg = "unexpected retry"; + const struct loopinfo *lp = s->loop; - if (!s->loop) { + while (lp && lp->type != LOOP_RESCUE) { + lp = lp->prev; + } + if (!lp) { raise_error(s, msg); } else { - struct loopinfo *lp = s->loop; - int n = 0; - - while (lp && lp->type != LOOP_RESCUE) { - if (lp->type == LOOP_BEGIN) { - n++; - } - lp = lp->prev; - } - if (!lp) { - raise_error(s, msg); - } - else { - if (n > 0) { - genop_1(s, OP_POPERR, n); - } - if (s->ensure_level > lp->ensure_level) { - genop_1(s, OP_EPOP, s->ensure_level - lp->ensure_level); - } - genjmp(s, OP_JMP, lp->pc0); - } + genjmp(s, OP_JUW, lp->pc0); } if (val) push(); } @@ -3132,7 +3120,6 @@ loop_push(codegen_scope *s, enum looptype t) p->type = t; p->pc0 = p->pc1 = p->pc2 = p->pc3 = 0; p->prev = s->loop; - p->ensure_level = s->ensure_level; p->acc = cursp(); s->loop = p; @@ -3148,7 +3135,6 @@ loop_break(codegen_scope *s, node *tree) } else { struct loopinfo *loop; - int n = 0; if (tree) { gen_retval(s, tree); @@ -3157,7 +3143,6 @@ loop_break(codegen_scope *s, node *tree) loop = s->loop; while (loop) { if (loop->type == LOOP_BEGIN) { - n++; loop = loop->prev; } else if (loop->type == LOOP_RESCUE) { @@ -3171,20 +3156,14 @@ loop_break(codegen_scope *s, node *tree) raise_error(s, "unexpected break"); return; } - if (n > 0) { - genop_1(s, OP_POPERR, n); - } if (loop->type == LOOP_NORMAL) { int tmp; - if (s->ensure_level > s->loop->ensure_level) { - genop_1(s, OP_EPOP, s->ensure_level - s->loop->ensure_level); - } if (tree) { gen_move(s, loop->acc, cursp(), 0); } - tmp = genjmp(s, OP_JMP, loop->pc3); + tmp = genjmp(s, OP_JUW, loop->pc3); loop->pc3 = tmp; } else { diff --git a/mrbgems/mruby-os-memsize/src/memsize.c b/mrbgems/mruby-os-memsize/src/memsize.c index 191ab062d..7030299f4 100644 --- a/mrbgems/mruby-os-memsize/src/memsize.c +++ b/mrbgems/mruby-os-memsize/src/memsize.c @@ -133,8 +133,6 @@ os_memsize_of_object(mrb_state* mrb, mrb_value obj) size += mrb_objspace_page_slot_size() + sizeof(struct RFiber) + sizeof(struct mrb_context) + - sizeof(struct RProc *) * f->cxt->esize + - sizeof(uint16_t *) * f->cxt->rsize + sizeof(mrb_value) * stack_size + sizeof(mrb_callinfo) * ci_size; break; diff --git a/src/codedump.c b/src/codedump.c index 81212921d..095028a39 100644 --- a/src/codedump.c +++ b/src/codedump.c @@ -261,6 +261,9 @@ codedump(mrb_state *mrb, const mrb_irep *irep) CASE(OP_JMP, S); printf("OP_JMP\t\t%03d\n", a); break; + CASE(OP_JUW, S); + printf("OP_JUW\t\t%03d\n", a); + break; CASE(OP_JMPIF, BS); printf("OP_JMPIF\tR%d\t%03d\t", a, b); print_lv_a(mrb, irep, a); diff --git a/src/gc.c b/src/gc.c index ab9779e1b..17f7e81e4 100644 --- a/src/gc.c +++ b/src/gc.c @@ -640,7 +640,6 @@ mark_context_stack(mrb_state *mrb, struct mrb_context *c) static void mark_context(mrb_state *mrb, struct mrb_context *c) { - int i; mrb_callinfo *ci; start: @@ -657,10 +656,6 @@ mark_context(mrb_state *mrb, struct mrb_context *c) mrb_gc_mark(mrb, (struct RBasic*)ci->target_class); } } - /* mark ensure stack */ - for (i=0; ieidx; i++) { - mrb_gc_mark(mrb, (struct RBasic*)c->ensure[i]); - } /* mark fibers */ mrb_gc_mark(mrb, (struct RBasic*)c->fib); if (c->prev) { @@ -1014,9 +1009,6 @@ gc_gray_counts(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) if (c->stbase + i > c->stend) i = c->stend - c->stbase; children += i; - /* mark ensure stack */ - children += c->eidx; - /* mark closure */ if (c->cibase) { for (i=0, ci = c->cibase; ci <= c->ci; i++, ci++) diff --git a/src/state.c b/src/state.c index 7a1283fa6..1f85448a1 100644 --- a/src/state.c +++ b/src/state.c @@ -171,8 +171,6 @@ mrb_free_context(mrb_state *mrb, struct mrb_context *c) if (!c) return; mrb_free(mrb, c->stbase); mrb_free(mrb, c->cibase); - mrb_free(mrb, c->rescue); - mrb_free(mrb, c->ensure); mrb_free(mrb, c); } diff --git a/src/vm.c b/src/vm.c index d11caa5c7..cc6f087f9 100644 --- a/src/vm.c +++ b/src/vm.c @@ -23,6 +23,7 @@ #include #include "value_array.h" #include +#include #ifdef MRB_DISABLE_STDIO #if defined(__cplusplus) @@ -280,8 +281,6 @@ cipush(mrb_state *mrb, const mrb_code *pc, int push_stacks, int acc, ci->mid = mid; ci->proc = proc; ci->stackent = c->stack; - ci->epos = c->eidx; - ci->ridx = ci[-1].ridx; ci->pc = pc; ci->argc = argc; ci->acc = acc; @@ -329,54 +328,6 @@ cipop(mrb_state *mrb) void mrb_exc_set(mrb_state *mrb, mrb_value exc); static mrb_value mrb_run(mrb_state *mrb, const struct RProc* proc, mrb_value self); -static void -ecall(mrb_state *mrb) -{ - struct RProc *p; - struct mrb_context *c = mrb->c; - mrb_callinfo *ci = c->ci; - struct RObject *exc; - struct REnv *env; - ptrdiff_t cioff; - int ai = mrb_gc_arena_save(mrb); - uint16_t i; - int nregs; - - if (c->eidx == 0) return; - i = --c->eidx; - - /* restrict total call depth of ecall() */ - if (++mrb->ecall_nest > MRB_ECALL_DEPTH_MAX) { - mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); - } - p = c->ensure[i]; - if (!p) return; - mrb_assert(!MRB_PROC_CFUNC_P(p)); - c->ensure[i] = NULL; - nregs = p->upper->body.irep->nregs; - if (ci->proc && !MRB_PROC_CFUNC_P(ci->proc) && - ci->proc->body.irep->nregs > nregs) { - nregs = ci->proc->body.irep->nregs; - } - cioff = ci - c->cibase; - ci = cipush(mrb, NULL, nregs, CI_ACC_SKIP, MRB_PROC_TARGET_CLASS(p), p, ci->mid, 0); - env = MRB_PROC_ENV(p); - mrb_assert(env); - exc = mrb->exc; mrb->exc = 0; - if (exc) { - mrb_gc_protect(mrb, mrb_obj_value(exc)); - } - if (mrb->c->fib) { - mrb_gc_protect(mrb, mrb_obj_value(mrb->c->fib)); - } - mrb_run(mrb, p, env->stack[0]); - mrb->c = c; - c->ci = c->cibase + cioff; - if (!mrb->exc) mrb->exc = exc; - mrb_gc_arena_restore(mrb, ai); - mrb->ecall_nest--; -} - #ifndef MRB_FUNCALL_ARGC_MAX #define MRB_FUNCALL_ARGC_MAX 16 #endif @@ -821,17 +772,56 @@ mrb_yield_cont(mrb_state *mrb, mrb_value b, mrb_value self, mrb_int argc, const } static struct RBreak* -break_new(mrb_state *mrb, const struct RProc *p, mrb_value val) +break_new(mrb_state *mrb, uint32_t tag, const struct RProc *p, mrb_value val) { struct RBreak *brk; brk = (struct RBreak*)mrb_obj_alloc(mrb, MRB_TT_BREAK, NULL); mrb_break_proc_set(brk, p); mrb_break_value_set(brk, val); + mrb_break_tag_set(brk, tag); return brk; } +#define MRB_CATCH_FILTER_RESCUE (UINT32_C(1) << MRB_CATCH_RESCUE) +#define MRB_CATCH_FILTER_ENSURE (UINT32_C(1) << MRB_CATCH_ENSURE) +#define MRB_CATCH_FILTER_ALL (MRB_CATCH_FILTER_RESCUE | MRB_CATCH_FILTER_ENSURE) + +static const struct mrb_irep_catch_hander * +catch_handler_find(mrb_state *mrb, mrb_callinfo *ci, const mrb_code *pc, uint32_t filter) +{ + mrb_irep *irep; + ptrdiff_t xpc; + size_t cnt; + const struct mrb_irep_catch_hander *e; + +/* The comparison operators use `>` and `<=` because pc already points to the next instruction */ +#define catch_cover_p(pc, beg, end) ((pc) > (beg) && (pc) <= (end)) + + if (ci->proc == NULL || MRB_PROC_CFUNC_P(ci->proc)) return NULL; + irep = ci->proc->body.irep; + if (irep->clen < 1) return NULL; + xpc = pc - irep->iseq; + /* If it retry at the top level, pc will be 0, so check with -1 as the start position */ + mrb_assert(catch_cover_p(xpc, -1, irep->ilen)); + if (!catch_cover_p(xpc, -1, irep->ilen)) return NULL; + + /* Currently uses a simple linear search to avoid processing complexity. */ + cnt = irep->clen; + e = mrb_irep_catch_handler_table(irep) + cnt - 1; + for (; cnt > 0; cnt --, e --) { + if (((UINT32_C(1) << e->type) & filter) && + catch_cover_p(xpc, bin_to_uint16(e->begin), bin_to_uint16(e->end))) { + return e; + } + } + +#undef catch_cover_p + + return NULL; +} + typedef enum { LOCALJUMP_ERROR_RETURN = 0, LOCALJUMP_ERROR_BREAK = 1, @@ -878,6 +868,81 @@ argnum_error(mrb_state *mrb, mrb_int num) mrb_exc_set(mrb, exc); } +static mrb_bool +break_tag_p(struct RBreak *brk, uint32_t tag) +{ + return (brk != NULL && brk->tt == MRB_TT_BREAK) ? TRUE : FALSE; +} + +static void +prepare_tagged_break(mrb_state *mrb, uint32_t tag, struct RProc *proc, mrb_value val) +{ + if (break_tag_p((struct RBreak*)mrb->exc, tag)) { + mrb_break_tag_set((struct RBreak*)mrb->exc, tag); + } + else { + mrb->exc = (struct RObject*)break_new(mrb, tag, proc, val); + } +} + +#define THROW_TAGGED_BREAK(mrb, tag, proc, val) \ + do { \ + prepare_tagged_break(mrb, tag, proc, val); \ + goto L_CATCH_TAGGED_BREAK; \ + } while (0) + +#define UNWIND_ENSURE(mrb, ci, pc, tag, proc, val) \ + do { \ + ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ENSURE); \ + if (ch) { \ + THROW_TAGGED_BREAK(mrb, tag, proc, val); \ + } \ + } while (0) + +/* + * CHECKPOINT_RESTORE(tag) { + * This part is executed when jumping by the same "tag" of RBreak (it is not executed the first time). + * Write the code required (initialization of variables, etc.) for the subsequent processing. + * } + * CHECKPOINT_MAIN(tag) { + * This part is always executed. + * } + * CHECKPOINT_END(tag); + * + * ... + * + * // Jump to CHECKPOINT_RESTORE with the same "tag". + * goto CHECKPOINT_LABEL_MAKE(tag); + */ + +#define CHECKPOINT_LABEL_MAKE(tag) L_CHECKPOINT_ ## tag + +#define CHECKPOINT_RESTORE(tag) \ + do { \ + DEBUG_ONLY_EXPR(int current_checkpoint_tag); \ + DEBUG_ONLY_EXPR(current_checkpoint_tag = (tag)); \ + if (FALSE) { \ + CHECKPOINT_LABEL_MAKE(tag): \ + DEBUG_ONLY_EXPR(current_checkpoint_tag = (tag)); \ + do { + +#define CHECKPOINT_MAIN(tag) \ + } while (0); \ + } \ + mrb_assert((tag) == current_checkpoint_tag); \ + do { + +#define CHECKPOINT_END(tag) \ + } while (0); \ + mrb_assert((tag) == current_checkpoint_tag); \ + } while (0) + +#ifdef MRB_DEBUG +#define DEBUG_ONLY_EXPR(e) e +#else +#define DEBUG_ONLY_EXPR(e) ((void)0) +#endif + #define ERR_PC_SET(mrb) mrb->c->ci->err = pc0; #define ERR_PC_CLR(mrb) mrb->c->ci->err = 0; #ifdef MRB_ENABLE_DEBUG_HOOK @@ -976,6 +1041,7 @@ mrb_vm_exec(mrb_state *mrb, const struct RProc *proc, const mrb_code *pc) uint16_t b; uint8_t c; mrb_sym mid; + const struct mrb_irep_catch_hander *ch; #ifdef DIRECT_THREADED static void *optable[] = { @@ -1231,6 +1297,30 @@ RETRY_TRY_BLOCK: NEXT; } + CASE(OP_JUW, S) { + CHECKPOINT_RESTORE(RBREAK_TAG_JUMP) { + struct RBreak *brk = (struct RBreak*)mrb->exc; + mrb_value target = mrb_break_value_get(brk); + mrb_assert(mrb_fixnum_p(target)); + a = mrb_fixnum(target); + mrb_assert(a >= 0 && a < irep->ilen); + } + CHECKPOINT_MAIN(RBREAK_TAG_JUMP) { + ch = catch_handler_find(mrb, mrb->c->ci, pc, MRB_CATCH_FILTER_ENSURE); + if (ch) { + /* avoiding a jump from a catch handler into the same handler */ + if (a < bin_to_uint16(ch->begin) || a >= bin_to_uint16(ch->end)) { + THROW_TAGGED_BREAK(mrb, RBREAK_TAG_JUMP, proc, mrb_fixnum_value(a)); + } + } + } + CHECKPOINT_END(RBREAK_TAG_JUMP); + + mrb->exc = NULL; /* clear break object */ + pc = irep->iseq + a; + JUMP; + } + CASE(OP_EXCEPT, B) { mrb_value exc; @@ -1563,6 +1653,7 @@ RETRY_TRY_BLOCK: mrb_gc_arena_restore(mrb, ai); if (mrb->exc) goto L_RAISE; ci = mrb->c->ci; + mrb_assert(!mrb_break_p(v)); if (!ci->target_class) { /* return from context modifying method (resume/yield) */ if (ci->acc == CI_ACC_RESUMED) { mrb->jmp = prev_jmp; @@ -1839,13 +1930,7 @@ RETRY_TRY_BLOCK: c = OP_R_NORMAL; L_RETURN: { - mrb_callinfo *ci; - -#define ecall_adjust() do {\ - ptrdiff_t cioff = ci - mrb->c->cibase;\ - ecall(mrb);\ - ci = mrb->c->cibase + cioff;\ -} while (0) + mrb_callinfo *ci; ci = mrb->c->ci; if (ci->mid) { @@ -1873,17 +1958,20 @@ RETRY_TRY_BLOCK: L_RAISE: ci0 = ci = mrb->c->ci; if (ci == mrb->c->cibase) { - if (ci->ridx == 0) goto L_FTOP; - goto L_RESCUE; + ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ALL); + if (ch == NULL) goto L_FTOP; + goto L_CATCH; } - while (ci[0].ridx == ci[-1].ridx) { + while ((ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ALL)) == NULL) { ci = cipop(mrb); if (ci[1].acc == CI_ACC_SKIP && prev_jmp) { mrb->jmp = prev_jmp; MRB_THROW(prev_jmp); } + pc = ci[1].pc; if (ci == mrb->c->cibase) { - if (ci->ridx == 0) { + ch = catch_handler_find(mrb, ci, pc, MRB_CATCH_FILTER_ALL); + if (ch == NULL) { L_FTOP: /* fiber top */ if (mrb->c == mrb->root_c) { mrb->c->stack = mrb->c->stbase; @@ -1892,9 +1980,6 @@ RETRY_TRY_BLOCK: else { struct mrb_context *c = mrb->c; - while (c->eidx > ci->epos) { - ecall_adjust(); - } c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; c->prev = NULL; @@ -1903,15 +1988,13 @@ RETRY_TRY_BLOCK: } break; } - /* call ensure only when we skip this callinfo */ - if (ci[0].ridx == ci[-1].ridx) { - while (mrb->c->eidx > ci->epos) { - ecall_adjust(); - } - } } - L_RESCUE: - if (ci->ridx == 0) goto L_STOP; + L_CATCH: + if (ch == NULL) goto L_STOP; + if (FALSE) { + L_CATCH_TAGGED_BREAK: /* from THROW_TAGGED_BREAK() or UNWIND_ENSURE() */ + ci = ci0 = mrb->c->ci; + } proc = ci->proc; irep = proc->body.irep; pool = irep->pool; @@ -1920,7 +2003,7 @@ RETRY_TRY_BLOCK: mrb->c->stack = ci[1].stackent; } mrb_stack_extend(mrb, irep->nregs); - pc = irep->iseq+mrb->c->rescue[--ci->ridx]; + pc = irep->iseq + bin_to_uint16(ch->target); } else { int acc; @@ -1950,8 +2033,19 @@ RETRY_TRY_BLOCK: localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; } - ci--; + CHECKPOINT_RESTORE(RBREAK_TAG_RETURN_BLOCK) { + cibase = mrb->c->cibase; + dst = top_proc(mrb, proc); + } + CHECKPOINT_MAIN(RBREAK_TAG_RETURN_BLOCK) { + UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_RETURN_BLOCK, proc, v); + } + CHECKPOINT_END(RBREAK_TAG_RETURN_BLOCK); + pc = ci->pc; + ci = cipop(mrb); } + mrb->exc = NULL; /* clear break object */ + proc = ci->proc; if (ci <= cibase) { localjump_error(mrb, LOCALJUMP_ERROR_RETURN); goto L_RAISE; @@ -1966,16 +2060,20 @@ RETRY_TRY_BLOCK: if (!c->prev) { /* toplevel return */ regs[irep->nlocals] = v; - goto L_STOP; + goto CHECKPOINT_LABEL_MAKE(RBREAK_TAG_STOP); } if (c->prev->ci == c->prev->cibase) { mrb_value exc = mrb_exc_new_str_lit(mrb, E_FIBER_ERROR, "double resume"); mrb_exc_set(mrb, exc); goto L_RAISE; } - while (c->eidx > 0) { - ecall(mrb); + CHECKPOINT_RESTORE(RBREAK_TAG_RETURN_TOPLEVEL) { + c = mrb->c; } + CHECKPOINT_MAIN(RBREAK_TAG_RETURN_TOPLEVEL) { + UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_RETURN_TOPLEVEL, proc, v); + } + CHECKPOINT_END(RBREAK_TAG_RETURN_TOPLEVEL); /* automatic yield at the end */ c->status = MRB_FIBER_TERMINATED; mrb->c = c->prev; @@ -1983,6 +2081,14 @@ RETRY_TRY_BLOCK: mrb->c->status = MRB_FIBER_RUNNING; ci = mrb->c->ci; } + CHECKPOINT_RESTORE(RBREAK_TAG_RETURN) { + /* do nothing */ + } + CHECKPOINT_MAIN(RBREAK_TAG_RETURN) { + UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_RETURN, proc, v); + } + CHECKPOINT_END(RBREAK_TAG_RETURN); + mrb->exc = NULL; /* clear break object */ break; case OP_R_BREAK: if (MRB_PROC_STRICT_P(proc)) goto NORMAL_RETURN; @@ -2005,9 +2111,13 @@ RETRY_TRY_BLOCK: goto L_BREAK_ERROR; } } - while (mrb->c->eidx > mrb->c->ci->epos) { - ecall_adjust(); + CHECKPOINT_RESTORE(RBREAK_TAG_BREAK) { + /* do nothing */ } + CHECKPOINT_MAIN(RBREAK_TAG_BREAK) { + UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_BREAK, proc, v); + } + CHECKPOINT_END(RBREAK_TAG_BREAK); /* break from fiber block */ if (ci == mrb->c->cibase && ci->pc) { struct mrb_context *c = mrb->c; @@ -2017,45 +2127,64 @@ RETRY_TRY_BLOCK: ci = mrb->c->ci; } if (ci->acc < 0) { + ci = cipop(mrb); mrb_gc_arena_restore(mrb, ai); mrb->c->vmexec = FALSE; - mrb->exc = (struct RObject*)break_new(mrb, proc, v); + mrb->exc = (struct RObject*)break_new(mrb, RBREAK_TAG_BREAK, proc, v); mrb->jmp = prev_jmp; MRB_THROW(prev_jmp); } if (FALSE) { + struct RBreak *brk; + L_BREAK: - v = mrb_break_value_get((struct RBreak*)mrb->exc); - proc = mrb_break_proc_get((struct RBreak*)mrb->exc); - mrb->exc = NULL; + brk = (struct RBreak*)mrb->exc; + proc = mrb_break_proc_get(brk); + v = mrb_break_value_get(brk); ci = mrb->c->ci; + + switch (mrb_break_tag_get(brk)) { +#define DISPATCH_CHECKPOINTS(n, i) case n: goto CHECKPOINT_LABEL_MAKE(n); + RBREAK_TAG_FOREACH(DISPATCH_CHECKPOINTS) +#undef DISPATCH_CHECKPOINTS + default: + mrb_assert(!"wrong break tag"); + } } mrb->c->stack = ci->stackent; - proc = proc->upper; - while (mrb->c->cibase < ci && ci[-1].proc != proc) { + while (mrb->c->cibase < ci && ci[-1].proc != proc->upper) { if (ci[-1].acc == CI_ACC_SKIP) { - while (ci < mrb->c->ci) { - cipop(mrb); - } goto L_BREAK_ERROR; } - ci--; + CHECKPOINT_RESTORE(RBREAK_TAG_BREAK_UPPER) { + /* do nothing */ + } + CHECKPOINT_MAIN(RBREAK_TAG_BREAK_UPPER) { + UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_BREAK_UPPER, proc, v); + } + CHECKPOINT_END(RBREAK_TAG_BREAK_UPPER); + pc = ci->pc; + ci = cipop(mrb); } + CHECKPOINT_RESTORE(RBREAK_TAG_BREAK_INTARGET) { + /* do nothing */ + } + CHECKPOINT_MAIN(RBREAK_TAG_BREAK_INTARGET) { + UNWIND_ENSURE(mrb, ci, pc, RBREAK_TAG_BREAK_INTARGET, proc, v); + } + CHECKPOINT_END(RBREAK_TAG_BREAK_INTARGET); if (ci == mrb->c->cibase) { goto L_BREAK_ERROR; } + mrb->exc = NULL; /* clear break object */ break; default: /* cannot happen */ break; } - while (ci < mrb->c->ci) { - cipop(mrb); - } - ci[0].ridx = ci[-1].ridx; - while (mrb->c->eidx > ci->epos) { - ecall_adjust(); - } + mrb_assert(ci == mrb->c->ci); + mrb_assert(mrb->exc == NULL); + if (mrb->c->vmexec && !ci->target_class) { mrb_gc_arena_restore(mrb, ai); mrb->c->vmexec = FALSE; @@ -2679,14 +2808,18 @@ RETRY_TRY_BLOCK: CASE(OP_STOP, Z) { /* stop VM */ - L_STOP: - while (mrb->c->eidx > 0) { - ecall(mrb); + CHECKPOINT_RESTORE(RBREAK_TAG_STOP) { + /* do nothing */ + } + CHECKPOINT_MAIN(RBREAK_TAG_STOP) { + UNWIND_ENSURE(mrb, mrb->c->ci, pc, RBREAK_TAG_STOP, proc, mrb_nil_value()); } - mrb->c->cibase->ridx = 0; + CHECKPOINT_END(RBREAK_TAG_STOP); + L_STOP: ERR_PC_CLR(mrb); mrb->jmp = prev_jmp; if (mrb->exc) { + mrb_assert(mrb->exc->tt == MRB_TT_EXCEPTION); return mrb_obj_value(mrb->exc); } return regs[irep->nlocals]; @@ -2696,6 +2829,10 @@ RETRY_TRY_BLOCK: #undef regs } MRB_CATCH(&c_jmp) { + mrb_callinfo *ci = mrb->c->ci; + while (ci > mrb->c->cibase && ci->acc == CI_ACC_DIRECT) { + ci = cipop(mrb); + } exc_catched = TRUE; goto RETRY_TRY_BLOCK; } -- cgit v1.2.3