Project

General

Profile

Feature #14489 ยป 14489.patch

wanabe (_ wanabe), 03/07/2018 01:02 PM

View differences:

Makefile.in
527 527
update-coverage: update-simplecov update-simplecov-html update-doclie
528 528

  
529 529
INSNS	= opt_sc.inc optinsn.inc optunifs.inc insns.inc insns_info.inc \
530
	  vmtc.inc vm.inc mjit_compile.inc
530
	  vmtc.inc vm.inc mjit_compile.inc mjit_var.inc
531 531

  
532 532
$(INSNS): $(srcdir)/insns.def vm_opts.h \
533 533
	  $(srcdir)/defs/opt_operand.def $(srcdir)/defs/opt_insn_unif.def \
common.mk
925 925
$(srcs_vpath)mjit_compile.inc: $(srcdir)/tool/ruby_vm/views/mjit_compile.inc.erb \
926 926
  $(srcdir)/tool/ruby_vm/views/_mjit_compile_insn.erb $(srcdir)/tool/ruby_vm/views/_mjit_compile_send.erb \
927 927
  $(srcdir)/tool/ruby_vm/views/_mjit_compile_insn_body.erb $(srcdir)/tool/ruby_vm/views/_mjit_compile_pc_and_sp.erb
928
$(srcs_vpath)mjit_var.inc: $(srcdir)/tool/ruby_vm/views/mjit_var.inc.erb
928 929

  
929 930
common-srcs: $(srcs_vpath)parse.c $(srcs_vpath)lex.c $(srcs_vpath)enc/trans/newline.c $(srcs_vpath)id.c \
930 931
	     srcs-lib srcs-ext incs
......
2046 2047
mjit_compile.$(OBJEXT): {$(VPATH)}mjit.h
2047 2048
mjit_compile.$(OBJEXT): {$(VPATH)}mjit_compile.c
2048 2049
mjit_compile.$(OBJEXT): {$(VPATH)}mjit_compile.inc
2050
mjit_compile.$(OBJEXT): {$(VPATH)}mjit_var.inc
2049 2051
mjit_compile.$(OBJEXT): {$(VPATH)}vm_core.h
2050 2052
load.$(OBJEXT): $(CCAN_DIR)/check_type/check_type.h
2051 2053
load.$(OBJEXT): $(CCAN_DIR)/container_of/container_of.h
miniinit.c
13 13
#include "ruby/encoding.h"
14 14

  
15 15
/* loadpath.c */
16
const char ruby_exec_prefix[] = "";
16
const char ruby_exec_prefix[] = "./";
17 17
const char ruby_initial_load_paths[] = "";
18 18

  
19 19
/* localeinit.c */
mjit.c
95 95
#ifdef HAVE_FCNTL_H
96 96
#include <fcntl.h>
97 97
#endif
98
#include <libgen.h>
98 99

  
99 100
extern void rb_native_mutex_lock(rb_nativethread_lock_t *lock);
100 101
extern void rb_native_mutex_unlock(rb_nativethread_lock_t *lock);
......
191 192
static int in_gc;
192 193
/* True when JIT is working.  */
193 194
static int in_jit;
195
/* Object cache directory */
196
static VALUE o_cache_dir = Qfalse;
194 197

  
195 198
/* Defined in the client thread before starting MJIT threads:  */
196 199
/* Used C compiler path.  */
......
705 708
    return exit_code == 0;
