summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Kokubun <takashikkbn@gmail.com>2019-12-01 00:56:27 -0800
committerTakashi Kokubun <takashikkbn@gmail.com>2019-12-01 00:58:47 -0800
commita19d625e667024fe27dcee04dd748e914bc24762 (patch)
tree5ca8c6cec0d19cb54e8c2643d8736216bb6fd2e2
parentbdc62dfc8ecffd27dd5ad6756cce88eac5c993f5 (diff)
Allow specifying arbitrary MJIT flags by --jit-debug
This is a secret feature for me. It's only for testing and any behavior with this flag override is unsupported. I needed this because I sometimes want to add debug options but do not want to disable optimizations, for using Linux perf.
-rw-r--r--mjit.c32
-rw-r--r--mjit.h2
-rw-r--r--mjit_worker.c6
-rw-r--r--ruby.c5
-rw-r--r--test/ruby/test_rubyoptions.rb6
5 files changed, 48 insertions, 3 deletions
diff --git a/mjit.c b/mjit.c
index f1e3934326..5749f21872 100644
--- a/mjit.c
+++ b/mjit.c
@@ -700,6 +700,33 @@ start_worker(void)
return true;
}
+// Convert "foo bar" to {"foo", "bar", NULL} array. Caller is responsible for
+// freeing a returned buffer and its elements.
+static char **
+split_flags(char *flags)
+{
+ char *buf[MAXPATHLEN];
+ int i = 0;
+ char *next;
+ for (; flags != NULL; flags = next) {
+ next = strchr(flags, ' ');
+ if (next == NULL) {
+ if (strlen(flags) > 0)
+ buf[i++] = strdup(flags);
+ }
+ else {
+ if (next > flags)
+ buf[i++] = strndup(flags, next - flags);
+ next++; // skip space
+ }
+ }
+ buf[i] = NULL;
+
+ char **ret = xmalloc(sizeof(char **) * i);
+ memcpy((void *)ret, buf, sizeof(char **) * i);
+ return ret;
+}
+
// Initialize MJIT. Start a thread creating the precompiled header and
// processing ISeqs. The function should be called first for using MJIT.
// If everything is successful, MJIT_INIT_P will be TRUE.
@@ -728,6 +755,8 @@ mjit_init(struct mjit_options *opts)
verbose(2, "MJIT: CC defaults to %s", cc_path);
cc_common_args = xmalloc(sizeof(CC_COMMON_ARGS));
memcpy((void *)cc_common_args, CC_COMMON_ARGS, sizeof(CC_COMMON_ARGS));
+ cc_added_args = split_flags(opts->debug_flags);
+ xfree(opts->debug_flags);
#if MJIT_CFLAGS_PIPE
{ // eliminate a flag incompatible with `-pipe`
size_t i, j;
@@ -921,6 +950,9 @@ mjit_finish(bool close_handle_p)
xfree(header_file); header_file = NULL;
#endif
xfree((void *)cc_common_args); cc_common_args = NULL;
+ for (char **flag = cc_added_args; *flag != NULL; flag++)
+ xfree(*flag);
+ xfree((void *)cc_added_args); cc_added_args = NULL;
xfree(tmp_dir); tmp_dir = NULL;
xfree(pch_file); pch_file = NULL;
diff --git a/mjit.h b/mjit.h
index e89a2b9a6f..ff16c0fca4 100644
--- a/mjit.h
+++ b/mjit.h
@@ -43,6 +43,8 @@ struct mjit_options {
// Disable compiler optimization and add debug symbols. It can be
// very slow.
char debug;
+ // Add arbitrary cflags.
+ char* debug_flags;
// If not 0, all ISeqs are synchronously compiled. For testing.
unsigned int wait;
// Number of calls to trigger JIT compilation. For testing.
diff --git a/mjit_worker.c b/mjit_worker.c
index b23baf656d..ce8133ac7d 100644
--- a/mjit_worker.c
+++ b/mjit_worker.c
@@ -221,6 +221,8 @@ static VALUE valid_class_serials;
static const char *cc_path;
// Used C compiler flags.
static const char **cc_common_args;
+// Used C compiler flags added by --jit-debug=...
+static char **cc_added_args;
// Name of the precompiled header file.
static char *pch_file;
// The process id which should delete the pch_file on mjit_finish.
@@ -759,7 +761,7 @@ make_pch(void)
};
verbose(2, "Creating precompiled header");
- char **args = form_args(3, cc_common_args, CC_CODEFLAG_ARGS, rest_args);
+ char **args = form_args(4, cc_common_args, CC_CODEFLAG_ARGS, cc_added_args, rest_args);
if (args == NULL) {
mjit_warning("making precompiled header failed on forming args");
CRITICAL_SECTION_START(3, "in make_pch");
@@ -796,7 +798,7 @@ compile_c_to_o(const char *c_file, const char *o_file)
"-c", NULL
};
- char **args = form_args(4, cc_common_args, CC_CODEFLAG_ARGS, files, CC_LINKER_ARGS);
+ char **args = form_args(5, cc_common_args, CC_CODEFLAG_ARGS, cc_added_args, files, CC_LINKER_ARGS);
if (args == NULL)
return false;
diff --git a/ruby.c b/ruby.c
index 6edc5c474d..69963e390b 100644
--- a/ruby.c
+++ b/ruby.c
@@ -298,7 +298,7 @@ usage(const char *name, int help)
};
static const struct message mjit_options[] = {
M("--jit-warnings", "", "Enable printing JIT warnings"),
- M("--jit-debug", "", "Enable JIT debugging (very slow)"),
+ M("--jit-debug", "", "Enable JIT debugging (very slow), or add cflags if specified"),
M("--jit-wait", "", "Wait until JIT compilation is finished everytime (for testing)"),
M("--jit-save-temps", "", "Save JIT temporary files in $TMP or /tmp (for testing)"),
M("--jit-verbose=num", "", "Print JIT logs of level num or less to stderr (default: 0)"),
@@ -969,6 +969,9 @@ setup_mjit_options(const char *s, struct mjit_options *mjit_opt)
else if (strcmp(s, "-warnings") == 0) {
mjit_opt->warnings = 1;
}
+ else if (strncmp(s, "-debug=", 7) == 0) {
+ mjit_opt->debug_flags = strdup(s + 7);
+ }
else if (strcmp(s, "-debug") == 0) {
mjit_opt->debug = 1;
}
diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb
index 10d54550c1..abdacc508e 100644
--- a/test/ruby/test_rubyoptions.rb
+++ b/test/ruby/test_rubyoptions.rb
@@ -1043,6 +1043,12 @@ class TestRubyOptions < Test::Unit::TestCase
assert_in_out_err([IO::NULL], success: true)
end
+ def test_jit_debug
+ if JITSupport.supported?
+ assert_in_out_err(["--jit-debug=-O0 -O1", "--jit-verbose=2", ""], "", [], /-O0 -O1/)
+ end
+ end
+
private
def mjit_force_enabled?