[前][次][番号順一覧][スレッド一覧]

ruby-changes:50079

From: k0kubun <ko1@a...>
Date: Sun, 4 Feb 2018 20:22:38 +0900 (JST)
Subject: [ruby-changes:50079] k0kubun:r62197 (trunk): mjit_compile.c: merge initial JIT compiler

k0kubun	2018-02-04 20:22:28 +0900 (Sun, 04 Feb 2018)

  New Revision: 62197

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=62197

  Log:
    mjit_compile.c: merge initial JIT compiler
    
    which has been developed by Takashi Kokubun <takashikkbn@gmail> as
    YARV-MJIT. Many of its bugs are fixed by wanabe <s.wanabe@g...>.
    
    This JIT compiler is designed to be a safe migration path to introduce
    JIT compiler to MRI. So this commit does not include any bytecode
    changes or dynamic instruction modifications, which are done in original
    MJIT.
    
    This commit even strips off some aggressive optimizations from
    YARV-MJIT, and thus it's slower than YARV-MJIT too. But it's still
    fairly faster than Ruby 2.5 in some benchmarks (attached below).
    
    Note that this JIT compiler passes `make test`, `make test-all`, `make
    test-spec` without JIT, and even with JIT. Not only it's perfectly safe
    with JIT disabled because it does not replace VM instructions unlike
    MJIT, but also with JIT enabled it stably runs Ruby applications
    including Rails applications.
    
    I'm expecting this version as just "initial" JIT compiler. I have many
    optimization ideas which are skipped for initial merging, and you may
    easily replace this JIT compiler with a faster one by just replacing
    mjit_compile.c. `mjit_compile` interface is designed for the purpose.
    
    common.mk: update dependencies for mjit_compile.c.
    
    internal.h: declare `rb_vm_insn_addr2insn` for MJIT.
    
    vm.c: exclude some definitions if `-DMJIT_HEADER` is provided to
    compiler. This avoids to include some functions which take a long time
    to compile, e.g. vm_exec_core. Some of the purpose is achieved in
    transform_mjit_header.rb (see `IGNORED_FUNCTIONS`) but others are
    manually resolved for now. Load mjit_helper.h for MJIT header.
    mjit_helper.h: New. This is a file used only by JIT-ed code. I'll
    refactor `mjit_call_cfunc` later.
    vm_eval.c: add some #ifdef switches to skip compiling some functions
    like Init_vm_eval.
    
    win32/mkexports.rb: export thread/ec functions, which are used by MJIT.
    
    include/ruby/defines.h: add MJIT_FUNC_EXPORTED macro alis to clarify
    that a function is exported only for MJIT.
    
    array.c: export a function used by MJIT.
    bignum.c: ditto.
    class.c: ditto.
    compile.c: ditto.
    error.c: ditto.
    gc.c: ditto.
    hash.c: ditto.
    iseq.c: ditto.
    numeric.c: ditto.
    object.c: ditto.
    proc.c: ditto.
    re.c: ditto.
    st.c: ditto.
    string.c: ditto.
    thread.c: ditto.
    variable.c: ditto.
    vm_backtrace.c: ditto.
    vm_insnhelper.c: ditto.
    vm_method.c: ditto.
    
    I would like to improve maintainability of function exports, but I
    believe this way is acceptable as initial merging if we clarify the
    new exports are for MJIT (so that we can use them as TODO list to fix)
    and add unit tests to detect unresolved symbols.
    I'll add unit tests of JIT compilations in succeeding commits.
    
    Author: Takashi Kokubun <takashikkbn@g...>
    Contributor: wanabe <s.wanabe@g...>
    
    Part of [Feature #14235]
    
    ---
    
    * Known issues
      * Code generated by gcc is faster than clang. The benchmark may be worse
        in macOS. Following benchmark result is provided by gcc w/ Linux.
      * Performance is decreased when Google Chrome is running
      * JIT can work on MinGW, but it doesn't improve performance at least
        in short running benchmark.
      * Currently it doesn't perform well with Rails. We'll try to fix this
        before release.
    
    ---
    
    * Benchmark reslts
    
    Benchmarked with:
    Intel 4.0GHz i7-4790K with 16GB memory under x86-64 Ubuntu 8 Cores
    
    - 2.0.0-p0: Ruby 2.0.0-p0
    - r62186: Ruby trunk (early 2.6.0), before MJIT changes
    - JIT off: On this commit, but without `--jit` option
    - JIT on: On this commit, and with `--jit` option
    
    ** Optcarrot fps
    
    Benchmark: https://github.com/mame/optcarrot
    
    |         |2.0.0-p0 |r62186   |JIT off  |JIT on   |
    |:--------|:--------|:--------|:--------|:--------|
    |fps      |37.32    |51.46    |51.31    |58.88    |
    |vs 2.0.0 |1.00x    |1.38x    |1.37x    |1.58x    |
    
    ** MJIT benchmarks
    
    Benchmark: https://github.com/benchmark-driver/mjit-benchmarks
    (Original: https://github.com/vnmakarov/ruby/tree/rtl_mjit_branch/MJIT-benchmarks)
    
    |           |2.0.0-p0 |r62186   |JIT off  |JIT on   |
    |:----------|:--------|:--------|:--------|:--------|
    |aread      |1.00     |1.09     |1.07     |2.19     |
    |aref       |1.00     |1.13     |1.11     |2.22     |
    |aset       |1.00     |1.50     |1.45     |2.64     |
    |awrite     |1.00     |1.17     |1.13     |2.20     |
    |call       |1.00     |1.29     |1.26     |2.02     |
    |const2     |1.00     |1.10     |1.10     |2.19     |
    |const      |1.00     |1.11     |1.10     |2.19     |
    |fannk      |1.00     |1.04     |1.02     |1.00     |
    |fib        |1.00     |1.32     |1.31     |1.84     |
    |ivread     |1.00     |1.13     |1.12     |2.43     |
    |ivwrite    |1.00     |1.23     |1.21     |2.40     |
    |mandelbrot |1.00     |1.13     |1.16     |1.28     |
    |meteor     |1.00     |2.97     |2.92     |3.17     |
    |nbody      |1.00     |1.17     |1.15     |1.49     |
    |nest-ntimes|1.00     |1.22     |1.20     |1.39     |
    |nest-while |1.00     |1.10     |1.10     |1.37     |
    |norm       |1.00     |1.18     |1.16     |1.24     |
    |nsvb       |1.00     |1.16     |1.16     |1.17     |
    |red-black  |1.00     |1.02     |0.99     |1.12     |
    |sieve      |1.00     |1.30     |1.28     |1.62     |
    |trees      |1.00     |1.14     |1.13     |1.19     |
    |while      |1.00     |1.12     |1.11     |2.41     |
    
    ** Discourse's script/bench.rb
    
    Benchmark: https://github.com/discourse/discourse/blob/v1.8.7/script/bench.rb
    
    NOTE: Rails performance was somehow a little degraded with JIT for now.
    We should fix this.
    (At least I know opt_aref is performing badly in JIT and I have an idea
     to fix it. Please wait for the fix.)
    
    *** JIT off
    Your Results: (note for timings- percentile is first, duration is second in millisecs)
    
    categories_admin:
      50: 17
      75: 18
      90: 22
      99: 29
    home_admin:
      50: 21
      75: 21
      90: 27
      99: 40
    topic_admin:
      50: 17
      75: 18
      90: 22
      99: 32
    categories:
      50: 35
      75: 41
      90: 43
      99: 77
    home:
      50: 39
      75: 46
      90: 49
      99: 95
    topic:
      50: 46
      75: 52
      90: 56
      99: 101
    
    *** JIT on
    Your Results: (note for timings- percentile is first, duration is second in millisecs)
    
    categories_admin:
      50: 19
      75: 21
      90: 25
      99: 33
    home_admin:
      50: 24
      75: 26
      90: 30
      99: 35
    topic_admin:
      50: 19
      75: 20
      90: 25
      99: 30
    categories:
      50: 40
      75: 44
      90: 48
      99: 76
    home:
      50: 42
      75: 48
      90: 51
      99: 89
    topic:
      50: 49
      75: 55
      90: 58
      99: 99

  Added files:
    trunk/tool/ruby_vm/views/_mjit_compile_insn.erb
    trunk/tool/ruby_vm/views/_mjit_compile_send.erb
    trunk/tool/ruby_vm/views/mjit_compile.inc.erb
  Modified files:
    trunk/Makefile.in
    trunk/array.c
    trunk/bignum.c
    trunk/class.c
    trunk/common.mk
    trunk/compile.c
    trunk/error.c
    trunk/gc.c
    trunk/hash.c
    trunk/include/ruby/defines.h
    trunk/insns.def
    trunk/internal.h
    trunk/iseq.c
    trunk/mjit.c
    trunk/mjit.h
    trunk/mjit_compile.c
    trunk/numeric.c
    trunk/object.c
    trunk/proc.c
    trunk/re.c
    trunk/st.c
    trunk/string.c
    trunk/test/-ext-/thread_fd_close/test_thread_fd_close.rb
    trunk/test/lib/minitest/unit.rb
    trunk/test/ruby/test_io.rb
    trunk/test/ruby/test_settracefunc.rb
    trunk/test/ruby/test_thread.rb
    trunk/test/rubygems/test_gem_util.rb
    trunk/test/thread/test_cv.rb
    trunk/test/thread/test_sync.rb
    trunk/test/webrick/test_httpserver.rb
    trunk/test/webrick/test_server.rb
    trunk/thread.c
    trunk/tool/transform_mjit_header.rb
    trunk/tool/update-deps
    trunk/variable.c
    trunk/vm.c
    trunk/vm_backtrace.c
    trunk/vm_core.h
    trunk/vm_eval.c
    trunk/vm_exec.h
    trunk/vm_insnhelper.c
    trunk/vm_insnhelper.h
    trunk/vm_method.c
    trunk/vm_trace.c
    trunk/win32/Makefile.sub
    trunk/win32/mkexports.rb
Index: compile.c
===================================================================
--- compile.c	(revision 62196)
+++ compile.c	(revision 62197)
@@ -754,7 +754,7 @@ rb_iseq_translate_threaded_code(rb_iseq_ https://github.com/ruby/ruby/blob/trunk/compile.c#L754
 }
 
 #if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
-static int
+int
 rb_vm_insn_addr2insn(const void *addr) /* cold path */
 {
     int insn;
Index: vm_trace.c
===================================================================
--- vm_trace.c	(revision 62196)
+++ vm_trace.c	(revision 62197)
@@ -325,7 +325,7 @@ exec_hooks_protected(rb_execution_contex https://github.com/ruby/ruby/blob/trunk/vm_trace.c#L325
     return state;
 }
 
-void
+MJIT_FUNC_EXPORTED void
 rb_exec_event_hooks(rb_trace_arg_t *trace_arg, int pop_p)
 {
     rb_execution_context_t *ec = trace_arg->ec;
Index: common.mk
===================================================================
--- common.mk	(revision 62196)
+++ common.mk	(revision 62197)
@@ -890,6 +890,7 @@ $(srcs_vpath)insns.inc: $(srcdir)/tool/r https://github.com/ruby/ruby/blob/trunk/common.mk#L890
 $(srcs_vpath)insns_info.inc: $(srcdir)/tool/ruby_vm/views/insns_info.inc.erb
 $(srcs_vpath)vmtc.inc: $(srcdir)/tool/ruby_vm/views/vmtc.inc.erb
 $(srcs_vpath)vm.inc: $(srcdir)/tool/ruby_vm/views/vm.inc.erb
+$(srcs_vpath)mjit_compile.inc: $(srcdir)/tool/ruby_vm/views/mjit_compile.inc.erb $(srcdir)/tool/ruby_vm/views/_mjit_compile_insn.erb $(srcdir)/tool/ruby_vm/views/_mjit_compile_send.erb
 
 common-srcs: $(srcs_vpath)parse.c $(srcs_vpath)lex.c $(srcs_vpath)enc/trans/newline.c $(srcs_vpath)id.c \
 	     srcs-lib srcs-ext incs
@@ -2003,8 +2004,12 @@ mjit.$(OBJEXT): {$(VPATH)}mjit.h https://github.com/ruby/ruby/blob/trunk/common.mk#L2004
 mjit.$(OBJEXT): {$(VPATH)}ruby_assert.h
 mjit.$(OBJEXT): {$(VPATH)}version.h
 mjit.$(OBJEXT): {$(VPATH)}vm_core.h
+mjit_compile.$(OBJEXT): {$(VPATH)}insns.inc
+mjit_compile.$(OBJEXT): {$(VPATH)}insns_info.inc
 mjit_compile.$(OBJEXT): {$(VPATH)}internal.h
+mjit_compile.$(OBJEXT): {$(VPATH)}mjit.h
 mjit_compile.$(OBJEXT): {$(VPATH)}mjit_compile.c
+mjit_compile.$(OBJEXT): {$(VPATH)}mjit_compile.inc
 mjit_compile.$(OBJEXT): {$(VPATH)}vm_core.h
 load.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
 load.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
Index: win32/Makefile.sub
===================================================================
--- win32/Makefile.sub	(revision 62196)
+++ win32/Makefile.sub	(revision 62197)
@@ -1192,7 +1192,7 @@ rb_mjit_header.h: PHONY probes.h https://github.com/ruby/ruby/blob/trunk/win32/Makefile.sub#L1192
 	$(Q) $(IFCHANGE) $@ vm.i
 
 INSNS	= opt_sc.inc optinsn.inc optunifs.inc insns.inc insns_info.inc \
-	  vmtc.inc vm.inc
+	  vmtc.inc vm.inc mjit_compile.inc
 
 !if [exit > insns_rules.mk]
 !else if [for %I in ($(INSNS)) do \
Index: object.c
===================================================================
--- object.c	(revision 62196)
+++ object.c	(revision 62197)
@@ -198,7 +198,7 @@ rb_eql(VALUE obj1, VALUE obj2) https://github.com/ruby/ruby/blob/trunk/object.c#L198
  * \private
  *++
  */
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_obj_equal(VALUE obj1, VALUE obj2)
 {
     if (obj1 == obj2) return Qtrue;
@@ -217,7 +217,7 @@ VALUE rb_obj_hash(VALUE obj); https://github.com/ruby/ruby/blob/trunk/object.c#L217
  *++
  */
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_obj_not(VALUE obj)
 {
     return RTEST(obj) ? Qfalse : Qtrue;
@@ -233,7 +233,7 @@ rb_obj_not(VALUE obj) https://github.com/ruby/ruby/blob/trunk/object.c#L233
  *++
  */
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_obj_not_equal(VALUE obj1, VALUE obj2)
 {
     VALUE result = rb_funcall(obj1, id_eq, 1, obj2);
@@ -304,7 +304,7 @@ rb_obj_singleton_class(VALUE obj) https://github.com/ruby/ruby/blob/trunk/object.c#L304
 }
 
 /*! \private */
-void
+MJIT_FUNC_EXPORTED void
 rb_obj_copy_ivar(VALUE dest, VALUE obj)
 {
     if (!(RBASIC(dest)->flags & ROBJECT_EMBED) && ROBJECT_IVPTR(dest)) {
@@ -3019,7 +3019,7 @@ rb_check_convert_type(VALUE val, int typ https://github.com/ruby/ruby/blob/trunk/object.c#L3019
 }
 
 /*! \private */
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_check_convert_type_with_id(VALUE val, int type, const char *tname, ID method)
 {
     VALUE v;
Index: array.c
===================================================================
--- array.c	(revision 62196)
+++ array.c	(revision 62197)
@@ -506,7 +506,7 @@ VALUE https://github.com/ruby/ruby/blob/trunk/array.c#L506
     return ary;
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_ary_tmp_new_from_values(VALUE klass, long n, const VALUE *elts)
 {
     VALUE ary;
@@ -640,7 +640,7 @@ rb_check_array_type(VALUE ary) https://github.com/ruby/ruby/blob/trunk/array.c#L640
     return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary);
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_check_to_array(VALUE ary)
 {
     return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_a);
@@ -1297,7 +1297,7 @@ rb_ary_aref2(VALUE ary, VALUE b, VALUE e https://github.com/ruby/ruby/blob/trunk/array.c#L1297
     return rb_ary_subseq(ary, beg, len);
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_ary_aref1(VALUE ary, VALUE arg)
 {
     long beg, len;
Index: numeric.c
===================================================================
--- numeric.c	(revision 62196)
+++ numeric.c	(revision 62197)
@@ -1157,7 +1157,7 @@ flodivmod(double x, double y, double *di https://github.com/ruby/ruby/blob/trunk/numeric.c#L1157
  * An error will be raised if y == 0.
  */
 
-double
+MJIT_FUNC_EXPORTED double
 ruby_float_mod(double x, double y)
 {
     double mod;
@@ -1333,7 +1333,7 @@ num_equal(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1333
  *  so an implementation-dependent value is returned.
  */
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_float_equal(VALUE x, VALUE y)
 {
     volatile double a, b;
@@ -1436,7 +1436,7 @@ flo_cmp(VALUE x, VALUE y) https://github.com/ruby/ruby/blob/trunk/numeric.c#L1436
     return rb_dbl_cmp(a, b);
 }
 
-int
+MJIT_FUNC_EXPORTED int
 rb_float_cmp(VALUE x, VALUE y)
 {
     return NUM2INT(flo_cmp(x, y));
Index: gc.c
===================================================================
--- gc.c	(revision 62196)
+++ gc.c	(revision 62197)
@@ -2216,6 +2216,7 @@ obj_free(rb_objspace_t *objspace, VALUE https://github.com/ruby/ruby/blob/trunk/gc.c#L2216
 	break;
       case T_MODULE:
       case T_CLASS:
+        mjit_remove_class_serial(RCLASS_SERIAL(obj));
 	rb_id_table_free(RCLASS_M_TBL(obj));
 	if (RCLASS_IV_TBL(obj)) {
 	    st_free_table(RCLASS_IV_TBL(obj));
@@ -4054,7 +4055,7 @@ stack_check(rb_execution_context_t *ec, https://github.com/ruby/ruby/blob/trunk/gc.c#L4055
 
 #define STACKFRAME_FOR_CALL_CFUNC 838
 
-int
+MJIT_FUNC_EXPORTED int
 rb_ec_stack_check(rb_execution_context_t *ec)
 {
     return stack_check(ec, STACKFRAME_FOR_CALL_CFUNC);
@@ -6053,7 +6054,7 @@ rb_gc_writebarrier_unprotect(VALUE obj) https://github.com/ruby/ruby/blob/trunk/gc.c#L6054
 /*
  * remember `obj' if needed.
  */
-void
+MJIT_FUNC_EXPORTED void
 rb_gc_writebarrier_remember(VALUE obj)
 {
     rb_objspace_t *objspace = &rb_objspace;
Index: variable.c
===================================================================
--- variable.c	(revision 62196)
+++ variable.c	(revision 62197)
@@ -480,7 +480,7 @@ struct rb_global_variable { https://github.com/ruby/ruby/blob/trunk/variable.c#L480
     struct trace_var *trace;
 };
 
-struct rb_global_entry*
+MJIT_FUNC_EXPORTED struct rb_global_entry*
 rb_global_entry(ID id)
 {
     struct rb_global_entry *entry;
@@ -790,7 +790,7 @@ rb_f_untrace_var(int argc, const VALUE * https://github.com/ruby/ruby/blob/trunk/variable.c#L790
     return Qnil;
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_gvar_get(struct rb_global_entry *entry)
 {
     struct rb_global_variable *var = entry->var;
@@ -823,7 +823,7 @@ trace_en(struct rb_global_variable *var) https://github.com/ruby/ruby/blob/trunk/variable.c#L823
     return Qnil;		/* not reached */
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_gvar_set(struct rb_global_entry *entry, VALUE val)
 {
     struct trace_data trace;
@@ -858,7 +858,7 @@ rb_gv_get(const char *name) https://github.com/ruby/ruby/blob/trunk/variable.c#L858
     return rb_gvar_get(entry);
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_gvar_defined(struct rb_global_entry *entry)
 {
     if (entry->var->getter == rb_gvar_undef_getter) return Qfalse;
@@ -2010,7 +2010,7 @@ check_autoload_required(VALUE mod, ID id https://github.com/ruby/ruby/blob/trunk/variable.c#L2010
     return 0;
 }
 
-int
+MJIT_FUNC_EXPORTED int
 rb_autoloading_value(VALUE mod, ID id, VALUE* value)
 {
     VALUE load;
@@ -2211,7 +2211,7 @@ rb_autoload_p(VALUE mod, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2211
     return (ele = check_autoload_data(load)) ? ele->feature : Qnil;
 }
 
-void
+MJIT_FUNC_EXPORTED void
 rb_const_warn_if_deprecated(const rb_const_entry_t *ce, VALUE klass, ID id)
 {
     if (RB_CONST_DEPRECATED_P(ce)) {
@@ -2294,7 +2294,7 @@ rb_const_get_at(VALUE klass, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2294
     return rb_const_get_0(klass, id, TRUE, FALSE, FALSE);
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_public_const_get_from(VALUE klass, ID id)
 {
     return rb_const_get_0(klass, id, TRUE, TRUE, TRUE);
@@ -2306,7 +2306,7 @@ rb_public_const_get(VALUE klass, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2306
     return rb_const_get_0(klass, id, FALSE, TRUE, TRUE);
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_public_const_get_at(VALUE klass, ID id)
 {
     return rb_const_get_0(klass, id, TRUE, FALSE, TRUE);
@@ -2544,7 +2544,7 @@ rb_const_defined_at(VALUE klass, ID id) https://github.com/ruby/ruby/blob/trunk/variable.c#L2544
     return rb_const_defined_0(klass, id, TRUE, FALSE, FALSE);
 }
 
-int
+MJIT_FUNC_EXPORTED int
 rb_public_const_defined_from(VALUE klass, ID id)
 {
     return rb_const_defined_0(klass, id, TRUE, TRUE, TRUE);
@@ -3123,7 +3123,7 @@ rb_st_copy(VALUE obj, struct st_table *o https://github.com/ruby/ruby/blob/trunk/variable.c#L3123
     return new_tbl;
 }
 
-rb_const_entry_t *
+MJIT_FUNC_EXPORTED rb_const_entry_t *
 rb_const_lookup(VALUE klass, ID id)
 {
     struct rb_id_table *tbl = RCLASS_CONST_TBL(klass);
Index: string.c
===================================================================
--- string.c	(revision 62196)
+++ string.c	(revision 62197)
@@ -373,7 +373,7 @@ rb_setup_fake_str(struct RString *fake_s https://github.com/ruby/ruby/blob/trunk/string.c#L373
     return setup_fake_str(fake_str, name, len, rb_enc_to_index(enc));
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_fstring_new(const char *ptr, long len)
 {
     struct RString fake_str;
@@ -1445,7 +1445,7 @@ rb_obj_as_string(VALUE obj) https://github.com/ruby/ruby/blob/trunk/string.c#L1445
     return rb_obj_as_string_result(str, obj);
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_obj_as_string_result(VALUE str, VALUE obj)
 {
     if (!RB_TYPE_P(str, T_STRING))
@@ -2933,7 +2933,7 @@ rb_str_append(VALUE str, VALUE str2) https://github.com/ruby/ruby/blob/trunk/string.c#L2933
 
 #define MIN_PRE_ALLOC_SIZE 48
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_str_concat_literals(size_t num, const VALUE *strary)
 {
     VALUE str;
@@ -10391,7 +10391,7 @@ rb_str_quote_unprintable(VALUE str) https://github.com/ruby/ruby/blob/trunk/string.c#L10391
     return str;
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_id_quote_unprintable(ID id)
 {
     return rb_str_quote_unprintable(rb_id2str(id));
@@ -10468,7 +10468,7 @@ sym_to_sym(VALUE sym) https://github.com/ruby/ruby/blob/trunk/string.c#L10468
     return sym;
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_sym_proc_call(ID mid, int argc, const VALUE *argv, VALUE passed_proc)
 {
     VALUE obj;
Index: st.c
===================================================================
--- st.c	(revision 62196)
+++ st.c	(revision 62197)
@@ -2171,7 +2171,7 @@ st_insert_generic(st_table *tab, long ar https://github.com/ruby/ruby/blob/trunk/st.c#L2171
 
 /* Mimics ruby's { foo => bar } syntax. This function is placed here
    because it touches table internals and write barriers at once. */
-void
+MJIT_FUNC_EXPORTED void
 rb_hash_bulk_insert(long argc, const VALUE *argv, VALUE hash)
 {
     st_index_t n;
Index: include/ruby/defines.h
===================================================================
--- include/ruby/defines.h	(revision 62196)
+++ include/ruby/defines.h	(revision 62197)
@@ -270,6 +270,10 @@ void xfree(void*); https://github.com/ruby/ruby/blob/trunk/include/ruby/defines.h#L270
 #define RUBY_FUNC_EXPORTED
 #endif
 
+/* MJIT_FUNC_EXPORTED is used for functions which are exported only for MJIT
+   and NOT ensured to be exported in future versions. */
+#define MJIT_FUNC_EXPORTED RUBY_FUNC_EXPORTED
+
 #ifndef RUBY_EXTERN
 #define RUBY_EXTERN extern
 #endif
Index: vm_method.c
===================================================================
--- vm_method.c	(revision 62196)
+++ vm_method.c	(revision 62197)
@@ -62,6 +62,7 @@ static struct { https://github.com/ruby/ruby/blob/trunk/vm_method.c#L62
 static void
 rb_class_clear_method_cache(VALUE klass, VALUE arg)
 {
+    mjit_remove_class_serial(RCLASS_SERIAL(klass));
     RCLASS_SERIAL(klass) = rb_next_class_serial();
 
     if (RB_TYPE_P(klass, T_ICLASS)) {
@@ -171,7 +172,7 @@ rb_free_method_entry(const rb_method_ent https://github.com/ruby/ruby/blob/trunk/vm_method.c#L172
 }
 
 static inline rb_method_entry_t *search_method(VALUE klass, ID id, VALUE *defined_class_ptr);
-static int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
+extern int rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2);
 
 static inline rb_method_entry_t *
 lookup_method_table(VALUE klass, ID id)
@@ -222,7 +223,7 @@ setup_method_cfunc_struct(rb_method_cfun https://github.com/ruby/ruby/blob/trunk/vm_method.c#L223
     cfunc->invoker = call_cfunc_invoker_func(argc);
 }
 
-static void
+MJIT_FUNC_EXPORTED void
 method_definition_set(const rb_method_entry_t *me, rb_method_definition_t *def, void *opts)
 {
     *(rb_method_definition_t **)&me->def = def;
@@ -336,7 +337,7 @@ method_definition_reset(const rb_method_ https://github.com/ruby/ruby/blob/trunk/vm_method.c#L337
     }
 }
 
-static rb_method_definition_t *
+MJIT_FUNC_EXPORTED rb_method_definition_t *
 method_definition_create(rb_method_type_t type, ID mid)
 {
     rb_method_definition_t *def;
@@ -401,7 +402,7 @@ rb_method_entry_clone(const rb_method_en https://github.com/ruby/ruby/blob/trunk/vm_method.c#L402
     return me;
 }
 
-const rb_callable_method_entry_t *
+MJIT_FUNC_EXPORTED const rb_callable_method_entry_t *
 rb_method_entry_complement_defined_class(const rb_method_entry_t *src_me, ID called_id, VALUE defined_class)
 {
     rb_method_definition_t *def = src_me->def;
@@ -812,7 +813,7 @@ method_entry_get(VALUE klass, ID id, VAL https://github.com/ruby/ruby/blob/trunk/vm_method.c#L813
     return method_entry_get_without_cache(klass, id, defined_class_ptr);
 }
 
-const rb_method_entry_t *
+MJIT_FUNC_EXPORTED const rb_method_entry_t *
 rb_method_entry(VALUE klass, ID id)
 {
     return method_entry_get(klass, id, NULL);
@@ -853,7 +854,7 @@ prepare_callable_method_entry(VALUE defi https://github.com/ruby/ruby/blob/trunk/vm_method.c#L854
     return cme;
 }
 
-const rb_callable_method_entry_t *
+MJIT_FUNC_EXPORTED const rb_callable_method_entry_t *
 rb_callable_method_entry(VALUE klass, ID id)
 {
     VALUE defined_class;
@@ -886,7 +887,7 @@ method_entry_resolve_refinement(VALUE kl https://github.com/ruby/ruby/blob/trunk/vm_method.c#L887
     return me;
 }
 
-const rb_callable_method_entry_t *
+MJIT_FUNC_EXPORTED const rb_callable_method_entry_t *
 rb_callable_method_entry_with_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
 {
     VALUE defined_class, *dcp = defined_class_ptr ? defined_class_ptr : &defined_class;
@@ -900,7 +901,7 @@ rb_method_entry_without_refinements(VALU https://github.com/ruby/ruby/blob/trunk/vm_method.c#L901
     return method_entry_resolve_refinement(klass, id, FALSE, defined_class_ptr);
 }
 
-const rb_callable_method_entry_t *
+MJIT_FUNC_EXPORTED const rb_callable_method_entry_t *
 rb_callable_method_entry_without_refinements(VALUE klass, ID id, VALUE *defined_class_ptr)
 {
     VALUE defined_class, *dcp = defined_class_ptr ? defined_class_ptr : &defined_class;
@@ -1462,7 +1463,7 @@ original_method_definition(const rb_meth https://github.com/ruby/ruby/blob/trunk/vm_method.c#L1463
     return def;
 }
 
-static int
+MJIT_FUNC_EXPORTED int
 rb_method_definition_eq(const rb_method_definition_t *d1, const rb_method_definition_t *d2)
 {
     d1 = original_method_definition(d1);
Index: error.c
===================================================================
--- error.c	(revision 62196)
+++ error.c	(revision 62197)
@@ -1161,7 +1161,7 @@ exc_set_backtrace(VALUE exc, VALUE bt) https://github.com/ruby/ruby/blob/trunk/error.c#L1161
     return rb_ivar_set(exc, id_bt, rb_check_backtrace(bt));
 }
 
-VALUE
+MJIT_FUNC_EXPORTED VALUE
 rb_exc_set_backtrace(VALUE exc, VALUE bt)
 {
     return exc_set_backtrace(exc, bt);
Index: tool/transform_mjit_header.rb
===================================================================
--- tool/transform_mjit_header.rb	(revision 62196)
+++ tool/transform_mjit_header.rb	(revision 62197)
@@ -17,6 +17,7 @@ module MJITHeader https://github.com/ruby/ruby/blob/trunk/tool/transform_mjit_header.rb#L17
   ]
 
   IGNORED_FUNCTIONS = [
+    'vm_search_method_slowpath', # This increases the time to compile when inlined. So we use it as external function.
     'rb_equal_opt', # Not used from VM and not compilable
   ]
 
Index: tool/update-deps
===================================================================
--- tool/update-deps	(revision 62196)
+++ tool/update-deps	(revision 62197)
@@ -120,6 +120,7 @@ FILES_NEED_VPATH = %w[ https://github.com/ruby/ruby/blob/trunk/tool/update-deps#L120
   known_errors.inc
   lex.c
   miniprelude.c
+  mjit_compile.inc
   newline.c
   node_name.inc
   opt_sc.inc
Index: tool/ruby_vm/views/_mjit_compile_send.erb
===================================================================
--- tool/ruby_vm/views/_mjit_compile_send.erb	(nonexistent)
+++ tool/ruby_vm/views/_mjit_compile_send.erb	(revision 62197)
@@ -0,0 +1,74 @@ https://github.com/ruby/ruby/blob/trunk/tool/ruby_vm/views/_mjit_compile_send.erb#L1
+% # -*- mode:c; style:ruby; coding: utf-8; indent-tabs-mode: nil -*-
+% # Copyright (c) 2018 Takashi Kokubun.  All rights reserved.
+% #
+% # This file is a part of  the programming language Ruby.  Permission is hereby
+% # granted, to either  redistribute and/or modify this file,  provided that the
+% # conditions mentioned  in the  file COPYING  are met.   Consult the  file for
+% # details.
+%
+% # Optimized case of send / opt_send_without_block instructions.
+    {
+% # compiler: Prepare operands which may be used by `insn.call_attribute`
+% insn.opes.each_with_index do |ope, i|
+        MAYBE_UNUSED(<%= ope.fetch(:decl) %>) = (<%= ope.fetch(:type) %>)operands[<%= i %>];
+% end
+%
+        const rb_iseq_t *iseq;
+        unsigned int argc = ci->orig_argc; /* unlike `ci->orig_argc`, `argc` may include blockarg */
+% if insn.name == 'send'
+        argc += ((ci->flag & VM_CALL_ARGS_BLOCKARG) ? 1 : 0);
+% end
+
+        if (inlinable_iseq_p(ci, cc, iseq = get_iseq_if_available(cc))) {
+            int param_size = iseq->body->param.size; /* TODO: check calling->argc for argument_arity_error */
+
+% # JIT: move sp and pc if necessary
+            fprintf(f, "    reg_cfp->pc = (VALUE *)0x%"PRIxVALUE";\n", (VALUE)(body->iseq_encoded + next_pos)); /* ADD_PC(INSN_ATTR(width)); */
+            fprintf(f, "    reg_cfp->sp = reg_cfp->bp + %d;\n", b->stack_size + 1 - <%= insn.pops.size %>); /* POPN(INSN_ATTR(popn)); */
+
+% # JIT: Invalidate call cache if it requires vm_search_method. This allows to inline some of following things.
+            fprintf(f, "    if (UNLIKELY(GET_GLOBAL_METHOD_STATE() != %llu || RCLASS_SERIA (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]