706 709
}
707 710

  
711
/* Compile C file to o. It returns 1 if it succeeds. */
712
static int
713
compile_c_to_o(const char *c_file, const char *o_file)
714
{
715
    int exit_code;
716
    const char *files[] = {
717
#ifdef __clang__
718
        "-include-pch", NULL,
719
#endif
720
        "-c",
721
#ifndef _MSC_VER
722
        "-o",
723
#endif
724
        NULL, NULL, NULL};
725
    const char *libs[] = {
726
#ifdef _WIN32
727
# ifdef _MSC_VER
728
        MJIT_LIBS
729
        "-link",
730
        libruby_installed,
731
        libruby_build,
732
# else
733
        /* Look for ruby.dll.a in build and install directories. */
734
        libruby_installed,
735
        libruby_build,
736
        MJIT_LIBS
737
        "-lmsvcrt",
738
        "-lgcc",
739
# endif
740
#endif
741
        NULL};
742
    char **args;
743
#ifdef _MSC_VER
744
    char *p;
745
    int olen;
746
#endif
747

  
748
    files[numberof(files)-2] = c_file;
749
#ifdef _MSC_VER
750
    olen = strlen(o_file);
751
    files[0] = p = xmalloc(rb_strlen_lit("-Fe") + olen + 1);
752
    p = append_lit(p, "-Fe");
753
    p = append_str2(p, o_file, olen);
754
    *p = '\0';
755
#else
756
# ifdef __clang__
757
    files[1] = pch_file;
758
# endif
759
    files[numberof(files)-3] = o_file;
760
#endif
761
    args = form_args(5, CC_LDSHARED_ARGS, CC_CODEFLAG_ARGS,
762
                     files, libs, CC_DLDFLAGS_ARGS);
763
    if (args == NULL)
764
        return FALSE;
765

  
766
    exit_code = exec_process(cc_path, args);
767
    xfree(args);
768
#ifdef _MSC_VER
769
    xfree((char *)files[0]);
770
#endif
771

  
772
    if (exit_code != 0)
773
        verbose(2, "compile_c_to_o: compile error: %d", exit_code);
774
    return exit_code == 0;
775
}
776

  
777
/* Compile var C file and o to so. It returns 1 if it succeeds. */
778
static int
779
compile_var_and_o_to_so(const char *var_file, const char *o_file, const char *so_file)
780
{
781
    int exit_code;
782
    const char *files[] = {
783
#ifdef __clang__
784
        "-include-pch", NULL,
785
#endif
786
#ifndef _MSC_VER
787
        "-o",
788
#endif
789
        NULL, NULL, NULL, NULL};
790
    const char *libs[] = {
791
#ifdef _WIN32
792
# ifdef _MSC_VER
793
        MJIT_LIBS
794
        "-link",
795
        libruby_installed,
796
        libruby_build,
797
# else
798
        /* Look for ruby.dll.a in build and install directories. */
799
        libruby_installed,
800
        libruby_build,
801
        MJIT_LIBS
802
        "-lmsvcrt",
803
        "-lgcc",
804
# endif
805
#endif
806
        NULL};
807
    char **args;
808
#ifdef _MSC_VER
809
    char *p;
810
    int solen;
811
#endif
812

  
813
    files[numberof(files)-3] = var_file;
814
    files[numberof(files)-2] = o_file;
815
#ifdef _MSC_VER
816
    solen = strlen(so_file);
817
    files[0] = p = xmalloc(rb_strlen_lit("-Fe") + solen + 1);
818
    p = append_lit(p, "-Fe");
819
    p = append_str2(p, so_file, solen);
820
    *p = '\0';
821
#else
822
# ifdef __clang__
823
    files[1] = pch_file;
824
# endif
825
    files[numberof(files)-4] = so_file;
826
#endif
827
    args = form_args(5, CC_LDSHARED_ARGS, CC_CODEFLAG_ARGS,
828
                     files, libs, CC_DLDFLAGS_ARGS);
829
    if (args == NULL)
830
        return FALSE;
831

  
832
    exit_code = exec_process(cc_path, args);
833
    xfree(args);
834
#ifdef _MSC_VER
835
    xfree((char *)files[0]);
836
#endif
837

  
838
    if (exit_code != 0)
839
        verbose(2, "compile_c_to_so: compile error: %d", exit_code);
840
    return exit_code == 0;
841
}
842

  
708 843
static void *
709 844
load_func_from_so(const char *so_file, const char *funcname, struct rb_mjit_unit *unit)
710 845
{
......
749 884
            RSTRING_PTR(rb_iseq_path(unit->iseq)), FIX2INT(unit->iseq->body->location.first_lineno), c_file);
750 885
}
751 886

  
887
static int
888
mkparentdir(char *path)
889
{
890
    struct stat sb;
891
    char *parent = dirname(strdupa(path));
892
    if (!strcmp(parent, path)) {
893
        return 1;
894
    }
895
    stat(parent, &sb);
896
    if (S_ISDIR(sb.st_mode)) {
897
        return 0;
898
    } else {
899
        if (mkparentdir(parent)) {
900
            return 1;
901
        }
902
        return mkdir(parent, 0
903
          | S_IRUSR | S_IWUSR | S_IXUSR
904
          | S_IRGRP | S_IWGRP | S_IXGRP
905
          | S_IROTH | S_IXOTH | S_IXOTH
906
        );
907
    }
908
}
909

  
752 910
/* Compile ISeq in UNIT and return function pointer of JIT-ed code.
753 911
   It may return NOT_COMPILABLE_JIT_ISEQ_FUNC if something went wrong. */
