diff options
31 files changed, 681 insertions, 311 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 81deb4515..335c0cdf6 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -5,51 +5,59 @@ on: [push, pull_request] jobs: Ubuntu-1604: runs-on: ubuntu-16.04 + env: + MRUBY_CONFIG: travis_config.rb steps: - uses: actions/checkout@v1 - name: apt run: sudo apt install ruby gperf - - name: build and test - run: rake -m -j4 all test - env: - MRUBY_CONFIG: travis_config.rb + - name: build + run: rake -m + - name: test + run: rake test Ubuntu-1804-gcc: runs-on: ubuntu-18.04 + env: + MRUBY_CONFIG: travis_config.rb + CC: gcc + CXX: g++ steps: - uses: actions/checkout@v1 - name: apt run: sudo apt install ruby gperf gcc g++ - - name: build and test - run: rake -m -j4 all test - env: - MRUBY_CONFIG: travis_config.rb - CC: gcc - CXX: g++ + - name: build + run: rake -m + - name: test + run: rake test Ubuntu-1804-clang: runs-on: ubuntu-18.04 + env: + MRUBY_CONFIG: travis_config.rb + CC: clang + CXX: clang++ steps: - uses: actions/checkout@v1 - name: apt run: sudo apt install ruby gperf - - name: build and test - run: rake -m -j4 all test - env: - MRUBY_CONFIG: travis_config.rb - CC: clang - CXX: clang++ + - name: build + run: rake -m + - name: test + run: rake test macOS: runs-on: macos-latest + env: + MRUBY_CONFIG: travis_config.rb steps: - uses: actions/checkout@v1 - name: brew run: brew install ruby gperf - - name: build and test - run: rake -m -j4 all test - env: - MRUBY_CONFIG: travis_config.rb + - name: build + run: rake -m + - name: test + run: rake test Windows-MinGW: runs-on: windows-latest @@ -57,8 +65,8 @@ jobs: - uses: actions/checkout@v1 - name: chocolatey run: choco install -y ruby gperf - - name: build and test - run: rake -E '$stdout.sync=true' -j4 test + - name: build + run: rake -E 'STDOUT.sync=true' test env: MRUBY_CONFIG: travis_config.rb CFLAGS: -g -O1 -Wall -Wundef @@ -82,25 +90,13 @@ jobs: - name: Set ENV run: | echo '::set-env name=PATH::C:\tools\cygwin\bin;C:\tools\cygwin\usr\bin' - - name: build and test + - name: build shell: cmd - run: C:\tools\cygwin\bin\ruby.exe /usr/bin/rake -m -j4 -E 'STDOUT.sync=true' test + run: C:\tools\cygwin\bin\ruby.exe /usr/bin/rake -E 'STDOUT.sync=true' -m env: MRUBY_CONFIG: travis_config.rb - - Windows-VC: - runs-on: windows-latest - steps: - - uses: actions/checkout@v1 - - name: chocolatey - run: choco install -y ruby gperf - - name: build and test + - name: test shell: cmd - run: | - call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvars64.bat" - rake -E "STDOUT.sync=true" -m -j4 test + run: C:\tools\cygwin\bin\ruby.exe /usr/bin/rake -E 'STDOUT.sync=true' test env: - MRUBY_CONFIG: appveyor_config.rb - # TODO(take-cheeze): Re-enable /O2 - CFLAGS: "/c /nologo /W3 /we4013 /Zi /MD /D_CRT_SECURE_NO_WARNINGS" - CXXFLAGS: "/c /nologo /W3 /Zi /MD /EHs /D_CRT_SECURE_NO_WARNINGS" + MRUBY_CONFIG: travis_config.rb @@ -43,3 +43,4 @@ of this list. YAMAMOTO Masaya KOBAYASHI Shuji RIZAL Reckordp + Rory O'Connell diff --git a/appveyor.yml b/appveyor.yml index e135383e1..e963ea035 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,39 +1,44 @@ version: "{build}" -os: Visual Studio 2017 - shallow_clone: true environment: matrix: - # Visual Studio 2017 64bit - - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat - - # Visual Studio 2017 32bit - - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvarsall.bat - machine: x86 - - # Visual Studio 2015 64bit - - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat - machine: amd64 - - # Visual Studio 2015 32bit - - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat + - job_name: Visual Studio 2019 64bit + visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat + appveyor_build_worker_image: Visual Studio 2019 + + - job_name: Visual Studio 2019 32bit + visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars32.bat + appveyor_build_worker_image: Visual Studio 2019 + + - job_name: Visual Studio 2017 64bit + visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat + appveyor_build_worker_image: Visual Studio 2017 + + - job_name: Visual Studio 2017 32bit + visualcpp: C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars32.bat + appveyor_build_worker_image: Visual Studio 2017 + + - job_name: Visual Studio 2015 64bit + visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat + appveyor_build_worker_image: Visual Studio 2015 + machine: x86_amd64 + + - job_name: Visual Studio 2015 32bit + visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat + appveyor_build_worker_image: Visual Studio 2015 machine: x86 - # Visual Studio 2013 64bit - - visualcpp: C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat - machine: amd64 - - init: - call "%visualcpp%" %machine% - # For using Rubyinstaller's Ruby 2.4 64bit - - set PATH=C:\Ruby24-x64\bin;%PATH% + # For using Rubyins4aller's Ruby 2.6 64bit + # 2.6 is the highest supported Ruby version across all historical + # Visual Studio AppVeyor images. Ruby 2.7 is only on the 2019 image. + - set PATH=C:\Ruby26-x64\bin;%PATH% - ruby --version - build_script: - set MRUBY_CONFIG=appveyor_config.rb - - rake -m - - rake -E $stdout.sync=true test + - rake -m -j4 + - rake -E STDOUT.sync=true test diff --git a/include/mruby/gc.h b/include/mruby/gc.h index 4d9fb60eb..1beffba2a 100644 --- a/include/mruby/gc.h +++ b/include/mruby/gc.h @@ -21,6 +21,7 @@ struct mrb_state; #define MRB_EACH_OBJ_BREAK 1 typedef int (mrb_each_object_callback)(struct mrb_state *mrb, struct RBasic *obj, void *data); void mrb_objspace_each_objects(struct mrb_state *mrb, mrb_each_object_callback *callback, void *data); +mrb_int mrb_objspace_page_slot_size(void); MRB_API void mrb_free_context(struct mrb_state *mrb, struct mrb_context *c); #ifndef MRB_GC_ARENA_SIZE diff --git a/include/mruby/hash.h b/include/mruby/hash.h index 0052a1105..04b265ec3 100644 --- a/include/mruby/hash.h +++ b/include/mruby/hash.h @@ -23,6 +23,7 @@ struct RHash { #define mrb_hash_ptr(v) ((struct RHash*)(mrb_ptr(v))) #define mrb_hash_value(p) mrb_obj_value((void*)(p)) +mrb_int mrb_os_memsize_of_hash_table(mrb_value obj); MRB_API mrb_value mrb_hash_new_capa(mrb_state *mrb, mrb_int capa); MRB_API mrb_value mrb_ensure_hash_type(mrb_state *mrb, mrb_value hash); MRB_API mrb_value mrb_check_hash_type(mrb_state *mrb, mrb_value hash); diff --git a/include/mruby/khash.h b/include/mruby/khash.h index 9f3f1a2cc..4884ba73c 100644 --- a/include/mruby/khash.h +++ b/include/mruby/khash.h @@ -61,7 +61,6 @@ static const uint8_t __m_either[] = {0x03, 0x0c, 0x30, 0xc0}; typedef struct kh_##name { \ khint_t n_buckets; \ khint_t size; \ - khint_t n_occupied; \ uint8_t *ed_flags; \ khkey_t *keys; \ khval_t *vals; \ @@ -73,7 +72,6 @@ static const uint8_t __m_either[] = {0x03, 0x0c, 0x30, 0xc0}; void kh_clear_##name(mrb_state *mrb, kh_##name##_t *h); \ khint_t kh_get_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key); \ khint_t kh_put_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key, int *ret); \ - void kh_put_prepare_##name(mrb_state *mrb, kh_##name##_t *h); \ void kh_resize_##name(mrb_state *mrb, kh_##name##_t *h, khint_t new_n_buckets); \ void kh_del_##name(mrb_state *mrb, kh_##name##_t *h, khint_t x); \ kh_##name##_t *kh_copy_##name(mrb_state *mrb, kh_##name##_t *h); @@ -103,7 +101,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len) size_t len = sizeof(khkey_t) + (kh_is_map ? sizeof(khval_t) : 0); \ uint8_t *p = (uint8_t*)mrb_malloc_simple(mrb, sizeof(uint8_t)*sz/4+len*sz); \ if (!p) { return 1; } \ - h->size = h->n_occupied = 0; \ + h->size = 0; \ h->keys = (khkey_t *)p; \ h->vals = kh_is_map ? (khval_t *)(p+sizeof(khkey_t)*sz) : NULL; \ h->ed_flags = p+len*sz; \ @@ -143,7 +141,7 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len) (void)mrb; \ if (h && h->ed_flags) { \ kh_fill_flags(h->ed_flags, 0xaa, h->n_buckets/4); \ - h->size = h->n_occupied = 0; \ + h->size = 0; \ } \ } \ khint_t kh_get_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key) \ @@ -184,16 +182,12 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len) mrb_free(mrb, old_keys); \ } \ } \ - void kh_put_prepare_##name(mrb_state *mrb, kh_##name##_t *h) \ - { \ - if (h->n_occupied >= khash_upper_bound(h)) { \ - kh_resize_##name(mrb, h, h->n_buckets*2); \ - } \ - } \ khint_t kh_put_##name(mrb_state *mrb, kh_##name##_t *h, khkey_t key, int *ret) \ { \ khint_t k, del_k, step = 0; \ - kh_put_prepare_##name(mrb, h); \ + if (h->size >= khash_upper_bound(h)) { \ + kh_resize_##name(mrb, h, h->n_buckets*2); \ + } \ k = __hash_func(mrb,key) & khash_mask(h); \ del_k = kh_end(h); \ while (!__ac_isempty(h->ed_flags, k)) { \ @@ -221,7 +215,6 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len) h->keys[k] = key; \ h->ed_flags[k/4] &= ~__m_empty[k%4]; \ h->size++; \ - h->n_occupied++; \ if (ret) *ret = 1; \ return k; \ } \ @@ -256,7 +249,6 @@ kh_fill_flags(uint8_t *p, uint8_t c, size_t len) #define kh_destroy(name, mrb, h) kh_destroy_##name(mrb, h) #define kh_clear(name, mrb, h) kh_clear_##name(mrb, h) #define kh_resize(name, mrb, h, s) kh_resize_##name(mrb, h, s) -#define kh_put_prepare(name, mrb, h) kh_put_prepare_##name(mrb, h) #define kh_put(name, mrb, h, k) kh_put_##name(mrb, h, k, NULL) #define kh_put2(name, mrb, h, k, r) kh_put_##name(mrb, h, k, r) #define kh_get(name, mrb, h, k) kh_get_##name(mrb, h, k) diff --git a/include/mruby/variable.h b/include/mruby/variable.h index 6e918cf57..5559f6606 100644 --- a/include/mruby/variable.h +++ b/include/mruby/variable.h @@ -35,6 +35,7 @@ mrb_value mrb_vm_cv_get(mrb_state*, mrb_sym); void mrb_vm_cv_set(mrb_state*, mrb_sym, mrb_value); mrb_value mrb_vm_const_get(mrb_state*, mrb_sym); void mrb_vm_const_set(mrb_state*, mrb_sym, mrb_value); +mrb_int mrb_obj_iv_tbl_memsize(mrb_state*, mrb_value); MRB_API mrb_value mrb_const_get(mrb_state*, mrb_value, mrb_sym); MRB_API void mrb_const_set(mrb_state*, mrb_value, mrb_sym, mrb_value); MRB_API mrb_bool mrb_const_defined(mrb_state*, mrb_value, mrb_sym); diff --git a/mrbgems/mruby-io/src/io.c b/mrbgems/mruby-io/src/io.c index 505ceb248..b3e192899 100644 --- a/mrbgems/mruby-io/src/io.c +++ b/mrbgems/mruby-io/src/io.c @@ -18,6 +18,7 @@ #if defined(_WIN32) || defined(_WIN64) #include <winsock.h> #include <io.h> + #include <basetsd.h> #define open _open #define close _close #define dup _dup @@ -32,6 +33,10 @@ typedef long fsuseconds_t; typedef int fmode_t; typedef int mrb_io_read_write_size; + #if !defined(_SSIZE_T_) && !defined(_SSIZE_T_DEFINED) && \ + !defined(__have_typedef_ssize_t) + typedef SSIZE_T ssize_t; + #endif #ifndef O_TMPFILE #define O_TMPFILE O_TEMPORARY diff --git a/mrbgems/mruby-objectspace/src/mruby_objectspace.c b/mrbgems/mruby-objectspace/src/mruby_objectspace.c index b89fb0580..bded3afa8 100644 --- a/mrbgems/mruby-objectspace/src/mruby_objectspace.c +++ b/mrbgems/mruby-objectspace/src/mruby_objectspace.c @@ -2,6 +2,14 @@ #include <mruby/gc.h> #include <mruby/hash.h> #include <mruby/class.h> +#include <mruby/object.h> +#include <mruby/numeric.h> +#include <mruby/string.h> +#include <mruby/array.h> +#include <mruby/variable.h> +#include <mruby/proc.h> +#include <mruby/value.h> +#include <mruby/range.h> struct os_count_struct { mrb_int total; @@ -92,6 +100,7 @@ os_count_objects(mrb_state *mrb, mrb_value self) COUNT_TYPE(T_ENV); COUNT_TYPE(T_DATA); COUNT_TYPE(T_FIBER); + COUNT_TYPE(T_ISTRUCT); #undef COUNT_TYPE default: type = mrb_fixnum_value(i); break; @@ -104,9 +113,9 @@ os_count_objects(mrb_state *mrb, mrb_value self) } struct os_each_object_data { - mrb_value block; struct RClass *target_module; mrb_int count; + mrb_value block; }; static int @@ -121,8 +130,8 @@ os_each_object_cb(mrb_state *mrb, struct RBasic *obj, void *ud) /* filter internal objects */ switch (obj->tt) { - case MRB_TT_ENV: - case MRB_TT_ICLASS: + case MRB_TT_FREE: case MRB_TT_ENV: + case MRB_TT_BREAK: case MRB_TT_ICLASS: return MRB_EACH_OBJ_OK; default: break; @@ -158,12 +167,8 @@ os_each_object_cb(mrb_state *mrb, struct RBasic *obj, void *ud) static mrb_value os_each_object(mrb_state *mrb, mrb_value self) { - mrb_value cls = mrb_nil_value(); - struct os_each_object_data d; - mrb_get_args(mrb, "&!|C", &d.block, &cls); - - d.target_module = mrb_nil_p(cls) ? NULL : mrb_class_ptr(cls); - d.count = 0; + struct os_each_object_data d = {0}; + mrb_get_args(mrb, "&!|c", &d.block, &d.target_module); mrb_objspace_each_objects(mrb, os_each_object_cb, &d); return mrb_fixnum_value(d.count); } diff --git a/mrbgems/mruby-os-memsize/mrbgem.rake b/mrbgems/mruby-os-memsize/mrbgem.rake new file mode 100644 index 000000000..b5c163bba --- /dev/null +++ b/mrbgems/mruby-os-memsize/mrbgem.rake @@ -0,0 +1,10 @@ +MRuby::Gem::Specification.new('mruby-os-memsize') do |spec| + spec.license = 'MIT' + spec.author = 'mruby developers' + spec.summary = 'ObjectSpace memsize_of method' + + spec.add_dependency('mruby-objectspace') + spec.add_test_dependency('mruby-metaprog') + spec.add_test_dependency('mruby-method') + spec.add_test_dependency('mruby-fiber') +end diff --git a/mrbgems/mruby-os-memsize/src/memsize.c b/mrbgems/mruby-os-memsize/src/memsize.c new file mode 100644 index 000000000..65020c97f --- /dev/null +++ b/mrbgems/mruby-os-memsize/src/memsize.c @@ -0,0 +1,242 @@ +#include <mruby.h> +#include <mruby/gc.h> +#include <mruby/hash.h> +#include <mruby/class.h> +#include <mruby/object.h> +#include <mruby/numeric.h> +#include <mruby/string.h> +#include <mruby/array.h> +#include <mruby/variable.h> +#include <mruby/proc.h> +#include <mruby/value.h> +#include <mruby/range.h> + +static mrb_int +os_memsize_of_ivars(mrb_state* mrb, mrb_value obj) +{ + return mrb_obj_iv_tbl_memsize(mrb, obj); +} + +static mrb_int +os_memsize_of_irep(mrb_state* state, const struct mrb_irep *irep) +{ + mrb_int size, i; + size = (irep->slen * sizeof(mrb_sym)) + + (irep->plen * sizeof(mrb_code)) + + (irep->ilen * sizeof(mrb_code)); + + for(i = 0; i < irep->rlen; i++) { + size += os_memsize_of_irep(state, irep->reps[i]); + } + return size; +} + +static mrb_int +os_memsize_of_method(mrb_state* mrb, mrb_value method_obj) +{ + mrb_int size; + mrb_value proc_value = mrb_obj_iv_get(mrb, mrb_obj_ptr(method_obj), + mrb_intern_lit(mrb, "_proc")); + struct RProc *proc = mrb_proc_ptr(proc_value); + + size = sizeof(struct RProc); + if (!MRB_PROC_CFUNC_P(proc)) size += os_memsize_of_irep(mrb, proc->body.irep); + return size; +} + +static mrb_bool +obj_is_kind_of_checked(mrb_state *mrb, mrb_value obj, const char *classname) +{ + mrb_value objclass = mrb_obj_value(mrb->object_class); + + if (mrb_const_defined(mrb, objclass, mrb_intern_cstr(mrb, classname))) { + struct RClass *klass = mrb_class_get(mrb, classname); + return mrb_obj_is_kind_of(mrb, obj, klass); + } + + return FALSE; +} + +static mrb_int +os_memsize_of_object(mrb_state* mrb, mrb_value obj) +{ + mrb_int size = 0; + + switch(mrb_type(obj)) { + case MRB_TT_STRING: + size += mrb_objspace_page_slot_size(); + if (!RSTR_EMBED_P(RSTRING(obj)) && !RSTR_SHARED_P(RSTRING(obj))) { + size += RSTRING_CAPA(obj); + size++; /* NUL terminator */ + } + break; + case MRB_TT_CLASS: + case MRB_TT_MODULE: + case MRB_TT_SCLASS: + case MRB_TT_ICLASS: + size += mrb_gc_mark_mt_size(mrb, mrb_class_ptr(obj)) * sizeof(mrb_method_t); + /* fall through */ + case MRB_TT_EXCEPTION: + case MRB_TT_OBJECT: { + size += mrb_objspace_page_slot_size(); + size += os_memsize_of_ivars(mrb, obj); + if (obj_is_kind_of_checked(mrb, obj, "UnboundMethod") || + obj_is_kind_of_checked(mrb, obj, "Method")) { + size += os_memsize_of_method(mrb, obj); + } + break; + } + case MRB_TT_HASH: { + size += mrb_objspace_page_slot_size() + + mrb_os_memsize_of_hash_table(obj); + break; + } + case MRB_TT_ARRAY: { + mrb_int len = RARRAY_LEN(obj); + /* Arrays that do not fit within an RArray perform a heap allocation + * storing an array of pointers to the original objects*/ + size += mrb_objspace_page_slot_size(); + if(len > MRB_ARY_EMBED_LEN_MAX) size += sizeof(mrb_value *) * len; + break; + } + case MRB_TT_PROC: { + struct RProc* proc = mrb_proc_ptr(obj); + size += mrb_objspace_page_slot_size(); + size += MRB_ENV_LEN(proc->e.env) * sizeof(mrb_value); + if(!MRB_PROC_CFUNC_P(proc)) size += os_memsize_of_irep(mrb, proc->body.irep); + break; + } + case MRB_TT_DATA: + size += mrb_objspace_page_slot_size(); + break; +#ifndef MRB_WITHOUT_FLOAT + case MRB_TT_FLOAT: +#ifdef MRB_WORD_BOXING + size += mrb_objspace_page_slot_size() + + sizeof(struct RFloat); +#endif + break; +#endif + case MRB_TT_RANGE: +#ifndef MRB_RANGE_EMBED + size += mrb_objspace_page_slot_size() + + sizeof(struct mrb_range_edges); +#endif + break; + case MRB_TT_FIBER: { + struct RFiber* f = (struct RFiber *)mrb_ptr(obj); + ptrdiff_t stack_size = f->cxt->stend - f->cxt->stbase; + ptrdiff_t ci_size = f->cxt->ciend - f->cxt->cibase; + + 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; + } + case MRB_TT_ISTRUCT: + size += mrb_objspace_page_slot_size(); + break; + /* zero heap size types. + * immediate VM stack values, contained within mrb_state, or on C stack */ + case MRB_TT_TRUE: + case MRB_TT_FALSE: + case MRB_TT_FIXNUM: + case MRB_TT_BREAK: + case MRB_TT_CPTR: + case MRB_TT_SYMBOL: + case MRB_TT_FREE: + case MRB_TT_UNDEF: + case MRB_TT_ENV: + /* never used, silences compiler warning + * not having a default: clause lets the compiler tell us when there is a new + * TT not accounted for */ + case MRB_TT_MAXDEFINE: + break; + } + return size; +} + +/* + * call-seq: + * ObjectSpace.memsize_of(obj) -> Numeric + * + * Returns the amount of heap memory allocated for object in size_t units. + * + * The return value depends on the definition of size_t on that platform, + * therefore the value is not comparable across platform types. + * + * Immediate values such as integers, booleans, symbols and unboxed float numbers + * return 0. Additionally special objects which are small enough to fit inside an + * object pointer, termed embedded objects, will return the size of the object pointer. + * Strings and arrays below a compile-time defined size may be embedded. + */ + +static mrb_value +os_memsize_of(mrb_state *mrb, mrb_value self) +{ + mrb_int total; + mrb_value obj; + + mrb_get_args(mrb, "o", &obj); + + total = os_memsize_of_object(mrb, obj); + return mrb_fixnum_value(total); +} + +struct os_memsize_of_all_cb_data { + mrb_int t; + struct RClass *type; +}; + +static int +os_memsize_of_all_cb(mrb_state *mrb, struct RBasic *obj, void *d) +{ + struct os_memsize_of_all_cb_data *data = (struct os_memsize_of_all_cb_data *)d; + switch (obj->tt) { + case MRB_TT_FREE: case MRB_TT_ENV: + case MRB_TT_BREAK: case MRB_TT_ICLASS: + /* internal objects that should not be counted */ + return MRB_EACH_OBJ_OK; + default: + break; + } + /* skip Proc objects for methods */ + if (obj->c == NULL) return 0; + if (data->type == NULL || mrb_obj_is_kind_of(mrb, mrb_obj_value(obj), data->type)) + data->t += os_memsize_of_object(mrb, mrb_obj_value(obj)); + return MRB_EACH_OBJ_OK; +} + +/* + * call-seq: + * ObjectSpace.memsize_of_all([klass]) -> Numeric + * + * Return consuming memory size of all living objects of type klass. + * + */ + +static mrb_value +os_memsize_of_all(mrb_state *mrb, mrb_value self) +{ + struct os_memsize_of_all_cb_data data = { 0 }; + mrb_get_args(mrb, "|c", &data.type); + mrb_objspace_each_objects(mrb, os_memsize_of_all_cb, &data); + return mrb_fixnum_value(data.t); +} + +void +mrb_mruby_os_memsize_gem_init(mrb_state *mrb) +{ + struct RClass *os = mrb_module_get(mrb, "ObjectSpace"); + mrb_define_class_method(mrb, os, "memsize_of", os_memsize_of, MRB_ARGS_REQ(1)); + mrb_define_class_method(mrb, os, "memsize_of_all", os_memsize_of_all, MRB_ARGS_OPT(1)); +} + +void +mrb_mruby_os_memsize_gem_final(mrb_state *mrb) +{ +} diff --git a/mrbgems/mruby-os-memsize/test/memsize.rb b/mrbgems/mruby-os-memsize/test/memsize.rb new file mode 100644 index 000000000..6be8f1b06 --- /dev/null +++ b/mrbgems/mruby-os-memsize/test/memsize.rb @@ -0,0 +1,63 @@ +assert 'ObjectSpace.memsize_of' do + # immediate literals + int_size = ObjectSpace.memsize_of 1 + assert_equal int_size, 0, 'int zero' + + sym_size = ObjectSpace.memsize_of :foo + assert_equal sym_size, 0, 'sym zero' + + assert_equal ObjectSpace.memsize_of(true), int_size + assert_equal ObjectSpace.memsize_of(false), int_size + + assert_not_equal ObjectSpace.memsize_of('a'), 0, 'memsize of str' + + if __ENCODING__ == "UTF-8" + assert_not_equal ObjectSpace.memsize_of("こんにちは世界"), 0, 'memsize of utf8 str' + end + + # class defs + class_obj_size = ObjectSpace.memsize_of Class + assert_not_equal class_obj_size, 0, 'Class obj not zero' + + empty_class_def_size = ObjectSpace.memsize_of Class.new + assert_not_equal empty_class_def_size, 0, 'Class def not zero' + + proc_size = ObjectSpace.memsize_of Proc.new { x = 1; x } + assert_not_equal proc_size, 0 + + class_with_methods = Class.new do + def foo + a = 0 + a + 1 + end + end + + m_size = ObjectSpace.memsize_of class_with_methods.instance_method(:foo) + assert_not_equal m_size, 0, 'method size not zero' + + # collections + empty_array_size = ObjectSpace.memsize_of [] + assert_not_equal empty_array_size, 0, 'empty array size not zero' + assert_operator empty_array_size, :<, ObjectSpace.memsize_of(Array.new(16)), 'large array size greater than embed' + + # fiber + empty_fiber_size = ObjectSpace.memsize_of(Fiber.new {}) + assert_not_equal empty_fiber_size, 0, 'empty fiber not zero' + + #hash + assert_not_equal ObjectSpace.memsize_of({}), 0, 'empty hash size not zero' +end + +assert 'ObjectSpace.memsize_of_all' do + foo_class = Class.new do + def initialize + @a = 'a' + @b = 'b' + end + end + + foos = Array.new(10) { foo_class.new } + foo_size = ObjectSpace.memsize_of(foos.first) + + assert_equal ObjectSpace.memsize_of_all(foo_class), foo_size * foos.size, 'Memsize of all instance' +end diff --git a/mrbgems/mruby-pack/src/pack.c b/mrbgems/mruby-pack/src/pack.c index 3a2c3367a..80de397f4 100644 --- a/mrbgems/mruby-pack/src/pack.c +++ b/mrbgems/mruby-pack/src/pack.c @@ -1298,7 +1298,8 @@ mrb_pack_pack(mrb_state *mrb, mrb_value ary) default: break; } - if (dir == PACK_DIR_STR || dir == PACK_DIR_BASE64) { /* always consumes 1 entry */ + if (dir == PACK_DIR_STR || dir == PACK_DIR_BASE64 || dir == PACK_DIR_HEX) { + /* always consumes 1 entry */ aidx++; break; } diff --git a/mrbgems/mruby-print/mrblib/print.rb b/mrbgems/mruby-print/mrblib/print.rb index cfe14a5e1..6383901ee 100644 --- a/mrbgems/mruby-print/mrblib/print.rb +++ b/mrbgems/mruby-print/mrblib/print.rb @@ -4,38 +4,9 @@ # ISO 15.3.1 module Kernel ## - # Invoke method +print+ on STDOUT and passing +*args+ - # - # ISO 15.3.1.2.10 - def print(*args) - i = 0 - len = args.size - while i < len - __printstr__ args[i].to_s - i += 1 - end - end - - ## - # Invoke method +puts+ on STDOUT and passing +*args*+ - # - # ISO 15.3.1.2.11 - def puts(*args) - i = 0 - len = args.size - while i < len - s = args[i].to_s - __printstr__ s - __printstr__ "\n" if (s[-1] != "\n") - i += 1 - end - __printstr__ "\n" if len == 0 - nil - end - - ## # Print human readable object description # + # ISO 15.3.1.2.9 # ISO 15.3.1.3.34 def p(*args) i = 0 diff --git a/mrbgems/mruby-print/src/print.c b/mrbgems/mruby-print/src/print.c index 9301dbe55..df153d920 100644 --- a/mrbgems/mruby-print/src/print.c +++ b/mrbgems/mruby-print/src/print.c @@ -17,39 +17,73 @@ #endif static void -printstr(mrb_state *mrb, mrb_value obj) +printstr(mrb_state *mrb, const char *p, size_t len) { - if (mrb_string_p(obj)) { #if defined(_WIN32) - if (isatty(fileno(stdout))) { - DWORD written; - int mlen = (int)RSTRING_LEN(obj); - char* utf8 = RSTRING_PTR(obj); - int wlen = MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, NULL, 0); - wchar_t* utf16 = (wchar_t*)mrb_malloc(mrb, (wlen+1) * sizeof(wchar_t)); - if (MultiByteToWideChar(CP_UTF8, 0, utf8, mlen, utf16, wlen) > 0) { - utf16[wlen] = 0; - WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), - utf16, wlen, &written, NULL); - } - mrb_free(mrb, utf16); - } else + if (isatty(fileno(stdout))) { + DWORD written; + int wlen = MultiByteToWideChar(CP_UTF8, 0, p, len, NULL, 0); + wchar_t* utf16 = (wchar_t*)mrb_malloc(mrb, (wlen+1) * sizeof(wchar_t)); + if (MultiByteToWideChar(CP_UTF8, 0, p, len, utf16, wlen) > 0) { + utf16[wlen] = 0; + WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), + utf16, wlen, &written, NULL); + } + mrb_free(mrb, utf16); + } else #endif - fwrite(RSTRING_PTR(obj), RSTRING_LEN(obj), 1, stdout); - fflush(stdout); - } + fwrite(p, len, 1, stdout); + fflush(stdout); } -/* 15.3.1.2.9 */ -/* 15.3.1.3.34 */ -mrb_value +static mrb_value mrb_printstr(mrb_state *mrb, mrb_value self) { - mrb_value argv = mrb_get_arg1(mrb); + mrb_value s = mrb_get_arg1(mrb); + + if (mrb_string_p(s)) { + printstr(mrb, RSTRING_PTR(s), RSTRING_LEN(s)); + } + return s; +} + +/* 15.3.1.2.10 */ +/* 15.3.1.3.35 */ +static mrb_value +mrb_print(mrb_state *mrb, mrb_value self) +{ + mrb_int argc, i; + mrb_value *argv; - printstr(mrb, argv); + mrb_get_args(mrb, "*", &argv, &argc); + for (i=0; i<argc; i++) { + mrb_value s = mrb_str_to_str(mrb, argv[i]); + printstr(mrb, RSTRING_PTR(s), RSTRING_LEN(s)); + } + return mrb_nil_value(); +} + +/* 15.3.1.2.11 */ +/* 15.3.1.3.39 */ +static mrb_value +mrb_puts(mrb_state *mrb, mrb_value self) +{ + mrb_int argc, i; + mrb_value *argv; - return argv; + mrb_get_args(mrb, "*", &argv, &argc); + for (i=0; i<argc; i++) { + mrb_value s = mrb_str_to_str(mrb, argv[i]); + mrb_int len = RSTRING_LEN(s); + printstr(mrb, RSTRING_PTR(s), len); + if (len == 0 || RSTRING_PTR(s)[len-1] != '\n') { + printstr(mrb, "\n", 1); + } + } + if (argc == 0) { + printstr(mrb, "\n", 1); + } + return mrb_nil_value(); } void @@ -58,6 +92,8 @@ mrb_mruby_print_gem_init(mrb_state* mrb) struct RClass *krn; krn = mrb->kernel_module; mrb_define_method(mrb, krn, "__printstr__", mrb_printstr, MRB_ARGS_REQ(1)); + mrb_define_method(mrb, krn, "print", mrb_print, MRB_ARGS_ANY()); + mrb_define_method(mrb, krn, "puts", mrb_puts, MRB_ARGS_ANY()); } void diff --git a/mrbgems/mruby-random/src/random.c b/mrbgems/mruby-random/src/random.c index 515c0707a..10c81b946 100644 --- a/mrbgems/mruby-random/src/random.c +++ b/mrbgems/mruby-random/src/random.c @@ -218,6 +218,34 @@ mrb_ary_shuffle_bang(mrb_state *mrb, mrb_value ary) mrb_value r = mrb_nil_value(); rand_state *random; + /* + * MSC compiler bug generating invalid instructions with optimization + * enabled. MSC errantly uses a hardcoded value with optimizations on + * when using a fixed value from a union. + * Creating a temp volatile variable and reassigning back to the original + * value tricks the compiler to not perform this optimization; + */ +#if defined _MSC_VER && _MSC_VER >= 1923 + /* C++ will not cast away volatile easily, so we cannot do something like + * volatile mrb_value rr = r; r = (mrb_value)rr; with C++. + * That cast does work with C. + * We also have to trick the compiler to not optimize away the const_cast entirely + * by creating and manipulating an intermediate volatile pointer. + */ + volatile mrb_value *v_r; + volatile mrb_int ii; + mrb_value *p_r; + v_r = &r; + ii = 2; + v_r = v_r + 2; +#if defined __cplusplus + p_r = const_cast<mrb_value*>(v_r - ii); +#else + p_r = (mrb_value*)v_r - ii; +#endif + r = *p_r; +#endif + if (RARRAY_LEN(ary) > 1) { mrb_get_args(mrb, "|o", &r); diff --git a/mrbgems/mruby-test/mrbgem.rake b/mrbgems/mruby-test/mrbgem.rake index 97189a67b..ced252ae6 100644 --- a/mrbgems/mruby-test/mrbgem.rake +++ b/mrbgems/mruby-test/mrbgem.rake @@ -146,20 +146,8 @@ MRuby::Gem::Specification.new('mruby-test') do |spec| end end - # store the last gem selection and make the re-build - # of the test gem depending on a change to the gem - # selection - active_gems_path = "#{build_dir}/active_gems_path.lst" - active_gem_list = File.read active_gems_path if File.exist? active_gems_path - current_gem_list = build.gems.map(&:name).join("\n") - task active_gems_path do |_t| - mkdir_p File.dirname(active_gems_path) - File.write active_gems_path, current_gem_list - end - file clib => active_gems_path if active_gem_list != current_gem_list - file mlib => clib - file clib => [build.mrbcfile, __FILE__] do |_t| + file clib => ["#{build.build_dir}/mrbgems/active_gems.txt", build.mrbcfile, __FILE__] do |_t| _pp "GEN", "*.rb", "#{clib.relative_path}" mkdir_p File.dirname(clib) open(clib, 'w') do |f| diff --git a/mrblib/array.rb b/mrblib/array.rb index 6535d6d83..8586fbc39 100644 --- a/mrblib/array.rb +++ b/mrblib/array.rb @@ -12,7 +12,7 @@ class Array # ISO 15.2.12.5.10 # def each(&block) # return to_enum :each unless block - + # # idx = 0 # while idx < length # block.call(self[idx]) @@ -268,4 +268,8 @@ class Array def sort(&block) self.dup.sort!(&block) end + + def to_a + self + end end diff --git a/src/array.c b/src/array.c index dae2fbf34..ef8588d31 100644 --- a/src/array.c +++ b/src/array.c @@ -522,8 +522,10 @@ mrb_ary_push_m(mrb_state *mrb, mrb_value self) } array_copy(ARY_PTR(a)+len, argv, alen); ARY_SET_LEN(a, len2); - mrb_write_barrier(mrb, (struct RBasic*)a); - + while (alen--) { + mrb_field_write_barrier_value(mrb, (struct RBasic*)a, *argv); + argv++; + } return self; } @@ -941,7 +943,7 @@ mrb_ary_aset(mrb_state *mrb, mrb_value self) mrb_value v1, v2, v3; mrb_int i, len; - mrb_ary_modify(mrb, mrb_ary_ptr(self)); + ary_modify(mrb, mrb_ary_ptr(self)); if (mrb_get_argc(mrb) == 2) { mrb_value *vs = mrb_get_argv(mrb); v1 = vs[0]; v2 = vs[1]; diff --git a/src/class.c b/src/class.c index 1a36c1333..fc8a38ff9 100644 --- a/src/class.c +++ b/src/class.c @@ -587,6 +587,7 @@ void mrb_hash_check_kdict(mrb_state *mrb, mrb_value self); s: String [char*,mrb_int] Receive two arguments; s! gives (NULL,0) for nil z: String [char*] NUL terminated string; z! gives NULL for nil a: Array [mrb_value*,mrb_int] Receive two arguments; a! gives (NULL,0) for nil + c: Class/Module [strcut RClass*] f: Fixnum/Float [mrb_float] i: Fixnum/Float [mrb_int] b: boolean [mrb_bool] @@ -713,6 +714,22 @@ mrb_get_args(mrb_state *mrb, const char *format, ...) } } break; + case 'c': + { + struct RClass **p; + + p = va_arg(ap, struct RClass**); + if (i < argc) { + mrb_value ss; + + ss = argv[i++]; + if (!class_ptr_p(ss)) { + mrb_raisef(mrb, E_TYPE_ERROR, "%v is not class/module", ss); + } + *p = mrb_class_ptr(ss); + } + } + break; case 'S': { mrb_value *p; @@ -1151,22 +1168,22 @@ mrb_prepend_module(mrb_state *mrb, struct RClass *c, struct RClass *m) static mrb_value mrb_mod_prepend_features(mrb_state *mrb, mrb_value mod) { - mrb_value klass; + struct RClass *c; mrb_check_type(mrb, mod, MRB_TT_MODULE); - mrb_get_args(mrb, "C", &klass); - mrb_prepend_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod)); + mrb_get_args(mrb, "c", &c); + mrb_prepend_module(mrb, c, mrb_class_ptr(mod)); return mod; } static mrb_value mrb_mod_append_features(mrb_state *mrb, mrb_value mod) { - mrb_value klass; + struct RClass *c; mrb_check_type(mrb, mod, MRB_TT_MODULE); - mrb_get_args(mrb, "C", &klass); - mrb_include_module(mrb, mrb_class_ptr(klass), mrb_class_ptr(mod)); + mrb_get_args(mrb, "c", &c); + mrb_include_module(mrb, c, mrb_class_ptr(mod)); return mod; } @@ -107,10 +107,11 @@ mrb_obj_id(mrb_value obj) return MakeID(0); /* not define */ case MRB_TT_FALSE: if (mrb_nil_p(obj)) - return MakeID(1); - return MakeID(0); + return MakeID(4); + else + return MakeID(0); case MRB_TT_TRUE: - return MakeID(1); + return MakeID(2); case MRB_TT_SYMBOL: return MakeID(mrb_symbol(obj)); case MRB_TT_FIXNUM: @@ -225,14 +225,8 @@ mrb_realloc(mrb_state *mrb, void *p, size_t len) p2 = mrb_realloc_simple(mrb, p, len); if (len == 0) return p2; if (p2 == NULL) { - if (mrb->gc.out_of_memory) { - mrb_raise_nomemory(mrb); - /* mrb_panic(mrb); */ - } - else { - mrb->gc.out_of_memory = TRUE; - mrb_raise_nomemory(mrb); - } + mrb->gc.out_of_memory = TRUE; + mrb_raise_nomemory(mrb); } else { mrb->gc.out_of_memory = FALSE; @@ -673,7 +667,6 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) { mrb_assert(is_gray(obj)); paint_black(obj); - gc->gray_list = obj->gcnext; mrb_gc_mark(mrb, (struct RBasic*)obj->c); switch (obj->tt) { case MRB_TT_ICLASS: @@ -737,10 +730,11 @@ gc_mark_children(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) case MRB_TT_ARRAY: { struct RArray *a = (struct RArray*)obj; - size_t i, e; + size_t i, e=ARY_LEN(a); + mrb_value *p = ARY_PTR(a); - for (i=0,e=ARY_LEN(a); i<e; i++) { - mrb_gc_mark_value(mrb, ARY_PTR(a)[i]); + for (i=0; i<e; i++) { + mrb_gc_mark_value(mrb, p[i]); } } break; @@ -1049,10 +1043,9 @@ gc_gray_counts(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj) static void gc_mark_gray_list(mrb_state *mrb, mrb_gc *gc) { while (gc->gray_list) { - if (is_gray(gc->gray_list)) - gc_mark_children(mrb, gc, gc->gray_list); - else - gc->gray_list = gc->gray_list->gcnext; + struct RBasic *obj = gc->gray_list; + gc->gray_list = obj->gcnext; + gc_mark_children(mrb, gc, obj); } } @@ -1064,6 +1057,7 @@ incremental_marking_phase(mrb_state *mrb, mrb_gc *gc, size_t limit) while (gc->gray_list && tried_marks < limit) { struct RBasic *obj = gc->gray_list; + gc->gray_list = obj->gcnext; gc_mark_children(mrb, gc, obj); tried_marks += gc_gray_counts(mrb, gc, obj); } @@ -1082,7 +1076,9 @@ final_marking_phase(mrb_state *mrb, mrb_gc *gc) } mrb_gc_mark_gv(mrb); mark_context(mrb, mrb->c); - mark_context(mrb, mrb->root_c); + if (mrb->c != mrb->root_c) { + mark_context(mrb, mrb->root_c); + } mrb_gc_mark(mrb, (struct RBasic*)mrb->exc); gc_mark_gray_list(mrb, gc); mrb_assert(gc->gray_list == NULL); @@ -1605,6 +1601,13 @@ mrb_objspace_each_objects(mrb_state *mrb, mrb_each_object_callback *callback, vo } } +mrb_int +mrb_objspace_page_slot_size(void) +{ + const mrb_int i = sizeof(RVALUE); + return i; +} + #ifdef GC_TEST #ifdef GC_DEBUG static mrb_value gc_test(mrb_state *, mrb_value); diff --git a/src/hash.c b/src/hash.c index d9ee483d5..fd338d53b 100644 --- a/src/hash.c +++ b/src/hash.c @@ -174,6 +174,11 @@ ht_index(mrb_state *mrb, htable *t) segment *seg; size_t i; + if (size == 0) { + t->index = NULL; + mrb_free(mrb, index); + return; + } /* allocate index table */ if (index && index->size >= UPPER_BOUND(index->capa)) { size = index->capa+1; @@ -194,7 +199,7 @@ ht_index(mrb_state *mrb, htable *t) index->table[i] = NULL; } - /* rebuld index */ + /* rebuild index */ mask = HT_MASK(index); seg = t->rootseg; while (seg) { @@ -518,6 +523,20 @@ ht_foreach(mrb_state *mrb, htable *t, mrb_hash_foreach_func *func, void *p) } } +mrb_int +mrb_os_memsize_of_hash_table(mrb_value obj) +{ + struct htable *h = mrb_hash_ptr(obj)->ht; + mrb_int segkv_size = 0; + + if(h->index) segkv_size = (sizeof(struct segkv) * h->index->capa); + + return sizeof(htable) + + sizeof(segindex) + + (sizeof(segment) * h->size) + + segkv_size; +} + /* Iterates over the hash table. */ MRB_API void mrb_hash_foreach(mrb_state *mrb, struct RHash *hash, mrb_hash_foreach_func *func, void *p) @@ -1053,7 +1072,8 @@ mrb_hash_shift(mrb_state *mrb, mrb_value hash) mrb_hash_modify(mrb, hash); if (t && t->size > 0) { - mrb_value del_key, del_val; + mrb_value del_key = mrb_nil_value(); + mrb_value del_val = mrb_nil_value(); ht_shift(mrb, t, &del_key, &del_val); mrb_gc_protect(mrb, del_key); diff --git a/src/kernel.c b/src/kernel.c index 8f0c9c7b5..682feb13c 100644 --- a/src/kernel.c +++ b/src/kernel.c @@ -99,6 +99,18 @@ mrb_obj_id_m(mrb_state *mrb, mrb_value self) return mrb_fixnum_value(mrb_obj_id(self)); } +static int +env_bidx(struct REnv *e) +{ + int bidx; + + /* use saved block arg position */ + bidx = MRB_ENV_BIDX(e); + /* bidx may be useless (e.g. define_method) */ + if (bidx >= MRB_ENV_LEN(e)) return -1; + return bidx; +} + /* 15.3.1.2.2 */ /* 15.3.1.2.5 */ /* 15.3.1.3.6 */ @@ -129,6 +141,8 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) mrb_callinfo *ci = &mrb->c->ci[-1]; mrb_callinfo *cibase = mrb->c->cibase; mrb_value *bp; + int bidx; + struct REnv *e = NULL; struct RProc *p; if (ci <= cibase) { @@ -139,29 +153,36 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) /* search method/class/module proc */ while (p) { if (MRB_PROC_SCOPE_P(p)) break; + e = MRB_PROC_ENV(p); p = p->upper; } if (p == NULL) return mrb_false_value(); + if (e) { + bidx = env_bidx(e); + if (bidx < 0) return mrb_false_value(); + bp = &e->stack[bidx]; + goto block_given; + } /* search ci corresponding to proc */ while (cibase < ci) { if (ci->proc == p) break; ci--; } if (ci == cibase) { - return mrb_false_value(); + /* proc is closure */ + if (!MRB_PROC_ENV_P(p)) return mrb_false_value(); + e = MRB_PROC_ENV(p); + bidx = env_bidx(e); + if (bidx < 0) return mrb_false_value(); + bp = &e->stack[bidx]; } else if (ci->env) { - struct REnv *e = ci->env; - int bidx; - + e = ci->env; /* top-level does not have block slot (always false) */ - if (e->stack == mrb->c->stbase) - return mrb_false_value(); - /* use saved block arg position */ - bidx = MRB_ENV_BIDX(e); + if (e->stack == mrb->c->stbase) return mrb_false_value(); + bidx = env_bidx(e); /* bidx may be useless (e.g. define_method) */ - if (bidx >= MRB_ENV_LEN(e)) - return mrb_false_value(); + if (bidx < 0) return mrb_false_value(); bp = &e->stack[bidx]; } else { @@ -173,6 +194,7 @@ mrb_f_block_given_p_m(mrb_state *mrb, mrb_value self) bp++; } } + block_given: if (mrb_nil_p(*bp)) return mrb_false_value(); return mrb_true_value(); @@ -498,11 +520,11 @@ mrb_obj_is_instance_of(mrb_state *mrb, mrb_value obj, struct RClass* c) static mrb_value obj_is_instance_of(mrb_state *mrb, mrb_value self) { - mrb_value arg; + struct RClass *c; - mrb_get_args(mrb, "C", &arg); + mrb_get_args(mrb, "c", &c); - return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, mrb_class_ptr(arg))); + return mrb_bool_value(mrb_obj_is_instance_of(mrb, self, c)); } /* 15.3.1.3.24 */ @@ -535,11 +557,11 @@ obj_is_instance_of(mrb_state *mrb, mrb_value self) static mrb_value mrb_obj_is_kind_of_m(mrb_state *mrb, mrb_value self) { - mrb_value arg; + struct RClass *c; - mrb_get_args(mrb, "C", &arg); + mrb_get_args(mrb, "c", &c); - return mrb_bool_value(mrb_obj_is_kind_of(mrb, self, mrb_class_ptr(arg))); + return mrb_bool_value(mrb_obj_is_kind_of(mrb, self, c)); } KHASH_DECLARE(st, mrb_sym, char, FALSE) diff --git a/src/object.c b/src/object.c index db9dfb568..7257f402d 100644 --- a/src/object.c +++ b/src/object.c @@ -338,6 +338,7 @@ mrb_convert_type(mrb_state *mrb, mrb_value val, enum mrb_vtype type, const char if (mrb_type(val) == type) return val; v = convert_type(mrb, val, tname, method, TRUE); if (mrb_type(v) != type) { + if (type == MRB_TT_STRING) return mrb_any_to_s(mrb, val); mrb_raisef(mrb, E_TYPE_ERROR, "%v cannot be converted to %s by #%s", val, tname, method); } return v; diff --git a/src/state.c b/src/state.c index 533bdaa0b..790f7ca13 100644 --- a/src/state.c +++ b/src/state.c @@ -164,8 +164,6 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep) mrb_free(mrb, irep); } -void mrb_free_backtrace(mrb_state *mrb); - MRB_API void mrb_free_context(mrb_state *mrb, struct mrb_context *c) { diff --git a/src/string.c b/src/string.c index f1ffbe43d..78c41c5f3 100644 --- a/src/string.c +++ b/src/string.c @@ -1121,6 +1121,7 @@ mrb_str_to_str(mrb_state *mrb, mrb_value str) return mrb_sym_str(mrb, mrb_symbol(str)); case MRB_TT_FIXNUM: return mrb_fixnum_to_str(mrb, str, 10); + case MRB_TT_SCLASS: case MRB_TT_CLASS: case MRB_TT_MODULE: return mrb_mod_to_s(mrb, str); diff --git a/src/variable.c b/src/variable.c index 030aa7b00..f05fcee90 100644 --- a/src/variable.c +++ b/src/variable.c @@ -349,7 +349,7 @@ mrb_obj_iv_set_force(mrb_state *mrb, struct RObject *obj, mrb_sym sym, mrb_value obj->iv = iv_new(mrb); } iv_put(mrb, obj->iv, sym, v); - mrb_write_barrier(mrb, (struct RBasic*)obj); + mrb_field_write_barrier_value(mrb, (struct RBasic*)obj, v); } MRB_API void @@ -679,7 +679,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) if (iv_get(mrb, t, sym, NULL)) { mrb_check_frozen(mrb, c); iv_put(mrb, t, sym, v); - mrb_write_barrier(mrb, (struct RBasic*)c); + mrb_field_write_barrier_value(mrb, (struct RBasic*)c, v); return; } c = c->super; @@ -711,7 +711,7 @@ mrb_mod_cv_set(mrb_state *mrb, struct RClass *c, mrb_sym sym, mrb_value v) } iv_put(mrb, c->iv, sym, v); - mrb_write_barrier(mrb, (struct RBasic*)c); + mrb_field_write_barrier_value(mrb, (struct RBasic*)c, v); } MRB_API void @@ -1128,6 +1128,21 @@ mrb_class_find_path(mrb_state *mrb, struct RClass *c) return path; } +mrb_int +mrb_obj_iv_tbl_memsize(mrb_state* mrb, mrb_value obj) +{ + size_t nseg = 0; + segment *seg; + + if (mrb_obj_ptr(obj)->iv == NULL) return 0; + seg = mrb_obj_ptr(obj)->iv->rootseg; + while (seg) { + nseg++; + seg = seg->next; + } + return sizeof(iv_tbl) + sizeof(segment)*nseg; +} + #define identchar(c) (ISALNUM(c) || (c) == '_' || !ISASCII(c)) mrb_bool @@ -269,14 +269,13 @@ top_proc(mrb_state *mrb, struct RProc *proc) #define CI_ACC_RESUMED -3 static inline mrb_callinfo* -cipush(mrb_state *mrb) +cipush(mrb_state *mrb, const mrb_code *pc, int push_stacks, int acc, + struct RClass *target_class, struct RProc *proc, mrb_sym mid, int argc) { struct mrb_context *c = mrb->c; static const mrb_callinfo ci_zero = { 0 }; mrb_callinfo *ci = c->ci; - int ridx = ci->ridx; - if (ci + 1 == c->ciend) { ptrdiff_t size = ci - c->cibase; @@ -286,8 +285,16 @@ cipush(mrb_state *mrb) } ci = ++c->ci; *ci = ci_zero; - ci->epos = mrb->c->eidx; - ci->ridx = ridx; + 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; + ci->target_class = target_class; + c->stack += push_stacks; return ci; } @@ -313,14 +320,16 @@ mrb_env_unshare(mrb_state *mrb, struct REnv *e) } } -static inline void +static inline mrb_callinfo* cipop(mrb_state *mrb) { struct mrb_context *c = mrb->c; struct REnv *env = c->ci->env; + mrb->c->stack = c->ci->stackent; c->ci--; if (env) mrb_env_unshare(mrb, env); + return c->ci; } void mrb_exc_set(mrb_state *mrb, mrb_value exc); @@ -356,16 +365,9 @@ ecall(mrb_state *mrb) nregs = ci->proc->body.irep->nregs; } cioff = ci - c->cibase; - ci = cipush(mrb); - ci->stackent = mrb->c->stack; - ci->mid = ci[-1].mid; - ci->acc = CI_ACC_SKIP; - ci->argc = 0; - ci->proc = p; - ci->target_class = MRB_PROC_TARGET_CLASS(p); + 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); - c->stack += nregs; exc = mrb->exc; mrb->exc = 0; if (exc) { mrb_gc_protect(mrb, mrb_obj_value(exc)); @@ -447,7 +449,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc } MRB_CATCH(&c_jmp) { /* error */ while (nth_ci < (mrb->c->ci - mrb->c->cibase)) { - mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); } mrb->jmp = 0; @@ -486,12 +487,7 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc if (mrb->c->ci - mrb->c->cibase > MRB_FUNCALL_DEPTH_MAX) { mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } - ci = cipush(mrb); - ci->mid = mid; - ci->stackent = mrb->c->stack; - ci->argc = (int)argc; - ci->target_class = c; - mrb->c->stack = mrb->c->stack + n; + ci = cipush(mrb, NULL, n, 0, c, NULL, mid, argc); if (argc < 0) argc = 1; if (mrb->c->stbase <= argv && argv < mrb->c->stend) { voff = argv - mrb->c->stbase; @@ -524,7 +520,6 @@ mrb_funcall_with_block(mrb_state *mrb, mrb_value self, mrb_sym mid, mrb_int argc if (MRB_METHOD_CFUNC_P(m)) { ci->acc = CI_ACC_DIRECT; val = MRB_METHOD_CFUNC(m)(mrb, self); - mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); } else { @@ -565,11 +560,7 @@ mrb_exec_irep(mrb_state *mrb, mrb_value self, struct RProc *p) stack_clear(mrb->c->stack+keep, nregs-keep); } - ci = cipush(mrb); - ci->target_class = 0; - ci->pc = p->body.irep->iseq; - ci->stackent = mrb->c->stack; - ci->acc = 0; + cipush(mrb, p->body.irep->iseq, 0, 0, NULL, NULL, 0, 0); return self; } @@ -671,11 +662,7 @@ eval_under(mrb_state *mrb, mrb_value self, mrb_value blk, struct RClass *c) mrb->c->stack[0] = self; mrb->c->stack[1] = self; stack_clear(mrb->c->stack+2, nregs-2); - ci = cipush(mrb); - ci->target_class = 0; - ci->pc = p->body.irep->iseq; - ci->stackent = mrb->c->stack; - ci->acc = 0; + ci = cipush(mrb, p->body.irep->iseq, 0, 0, NULL, NULL, 0, 0); return self; } @@ -751,13 +738,7 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value mrb_exc_raise(mrb, mrb_obj_value(mrb->stack_err)); } p = mrb_proc_ptr(b); - ci = cipush(mrb); - ci->mid = mid; - ci->proc = p; - ci->target_class = c; - ci->acc = CI_ACC_SKIP; - ci->stackent = mrb->c->stack; - mrb->c->stack += n; + ci = cipush(mrb, NULL, n, CI_ACC_SKIP, c, p, mid, 0 /* dummy */); if (argc >= CALL_MAXARGS) { ci->argc = -1; n = 3; @@ -779,7 +760,6 @@ mrb_yield_with_class(mrb_state *mrb, mrb_value b, mrb_int argc, const mrb_value if (MRB_PROC_CFUNC_P(p)) { val = MRB_PROC_CFUNC(p)(mrb, self); - mrb->c->stack = mrb->c->ci->stackent; cipop(mrb); } else { @@ -1328,15 +1308,7 @@ RETRY_TRY_BLOCK: mrb->c->ensure[epos+n] = NULL; if (proc == NULL) continue; irep = proc->body.irep; - ci = cipush(mrb); - ci->mid = ci[-1].mid; - ci->argc = 0; - ci->proc = proc; - ci->stackent = mrb->c->stack; - ci->target_class = target_class; - ci->pc = pc; - ci->acc = nregs; - mrb->c->stack += ci->acc; + ci = cipush(mrb, pc, nregs, nregs, target_class, proc, ci->mid, 0); mrb_stack_extend(mrb, irep->nregs); regs[0] = self; pc = irep->iseq; @@ -1418,17 +1390,7 @@ RETRY_TRY_BLOCK: } /* push callinfo */ - ci = cipush(mrb); - ci->mid = mid; - ci->stackent = mrb->c->stack; - ci->target_class = cls; - ci->argc = argc; - - ci->pc = pc; - ci->acc = a; - - /* prepare stack */ - mrb->c->stack += a; + ci = cipush(mrb, pc, a, a, cls, NULL, mid, argc); if (MRB_METHOD_CFUNC_P(m)) { if (MRB_METHOD_PROC_P(m)) { @@ -1470,7 +1432,6 @@ RETRY_TRY_BLOCK: } mrb->c->stack[0] = recv; /* pop stackpos */ - mrb->c->stack = ci->stackent; pc = ci->pc; cipop(mrb); JUMP; @@ -1508,10 +1469,9 @@ RETRY_TRY_BLOCK: if (mrb->exc) goto L_RAISE; /* pop stackpos */ ci = mrb->c->ci; - mrb->c->stack = ci->stackent; - regs[ci->acc] = recv; pc = ci->pc; cipop(mrb); + regs[ci->acc] = recv; irep = mrb->c->ci->proc->body.irep; pool = irep->pool; syms = irep->syms; @@ -1617,15 +1577,9 @@ RETRY_TRY_BLOCK: } /* push callinfo */ - ci = cipush(mrb); - ci->mid = mid; - ci->stackent = mrb->c->stack; - ci->target_class = cls; - ci->pc = pc; - ci->argc = argc; + ci = cipush(mrb, pc, a, 0, cls, NULL, mid, argc); /* prepare stack */ - mrb->c->stack += a; mrb->c->stack[0] = recv; if (MRB_METHOD_CFUNC_P(m)) { @@ -1652,8 +1606,6 @@ RETRY_TRY_BLOCK: } } mrb->c->stack[0] = v; - /* pop stackpos */ - mrb->c->stack = ci->stackent; pc = ci->pc; cipop(mrb); JUMP; @@ -1954,13 +1906,11 @@ RETRY_TRY_BLOCK: goto L_RESCUE; } while (ci[0].ridx == ci[-1].ridx) { - cipop(mrb); - mrb->c->stack = ci->stackent; - if (ci->acc == CI_ACC_SKIP && prev_jmp) { + ci = cipop(mrb); + if (ci[1].acc == CI_ACC_SKIP && prev_jmp) { mrb->jmp = prev_jmp; MRB_THROW(prev_jmp); } - ci = mrb->c->ci; if (ci == mrb->c->cibase) { if (ci->ridx == 0) { L_FTOP: /* fiber top */ @@ -2142,15 +2092,13 @@ RETRY_TRY_BLOCK: return v; } acc = ci->acc; - mrb->c->stack = ci->stackent; - cipop(mrb); + ci = cipop(mrb); if (acc == CI_ACC_SKIP || acc == CI_ACC_DIRECT) { mrb_gc_arena_restore(mrb, ai); mrb->jmp = prev_jmp; return v; } - pc = ci->pc; - ci = mrb->c->ci; + pc = ci[1].pc; DEBUG(fprintf(stderr, "from :%s\n", mrb_sym_name(mrb, ci->mid))); proc = mrb->c->ci->proc; irep = proc->body.irep; @@ -2664,7 +2612,6 @@ RETRY_TRY_BLOCK: } CASE(OP_EXEC, BB) { - mrb_callinfo *ci; mrb_value recv = regs[a]; struct RProc *p; mrb_irep *nirep = irep->reps[b]; @@ -2677,19 +2624,7 @@ RETRY_TRY_BLOCK: p->flags |= MRB_PROC_SCOPE; /* prepare call stack */ - ci = cipush(mrb); - ci->pc = pc; - ci->acc = a; - ci->mid = 0; - ci->stackent = mrb->c->stack; - ci->argc = 0; - ci->target_class = mrb_class_ptr(recv); - - /* prepare stack */ - mrb->c->stack += a; - - /* setup block to call */ - ci->proc = p; + cipush(mrb, pc, a, a, mrb_class_ptr(recv), p, 0, 0); irep = p->body.irep; pool = irep->pool; @@ -2834,7 +2769,6 @@ mrb_run(mrb_state *mrb, struct RProc *proc, mrb_value self) MRB_API mrb_value mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int stack_keep) { - mrb_callinfo *ci; mrb_value v; if (!mrb->c->cibase) { @@ -2844,11 +2778,7 @@ mrb_top_run(mrb_state *mrb, struct RProc *proc, mrb_value self, unsigned int sta mrb->c->ci->env = NULL; return mrb_vm_run(mrb, proc, self, stack_keep); } - ci = cipush(mrb); - ci->stackent = mrb->c->stack; - ci->mid = 0; - ci->acc = CI_ACC_SKIP; - ci->target_class = mrb->object_class; + cipush(mrb, NULL, 0, CI_ACC_SKIP, mrb->object_class, NULL, 0, 0); v = mrb_vm_run(mrb, proc, self, stack_keep); return v; diff --git a/tasks/benchmark.rake b/tasks/benchmark.rake index 84e69ebee..6352f5c17 100644 --- a/tasks/benchmark.rake +++ b/tasks/benchmark.rake @@ -5,7 +5,7 @@ end $dat_files = [] def bm_files - Dir.glob("#{MRUBY_ROOT}/benchmark/bm_*.rb") + Dir.glob("#{MRUBY_ROOT}/benchmark/bm_*.rb").sort end def build_config_name @@ -67,8 +67,8 @@ MRuby.each_target do |target| puts "..." data = (0...MRuby::BENCHMARK_REPEAT).map do |n| - str = %x{(time -f "%e %S %U" #{mruby_bin} #{bm_file}) 2>&1 >/dev/null} - str.split(' ').map(&:to_f) + str = %x{(time -p #{mruby_bin} #{bm_file}) 2>&1 >/dev/null} + str.scan(/\d+\.\d+$/).map(&:to_f) # [real, user, sys] end File.open(task.name, "w") do |f| diff --git a/tasks/mrbgems.rake b/tasks/mrbgems.rake index c814a16db..0a3ae652d 100644 --- a/tasks/mrbgems.rake +++ b/tasks/mrbgems.rake @@ -5,9 +5,10 @@ MRuby.each_target do gems.check self # loader all gems + active_gems_txt = "#{build_dir}/mrbgems/active_gems.txt" self.libmruby_objs << objfile("#{build_dir}/mrbgems/gem_init") file objfile("#{build_dir}/mrbgems/gem_init") => ["#{build_dir}/mrbgems/gem_init.c", "#{build_dir}/LEGAL"] - file "#{build_dir}/mrbgems/gem_init.c" => [MRUBY_CONFIG, __FILE__, *Dir.glob("#{build_dir}/mrbgems/mruby-*/*.c")] do |t| + file "#{build_dir}/mrbgems/gem_init.c" => [active_gems_txt, MRUBY_CONFIG, __FILE__] do |t| mkdir_p "#{build_dir}/mrbgems" open(t.name, 'w') do |f| gem_func_gems = gems.select { |g| g.generate_functions } @@ -49,6 +50,15 @@ MRuby.each_target do f.puts %Q[}] end end + file active_gems_txt => :generate_active_gems_txt + task :generate_active_gems_txt do |t| + def t.timestamp; Time.at(0) end + active_gems = gems.sort_by(&:name).inject(""){|s, g| s << "#{g.name}\n"} + if !File.exist?(active_gems_txt) || File.read(active_gems_txt) != active_gems + mkdir_p File.dirname(active_gems_txt) + File.write(active_gems_txt, active_gems) + end + end end # legal documents |