754 912
static mjit_func_t
755 913
convert_unit_to_func(struct rb_mjit_unit *unit)
756 914
{
757
    char c_file_buff[70], *c_file = c_file_buff, *so_file, funcname[35];
915
    char c_file_buff[70], *c_file = c_file_buff, *so_file, funcname[35], *var_file;
758 916
    int success;
759 917
    int fd;
918
    char create_o_cache = 0;
760 919
    FILE *f;
761 920
    void *func;
762 921
    double start_time, end_time;
763 922
    int c_file_len = (int)sizeof(c_file_buff);
764 923
    static const char c_ext[] = ".c";
765 924
    static const char so_ext[] = DLEXT;
925
    char *o_file = NULL;
766 926
    const int access_mode =
767 927
#ifdef O_BINARY
768 928
        O_BINARY|
769 929
#endif
770 930
        O_WRONLY|O_EXCL|O_CREAT;
771 931

  
932
    if (mjit_opts.cache_objs) {
933
        struct stat o_st, r_st;
934
        char *rb_file = RSTRING_PTR(rb_iseq_realpath(unit->iseq));
935
        if (stat(rb_file, &r_st)) {
936
            o_file = NULL;
937
            verbose(2, "Can't get stat of '%s'", rb_file);
938
        } else {
939
            o_file = malloc(RSTRING_LEN(o_cache_dir) + strlen(rb_file) + 15);
940
            sprintf(o_file, "%s%s.%d.o", RSTRING_PTR(o_cache_dir), rb_file, FIX2INT(unit->iseq->body->location.first_lineno));
941
            verbose(2, "Check Cache '%s'", o_file);
942
            if (mkparentdir(o_file)) {
943
                verbose(2, "Can't create directory of '%s'", o_file);
944
                o_file = NULL;
945
            } else if (stat(o_file, &o_st)) {
946
                if (errno == ENOENT) {
947
                    create_o_cache = 1;
948
                    verbose(2, "Create '%s'", o_file);
949
                } else {
950
                    o_file = NULL;
951
                    verbose(2, "Can't get stat of '%s'", o_file);
952
                }
953
            } else if(o_st.st_mtime > r_st.st_mtime) {
954
                verbose(2, "Use cache '%s'", o_file);
955
            } else {
956
                create_o_cache = 1;
957
                verbose(2, "Update '%s'", o_file);
958
            }
959
        }
960
    }
772 961
    c_file_len = sprint_uniq_filename(c_file_buff, c_file_len, unit->id, MJIT_TMP_PREFIX, c_ext);
773 962
    if (c_file_len >= (int)sizeof(c_file_buff)) {
774 963
        ++c_file_len;
......
781 970
    memcpy(&so_file[c_file_len - sizeof(c_ext)], so_ext, sizeof(so_ext));
782 971
    sprintf(funcname, "_mjit%d", unit->id);
783 972

  
973
    if (o_file) {
974
        static const char var_suffix[] = "_var";
975
        var_file = alloca(c_file_len + sizeof(var_suffix));
976
        memcpy(var_file, c_file, c_file_len - sizeof(c_ext));
977
        memcpy(&var_file[c_file_len - sizeof(c_ext)], var_suffix, sizeof(var_suffix));
978
        memcpy(&var_file[c_file_len - sizeof(c_ext) + sizeof(var_suffix) - 1], c_ext, sizeof(c_ext));
979
        verbose(2, "Create '%s'", var_file);
980

  
981
        fd = rb_cloexec_open(var_file, access_mode, 0600);
982
        if (fd < 0 || (f = fdopen(fd, "w")) == NULL) {
983
            int e = errno;
984
            if (fd >= 0) (void)close(fd);
985
            verbose(1, "Failed to fopen '%s', giving up JIT for it (%s)", var_file, strerror(e));
986
            return (mjit_func_t)NOT_COMPILABLE_JIT_ISEQ_FUNC;
987
        }
988
#ifdef __clang__
989
    /* -include-pch is used for Clang */
990
#else
991
    {
992
# ifdef __GNUC__
993
        const char *s = pch_file;
994
# else
995
        const char *s = header_file;
996
# endif
997
        const char *e = header_name_end(s);
998

  
999
        fprintf(f, "#include \"");
1000
        /* print pch_file except .gch */
1001
        for (; s < e; s++) {
1002
            switch(*s) {
1003
              case '\\': case '"':
1004
                fputc('\\', f);
1005
            }
1006
            fputc(*s, f);
1007
        }
1008
        fprintf(f, "\"\n");
1009
    }
1010
#endif
1011
        mjit_compile_var(f, unit->iseq->body, funcname);
1012
        fclose(f);
1013
    }
1014

  
1015
    if (!o_file || create_o_cache) {
784 1016
    fd = rb_cloexec_open(c_file, access_mode, 0600);
785 1017
    if (fd < 0 || (f = fdopen(fd, "w")) == NULL) {
786 1018
        int e = errno;
......
835 1067
        verbose(2, "start compile: %s@%s:%d -> %s", label, path, lineno, c_file);
836 1068
        fprintf(f, "/* %s@%s:%d */\n\n", label, path, lineno);
837 1069
    }
838
    success = mjit_compile(f, unit->iseq->body, funcname);
1070
    success = mjit_compile(f, unit->iseq->body, funcname, create_o_cache);
1071
    fclose(f);
839 1072

  
840 1073
    /* release blocking mjit_gc_start_hook */
841 1074
    CRITICAL_SECTION_START(3, "after mjit_compile to wakeup client for GC");
......
844 1077
    rb_native_cond_signal(&mjit_client_wakeup);
845 1078
    CRITICAL_SECTION_FINISH(3, "in worker to wakeup client for GC");
846 1079

  
847
    fclose(f);
848 1080
    if (!success) {
849 1081
        if (!mjit_opts.save_temps)
850 1082
            remove(c_file);
851 1083
        print_jit_result("failure", unit, 0, c_file);
852 1084
        return (mjit_func_t)NOT_COMPILABLE_JIT_ISEQ_FUNC;
853 1085
    }
1086
    }
854 1087

  
855 1088
    start_time = real_ms_time();
856
    success = compile_c_to_so(c_file, so_file);
1089
    if (o_file) {
1090
        if (create_o_cache) {
1091
            success = compile_c_to_o(c_file, o_file);
1092
            success = compile_var_and_o_to_so(var_file, o_file, so_file) && success;
1093
        } else {
1094
            success = compile_var_and_o_to_so(var_file, o_file, so_file);
1095
        }
1096
        free(o_file);
1097
    } else {
1098
        success = compile_c_to_so(c_file, so_file);
1099
    }
857 1100
    end_time = real_ms_time();
858 1101

  
859 1102
    if (!mjit_opts.save_temps)
......
1387 1630
        rb_native_cond_destroy(&mjit_gc_wakeup);
1388 1631
        verbose(1, "Failure in MJIT thread initialization\n");
1389 1632
    }
1633

  
1634
    /* Initialize Object cache directory */
1635
    if (mjit_opts.cache_objs) {
1636
        o_cache_dir = rb_default_home_dir(rb_str_new(0, 0));
1637
        rb_str_concat(o_cache_dir, rb_str_new2("/"));
1638
        rb_str_concat(o_cache_dir, rb_str_new2(".cache"));
1639
        rb_str_concat(o_cache_dir, rb_str_new2("/"));
1640
        rb_str_concat(o_cache_dir, rb_str_new2("ruby-mjit"));
1641
        rb_str_concat(o_cache_dir, rb_str_new2("/"));
1642
    }
1390 1643
}
1391 1644

  
1392 1645
/* Finish the threads processing units and creating PCH, finalize
......
1450 1703
    if (!mjit_init_p)
1451 1704
        return;
1452 1705
    RUBY_MARK_ENTER("mjit");
1706
    RUBY_MARK_UNLESS_NULL(o_cache_dir);
1453 1707
    CRITICAL_SECTION_START(4, "mjit_mark");
1454 1708
    for (node = unit_queue.head; node != NULL; node = node->next) {
1455 1709
        if (node->unit->iseq) { /* ISeq is still not GCed */
mjit.h
47 47
    /* Maximal permitted number of iseq JIT codes in a MJIT memory
48 48
       cache.  */
49 49
    int max_cache_size;
50
    char cache_objs; /* flag of MJIT cache object files */
50 51
};
51 52

  
52 53
typedef VALUE (*mjit_func_t)(rb_execution_context_t *, rb_control_frame_t *);
......
59 60
extern mjit_func_t mjit_get_iseq_func(const struct rb_iseq_constant_body *body);
60 61
RUBY_SYMBOL_EXPORT_END
61 62

  
62
extern int mjit_compile(FILE *f, const struct rb_iseq_constant_body *body, const char *funcname);
63
extern int mjit_compile(FILE *f, const struct rb_iseq_constant_body *body, const char *funcname, const char create_o_cache);
64
extern void mjit_compile_var(FILE *f, const struct rb_iseq_constant_body *body, const char *funcname);
63 65
extern void mjit_init(struct mjit_options *opts);
64 66
extern void mjit_finish(void);
65 67
extern void mjit_gc_start_hook(void);
mjit_compile.c
101 101
}
102 102

  
103 103
static void compile_insns(FILE *f, const struct rb_iseq_constant_body *body, unsigned int stack_size,
104
                          unsigned int pos, struct compile_status *status);
104
                          unsigned int pos, struct compile_status *status, const char create_o_cache);
105 105

  
106 106
/* Main function of JIT compilation, vm_exec_core counterpart for JIT. Compile one insn to `f`, may modify
107 107
   b->stack_size and return next position.
......
111 111
   does not have it can be compiled as usual. */
112 112
static unsigned int
113 113
compile_insn(FILE *f, const struct rb_iseq_constant_body *body, const int insn, const VALUE *operands,
114
             const unsigned int pos, struct compile_status *status, struct compile_branch *b)
114
             const unsigned int pos, struct compile_status *status, struct compile_branch *b, const char create_o_cache)
115 115
{
116 116
    unsigned int next_pos = pos + insn_len(insn);
117 117

  
......
126 126
   called multiple times for each branch.  */
127 127
static void
128 128
compile_insns(FILE *f, const struct rb_iseq_constant_body *body, unsigned int stack_size,
129
              unsigned int pos, struct compile_status *status)
129
              unsigned int pos, struct compile_status *status, const char create_o_cache)
130 130
{
131 131
    int insn;
132 132
    struct compile_branch branch;
......
143 143
        status->compiled_for_pos[pos] = TRUE;
144 144

  
145 145
        fprintf(f, "\nlabel_%d: /* %s */\n", pos, insn_name(insn));
146
        pos = compile_insn(f, body, insn, body->iseq_encoded + (pos+1), pos, status, &branch);
146
        pos = compile_insn(f, body, insn, body->iseq_encoded + (pos+1), pos, status, &branch, create_o_cache);
147 147
        if (status->success && branch.stack_size > body->stack_max) {
148 148
            if (mjit_opts.warnings || mjit_opts.verbose)
149 149
                fprintf(stderr, "MJIT warning: JIT stack exceeded its max\n");
......
170 170

  
171 171
/* Compile ISeq to C code in F.  It returns 1 if it succeeds to compile. */
172 172
int
173
mjit_compile(FILE *f, const struct rb_iseq_constant_body *body, const char *funcname)
173
mjit_compile(FILE *f, const struct rb_iseq_constant_body *body, const char *funcname, const char create_o_cache)
174 174
{
175 175
    struct compile_status status;
176 176
    status.success = TRUE;
177 177
    status.compiled_for_pos = ZALLOC_N(int, body->iseq_size);
178 178
    status.local_stack_p = !body->catch_except_p;
179 179

  
180
    if (create_o_cache) {
181
        unsigned int pos = 0;
182
        int insn;
183
        const VALUE *operands;
184

  
185
        fprintf(f, "extern const VALUE *const original_body_iseq;\n");
186
        for (pos = 0; pos < body->iseq_size; pos = pos + insn_len(insn)) {
187
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
188
            insn = rb_vm_insn_addr2insn((void *)body->iseq_encoded[pos]);
189
#else
190
            insn = (int)body->iseq_encoded[pos];
191
#endif
192
          operands = body->iseq_encoded + (pos+1);
193
#define MJIT_EXTERN 1
194
/*****************/
195
 #include "mjit_var.inc"
196
/*****************/
197
#undef MJIT_EXTERN
198
        }
199
    }
180 200
#ifdef _WIN32
181 201
    fprintf(f, "__declspec(dllexport)\n");
182 202
#endif
......
187 207
    else {
188 208
        fprintf(f, "    VALUE *stack = reg_cfp->sp;\n");
189 209
    }
190
    fprintf(f, "    static const VALUE *const original_body_iseq = (VALUE *)0x%"PRIxVALUE";\n",
191
            (VALUE)body->iseq_encoded);
210
    if (!create_o_cache) {
211
        fprintf(f, "    static const VALUE *const original_body_iseq = (VALUE *)0x%"PRIxVALUE";\n",
212
                (VALUE)body->iseq_encoded);
213
    }
192 214

  
193 215
    /* Simulate `opt_pc` in setup_parameters_complex */
194 216
    if (body->param.flags.has_opt) {
......
208 230
    fprintf(f, "        return Qundef;\n");
209 231
    fprintf(f, "    }\n");
210 232

  
211
    compile_insns(f, body, 0, 0, &status);
233
    compile_insns(f, body, 0, 0, &status, create_o_cache);
212 234
    compile_cancel_handler(f, body, &status);
213 235
    fprintf(f, "\n} /* end of %s */\n", funcname);
214 236

  
215 237
    xfree(status.compiled_for_pos);
216 238
    return status.success;
217 239
}
240

  
241
void
242
mjit_compile_var(FILE *f, const struct rb_iseq_constant_body *body, const char *funcname)
243
{
244
    unsigned int pos = 0;
245
    int insn;
246
    const VALUE *operands;
247

  
248
    fprintf(f, "VALUE *const original_body_iseq = (VALUE *)0x%"PRIxVALUE";\n",
249
            (VALUE)body->iseq_encoded);
250
    for (pos = 0; pos < body->iseq_size; pos = pos + insn_len(insn)) {
251
#if OPT_DIRECT_THREADED_CODE || OPT_CALL_THREADED_CODE
252
        insn = rb_vm_insn_addr2insn((void *)body->iseq_encoded[pos]);
253
#else
254
        insn = (int)body->iseq_encoded[pos];
255
#endif
256
      operands = body->iseq_encoded + (pos+1);
257
#define MJIT_EXTERN 0
258
/*****************/
259
 #include "mjit_var.inc"
260
/*****************/
261
#undef MJIT_EXTERN
262
    }
263
}
ruby.c
274 274
        M("--jit-debug",         "", "Enable MJIT debugging (very slow)"),
275 275
        M("--jit-wait",          "", "Wait until JIT compilation is finished everytime (for testing)"),
276 276
        M("--jit-save-temps",    "", "Save MJIT temporary files in $TMP or /tmp (for testing)"),
277
        M("--jit-cache-objs",    "", "Cache object files"),
277 278
        M("--jit-verbose=num",   "", "Print MJIT logs of level num or less to stderr (default: 0)"),
278 279
        M("--jit-max-cache=num", "", "Max number of methods to be JIT-ed in a cache (default: 1000)"),
279 280
        M("--jit-min-calls=num", "", "Number of calls to trigger JIT (for testing, default: 5)"),
......
937 938
    else if (strncmp(s, "-min-calls=", 11) == 0) {
938 939
        mjit_opt->min_calls = atoi(s + 11);
939 940
    }
941
    else if (strcmp(s, "-cache-objs") == 0) {
942
        mjit_opt->cache_objs = 1;
943
    }
940 944
    else {
941 945
        rb_raise(rb_eRuntimeError,
942 946
                 "invalid MJIT option `%s' (--help will show valid MJIT options)", s + 1);
tool/ruby_vm/models/instructions.rb
17 17
RubyVM::Instructions = RubyVM::BareInstructions.to_a + \
18 18
                       RubyVM::OperandsUnifications.to_a + \
19 19
                       RubyVM::InstructionsUnifications.to_a
20
RubyVM::MJIT::UnsupportedInstructions = [
21
    'getblockparamproxy',  # TODO: support this
22
    'defineclass',         # low priority
23
    'opt_call_c_function', # low priority
24
]
20 25

  
21 26
require_relative 'trace_instructions'
22 27
RubyVM::Instructions.freeze
tool/ruby_vm/views/_mjit_compile_insn.erb
39 39
%
40 40
% # JIT: Initialize operands
41 41
% insn.opes.each_with_index do |ope, i|
42
        fprintf(f, "    <%= ope.fetch(:name) %> = (<%= ope.fetch(:type) %>)0x%"PRIxVALUE";", operands[<%= i %>]);
42
%   if !%w(... OFFSET lindex_t rb_num_t).include?(ope.fetch(:type))
43
        if (create_o_cache) {
44
            fprintf(f, "    <%= ope.fetch(:name) %> = mjit_var_%d_<%= i %>;", pos);
45
        } else {
46
%   else
47
        {
48
%   end
49
            fprintf(f, "    <%= ope.fetch(:name) %> = (<%= ope.fetch(:type) %>)0x%"PRIxVALUE";", operands[<%= i %>]);
50
        }
43 51
%   case ope.fetch(:type)
44 52
%   when 'ID'
45 53
        comment_id(f, (ID)operands[<%= i %>]);
......
90 98
%
91 99
% # compiler: If insn has conditional JUMP, the branch which is not targeted by JUMP should be compiled too.
92 100
% if insn.expr.expr =~ /if\s+\([^{}]+\)\s+\{[^{}]+JUMP\([^)]+\);[^{}]+\}/
93
    compile_insns(f, body, b->stack_size, pos + insn_len(insn), status);
101
    compile_insns(f, body, b->stack_size, pos + insn_len(insn), status, create_o_cache);
94 102
% end
95 103
%
96 104
% # compiler: If insn returns (leave) or does longjmp (throw), the branch should no longer be compiled. TODO: create attr for it?
tool/ruby_vm/views/_mjit_compile_send.erb
32 32
<%= render 'mjit_compile_pc_and_sp', locals: { insn: insn } -%>
33 33

  
34 34
% # JIT: Invalidate call cache if it requires vm_search_method. This allows to inline some of following things.
35
            fprintf(f, "    if (UNLIKELY(GET_GLOBAL_METHOD_STATE() != %"PRI_SERIALT_PREFIX"u ||\n", cc->method_state);
36
            fprintf(f, "        RCLASS_SERIAL(CLASS_OF(stack[%d])) != %"PRI_SERIALT_PREFIX"u)) {\n", b->stack_size - 1 - argc, cc->class_serial);
35
            if (create_o_cache) {
36
                fprintf(f, "    if (UNLIKELY(GET_GLOBAL_METHOD_STATE() != mjit_var_%d_method_state ||\n", pos);
37
                fprintf(f, "        RCLASS_SERIAL(CLASS_OF(stack[%d])) != mjit_var_%d_class_serial)) {\n", b->stack_size - 1 - argc, pos);
38
            } else {
39
                fprintf(f, "    if (UNLIKELY(GET_GLOBAL_METHOD_STATE() != %"PRI_SERIALT_PREFIX"u ||\n", cc->method_state);
40
                fprintf(f, "        RCLASS_SERIAL(CLASS_OF(stack[%d])) != %"PRI_SERIALT_PREFIX"u)) {\n", b->stack_size - 1 - argc, cc->class_serial);
41
            }
37 42
            fprintf(f, "        reg_cfp->pc = original_body_iseq + %d;\n", pos);
38 43
            fprintf(f, "        goto cancel;\n");
39 44
            fprintf(f, "    }\n");
......
42 47
            fprintf(f, "    {\n");
43 48
            fprintf(f, "        struct rb_calling_info calling;\n");
44 49
% if insn.name == 'send'
45
            fprintf(f, "        vm_caller_setup_arg_block(ec, reg_cfp, &calling, 0x%"PRIxVALUE", 0x%"PRIxVALUE", FALSE);\n", operands[0], operands[2]);
50
            if (create_o_cache) {
51
                fprintf(f, "        vm_caller_setup_arg_block(ec, reg_cfp, &calling, mjit_var_%d_0, mjit_var_%d_2, FALSE);\n", pos, pos);
52
            } else {
53
                fprintf(f, "        vm_caller_setup_arg_block(ec, reg_cfp, &calling, 0x%"PRIxVALUE", 0x%"PRIxVALUE", FALSE);\n", operands[0], operands[2]);
54
            }
46 55
% else
47 56
            fprintf(f, "        calling.block_handler = VM_BLOCK_HANDLER_NONE;\n");
48 57
% end
......
54 63
            fprintf(f, "            VALUE v;\n");
55 64
            fprintf(f, "            VALUE *argv = reg_cfp->sp - calling.argc;\n");
56 65
            fprintf(f, "            reg_cfp->sp = argv - 1;\n"); /* recv */
57
            fprintf(f, "            vm_push_frame(ec, (const rb_iseq_t *)0x%"PRIxVALUE", VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL, calling.recv, "
58
                    "calling.block_handler, 0x%"PRIxVALUE", (const VALUE *)0x%"PRIxVALUE", argv + %d, %d, %d);\n",
59
                    (VALUE)iseq, (VALUE)cc->me, (VALUE)iseq->body->iseq_encoded, param_size, iseq->body->local_table_size - param_size, iseq->body->stack_max);
66
            if (create_o_cache) {
67
                fprintf(f, "            vm_push_frame(ec, (const rb_iseq_t *)mjit_var_%d_iseq, VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL, calling.recv, "
68
                        "calling.block_handler, mjit_var_%d_ccme, (const VALUE *)mjit_var_%d_iseq_encoded, argv + %d, %d, %d);\n",
69
                        pos, pos, pos, param_size, iseq->body->local_table_size - param_size, iseq->body->stack_max);
70
            } else {
71
                fprintf(f, "            vm_push_frame(ec, (const rb_iseq_t *)0x%"PRIxVALUE", VM_FRAME_MAGIC_METHOD | VM_ENV_FLAG_LOCAL, calling.recv, "
72
                        "calling.block_handler, 0x%"PRIxVALUE", (const VALUE *)0x%"PRIxVALUE", argv + %d, %d, %d);\n",
73
                        (VALUE)iseq, (VALUE)cc->me, (VALUE)iseq->body->iseq_encoded, param_size, iseq->body->local_table_size - param_size, iseq->body->stack_max);
74
            }
60 75
            if (iseq->body->catch_except_p) {
61 76
                fprintf(f, "            VM_ENV_FLAGS_SET(ec->cfp->ep, VM_FRAME_FLAG_FINISH);\n");
62 77
                fprintf(f, "            v = vm_exec(ec, TRUE);\n");
tool/ruby_vm/views/mjit_compile.inc.erb
15 15
    edit: __FILE__,
16 16
} -%>
17 17
%
18
% unsupported_insns = [
19
%   'getblockparamproxy',  # TODO: support this
20
%   'defineclass',         # low priority
21
%   'opt_call_c_function', # low priority
22
% ]
18
% unsupported_insns = RubyVM::MJIT::UnsupportedInstructions
23 19
%
24 20
% opt_send_without_block = RubyVM::Instructions.find { |i| i.name == 'opt_send_without_block' }
25 21
% if opt_send_without_block.nil?
tool/ruby_vm/views/mjit_var.inc.erb
1
/* -*- mode:c; style:ruby; coding: utf-8; indent-tabs-mode: nil -*- */
2

  
3
% # Copyright (c)   All rights reserved.
4
% #
5
% # This file is a part of  the programming language Ruby.  Permission is hereby
6
% # granted, to either  redistribute and/or modify this file,  provided that the
7
% # conditions mentioned  in the  file COPYING  are met.   Consult the  file for
8
% # details.
9
<%= render 'copyright' %>
10
%
11
% # This is an ERB template that generates Ruby code that generates C code that
12
% # generates JIT-ed C code.
13
<%= render 'notice', locals: {
14
    this_file: 'is the main part of compile_insn() in mjit_compile.c',
15
    edit: __FILE__,
16
} -%>
17
%
18
% unsupported_insns = RubyVM::MJIT::UnsupportedInstructions
19

  
20
switch (insn) {
21
% (RubyVM::BareInstructions.to_a + RubyVM::OperandsUnifications.to_a).each do |insn|
22
%   next if unsupported_insns.include?(insn.name)
23
  case BIN(<%= insn.name %>):
24
%   if %w[opt_send_without_block send opt_aref].include?(insn.name)
25
#if MJIT_EXTERN
26
    fprintf(f, "extern const rb_serial_t mjit_var_%d_method_state;\n", pos);
27
    fprintf(f, "extern const rb_serial_t mjit_var_%d_class_serial;\n", pos);
28
    fprintf(f, "extern const VALUE mjit_var_%d_iseq;\n", pos);
29
    fprintf(f, "extern const VALUE mjit_var_%d_ccme;\n", pos);
30
    fprintf(f, "extern const VALUE mjit_var_%d_iseq_encoded;\n", pos);
31
#else
32
    {
33
        CALL_INFO ci = (CALL_INFO)operands[0];
34
        CALL_CACHE cc = (CALL_CACHE)operands[1];
35
        const rb_iseq_t *iseq = get_iseq_if_available(cc);
36
        if (inlinable_iseq_p(ci, cc, iseq = get_iseq_if_available(cc))) {
37
            fprintf(f, "const rb_serial_t mjit_var_%d_method_state = %"PRI_SERIALT_PREFIX"u;", pos, cc->method_state);
38
            fprintf(f, "const rb_serial_t mjit_var_%d_class_serial = %"PRI_SERIALT_PREFIX"u;", pos, cc->class_serial);
39
            fprintf(f, "const VALUE mjit_var_%d_iseq = 0x%"PRIxVALUE";\n", pos, (VALUE)iseq);
40
            fprintf(f, "const VALUE mjit_var_%d_ccme = 0x%"PRIxVALUE";\n", pos, (VALUE)cc->me);
41
            fprintf(f, "const VALUE mjit_var_%d_iseq_encoded = 0x%"PRIxVALUE";\n", pos, (VALUE)iseq->body->iseq_encoded);
42
        } else {
43
            fprintf(f, "const rb_serial_t mjit_var_%d_method_state = 0u;", pos);
44
            fprintf(f, "const rb_serial_t mjit_var_%d_class_serial = 0u;", pos);
45
            fprintf(f, "const VALUE mjit_var_%d_iseq = 0x0;\n", pos);
46
            fprintf(f, "const VALUE mjit_var_%d_ccme = 0x0;\n", pos);
47
            fprintf(f, "const VALUE mjit_var_%d_iseq_encoded = 0x0;\n", pos);
48
        }
49
    }
50
#endif
51
%   end
52
%   insn.opes.each_with_index do |ope, i|
53
%     next if %w(... OFFSET lindex_t rb_num_t).include?(ope.fetch(:type))
54
    fprintf(f, "/* <%= insn.name %> <%= ope.fetch(:type) %> */;\n");
55
#if MJIT_EXTERN
56
    fprintf(f, "extern const <%= ope.fetch(:type) %> mjit_var_%d_<%= i %>;\n", pos);
57
#else
58
    fprintf(f, "const <%= ope.fetch(:type) %> mjit_var_%d_<%= i %> = 0x%"PRIxVALUE";\n", pos, operands[<%= i %>]);
59
#endif
60
%   end
61
    break;
62
% end
63
}