mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Drop mswin support of MJIT (#6265)
The current MJIT relies on SIGCHLD and fork(2) to be performant, and it's something mswin can't offer. You could run Linux MJIT on WSL instead. [Misc #18968]
This commit is contained in:
parent
e85db84959
commit
ddf96b7693
Notes:
git
2022-08-21 10:36:02 +09:00
Merged-By: k0kubun <takashikkbn@gmail.com>
7 changed files with 13 additions and 465 deletions
334
mjit.c
334
mjit.c
|
@ -98,14 +98,9 @@
|
|||
#include "insns_info.inc"
|
||||
#include "internal/compile.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/wait.h>
|
||||
#include <sys/time.h>
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#ifdef HAVE_FCNTL_H
|
||||
#include <fcntl.h>
|
||||
|
@ -122,34 +117,11 @@
|
|||
# define MAXPATHLEN 1024
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
#define dlopen(name,flag) ((void*)LoadLibrary(name))
|
||||
#define dlerror() strerror(rb_w32_map_errno(GetLastError()))
|
||||
#define dlsym(handle,name) ((void*)GetProcAddress((handle),(name)))
|
||||
#define dlclose(handle) (!FreeLibrary(handle))
|
||||
#define RTLD_NOW -1
|
||||
|
||||
#define waitpid(pid,stat_loc,options) (WaitForSingleObject((HANDLE)(pid), INFINITE), GetExitCodeProcess((HANDLE)(pid), (LPDWORD)(stat_loc)), CloseHandle((HANDLE)pid), (pid))
|
||||
#define WIFEXITED(S) ((S) != STILL_ACTIVE)
|
||||
#define WEXITSTATUS(S) (S)
|
||||
#define WIFSIGNALED(S) (0)
|
||||
typedef intptr_t pid_t;
|
||||
#endif
|
||||
|
||||
// Atomically set function pointer if possible.
|
||||
#define MJIT_ATOMIC_SET(var, val) (void)ATOMIC_PTR_EXCHANGE(var, val)
|
||||
|
||||
#define MJIT_TMP_PREFIX "_ruby_mjit_"
|
||||
|
||||
// JIT compaction requires the header transformation because linking multiple .o files
|
||||
// doesn't work without having `static` in the same function definitions. We currently
|
||||
// don't support transforming the MJIT header on Windows.
|
||||
#ifdef _WIN32
|
||||
# define USE_JIT_COMPACTION 0
|
||||
#else
|
||||
# define USE_JIT_COMPACTION 1
|
||||
#endif
|
||||
|
||||
// Linked list of struct rb_mjit_unit.
|
||||
struct rb_mjit_unit_list {
|
||||
struct ccan_list_head head;
|
||||
|
@ -237,15 +209,8 @@ static struct rb_mjit_unit *current_cc_unit = NULL;
|
|||
// PID of currently running C compiler process. 0 if nothing is running.
|
||||
static pid_t current_cc_pid = 0; // TODO: make this part of unit?
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// Name of the header file.
|
||||
static char *header_file;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
// Linker option to enable libruby.
|
||||
static char *libruby_pathflag;
|
||||
#endif
|
||||
|
||||
#include "mjit_config.h"
|
||||
|
||||
|
@ -261,7 +226,7 @@ static char *libruby_pathflag;
|
|||
|
||||
// Use `-nodefaultlibs -nostdlib` for GCC where possible, which does not work on cygwin, AIX, and OpenBSD.
|
||||
// This seems to improve MJIT performance on GCC.
|
||||
#if defined __GNUC__ && !defined __clang__ && !defined(_WIN32) && !defined(__CYGWIN__) && !defined(_AIX) && !defined(__OpenBSD__)
|
||||
#if defined __GNUC__ && !defined __clang__ && !defined(__CYGWIN__) && !defined(_AIX) && !defined(__OpenBSD__)
|
||||
# define GCC_NOSTDLIB_FLAGS "-nodefaultlibs", "-nostdlib",
|
||||
#else
|
||||
# define GCC_NOSTDLIB_FLAGS // empty
|
||||
|
@ -286,7 +251,7 @@ static const char *const CC_LINKER_ARGS[] = {
|
|||
};
|
||||
|
||||
static const char *const CC_LIBS[] = {
|
||||
#if defined(_WIN32) || defined(__CYGWIN__)
|
||||
#if defined(__CYGWIN__)
|
||||
MJIT_LIBS // mswin, cygwin
|
||||
#endif
|
||||
#if defined __GNUC__ && !defined __clang__
|
||||
|
@ -371,22 +336,6 @@ remove_file(const char *filename)
|
|||
}
|
||||
}
|
||||
|
||||
// Lazily delete .so files.
|
||||
static void
|
||||
clean_temp_files(struct rb_mjit_unit *unit)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (unit->so_file) {
|
||||
char *so_file = unit->so_file;
|
||||
|
||||
unit->so_file = NULL;
|
||||
// unit->so_file is set only when mjit_opts.save_temps is false.
|
||||
remove_file(so_file);
|
||||
free(so_file);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// This is called in the following situations:
|
||||
// 1) On dequeue or `unload_units()`, associated ISeq is already GCed.
|
||||
// 2) The unit is not called often and unloaded by `unload_units()`.
|
||||
|
@ -409,7 +358,6 @@ free_unit(struct rb_mjit_unit *unit)
|
|||
if (unit->handle && dlclose(unit->handle)) { // handle is NULL if it's in queue
|
||||
mjit_warning("failed to close handle for u%d: %s", unit->id, dlerror());
|
||||
}
|
||||
clean_temp_files(unit);
|
||||
free(unit);
|
||||
}
|
||||
|
||||
|
@ -556,22 +504,6 @@ start_process(const char *abspath, char *const *argv)
|
|||
}
|
||||
|
||||
pid_t pid;
|
||||
#ifdef _WIN32
|
||||
extern HANDLE rb_w32_start_process(const char *abspath, char *const *argv, int out_fd);
|
||||
int out_fd = 0;
|
||||
if (mjit_opts.verbose <= 1) {
|
||||
// Discard cl.exe's outputs like:
|
||||
// _ruby_mjit_p12u3.c
|
||||
// Creating library C:.../_ruby_mjit_p12u3.lib and object C:.../_ruby_mjit_p12u3.exp
|
||||
out_fd = dev_null;
|
||||
}
|
||||
|
||||
pid = (pid_t)rb_w32_start_process(abspath, argv, out_fd);
|
||||
if (pid == 0) {
|
||||
verbose(1, "MJIT: Failed to create process: %s", dlerror());
|
||||
return -1;
|
||||
}
|
||||
#else
|
||||
if ((pid = vfork()) == 0) { /* TODO: reuse some function in process.c */
|
||||
umask(0077);
|
||||
if (mjit_opts.verbose == 0) {
|
||||
|
@ -589,7 +521,6 @@ start_process(const char *abspath, char *const *argv)
|
|||
verbose(1, "MJIT: Error in execv: %s", abspath);
|
||||
_exit(1);
|
||||
}
|
||||
#endif
|
||||
(void)close(dev_null);
|
||||
return pid;
|
||||
}
|
||||
|
@ -629,14 +560,7 @@ exec_process(const char *path, char *const argv[])
|
|||
static void
|
||||
remove_so_file(const char *so_file, struct rb_mjit_unit *unit)
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
// Windows can't remove files while it's used.
|
||||
unit->so_file = strdup(so_file); // lazily delete on `clean_temp_files()`
|
||||
if (unit->so_file == NULL)
|
||||
mjit_warning("failed to allocate memory to lazily remove '%s': %s", so_file, strerror(errno));
|
||||
#else
|
||||
remove_file(so_file);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Print _mjitX, but make a human-readable funcname when --mjit-debug is used
|
||||
|
@ -683,87 +607,6 @@ static const int c_file_access_mode =
|
|||
#define append_str(p, str) append_str2(p, str, sizeof(str)-1)
|
||||
#define append_lit(p, str) append_str2(p, str, rb_strlen_lit(str))
|
||||
|
||||
#ifdef _MSC_VER
|
||||
// Compile C file to so. It returns true if it succeeds. (mswin)
|
||||
static bool
|
||||
compile_c_to_so(const char *c_file, const char *so_file)
|
||||
{
|
||||
const char *files[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, "-link", libruby_pathflag, NULL };
|
||||
char *p;
|
||||
|
||||
// files[0] = "-Fe*.dll"
|
||||
files[0] = p = alloca(sizeof(char) * (rb_strlen_lit("-Fe") + strlen(so_file) + 1));
|
||||
p = append_lit(p, "-Fe");
|
||||
p = append_str2(p, so_file, strlen(so_file));
|
||||
*p = '\0';
|
||||
|
||||
// files[1] = "-Fo*.obj"
|
||||
// We don't need .obj file, but it's somehow created to cwd without -Fo and we want to control the output directory.
|
||||
files[1] = p = alloca(sizeof(char) * (rb_strlen_lit("-Fo") + strlen(so_file) - rb_strlen_lit(DLEXT) + rb_strlen_lit(".obj") + 1));
|
||||
char *obj_file = p = append_lit(p, "-Fo");
|
||||
p = append_str2(p, so_file, strlen(so_file) - rb_strlen_lit(DLEXT));
|
||||
p = append_lit(p, ".obj");
|
||||
*p = '\0';
|
||||
|
||||
// files[2] = "-Yu*.pch"
|
||||
files[2] = p = alloca(sizeof(char) * (rb_strlen_lit("-Yu") + strlen(pch_file) + 1));
|
||||
p = append_lit(p, "-Yu");
|
||||
p = append_str2(p, pch_file, strlen(pch_file));
|
||||
*p = '\0';
|
||||
|
||||
// files[3] = "C:/.../rb_mjit_header-*.obj"
|
||||
files[3] = p = alloca(sizeof(char) * (strlen(pch_file) + 1));
|
||||
p = append_str2(p, pch_file, strlen(pch_file) - strlen(".pch"));
|
||||
p = append_lit(p, ".obj");
|
||||
*p = '\0';
|
||||
|
||||
// files[4] = "-Tc*.c"
|
||||
files[4] = p = alloca(sizeof(char) * (rb_strlen_lit("-Tc") + strlen(c_file) + 1));
|
||||
p = append_lit(p, "-Tc");
|
||||
p = append_str2(p, c_file, strlen(c_file));
|
||||
*p = '\0';
|
||||
|
||||
// files[5] = "-Fd*.pdb"
|
||||
// Generate .pdb file in temporary directory instead of cwd.
|
||||
files[5] = p = alloca(sizeof(char) * (rb_strlen_lit("-Fd") + strlen(so_file) - rb_strlen_lit(DLEXT) + rb_strlen_lit(".pdb") + 1));
|
||||
p = append_lit(p, "-Fd");
|
||||
p = append_str2(p, so_file, strlen(so_file) - rb_strlen_lit(DLEXT));
|
||||
p = append_lit(p, ".pdb");
|
||||
*p = '\0';
|
||||
|
||||
// files[6] = "-Z7"
|
||||
// Put this last to override any debug options that came previously.
|
||||
files[6] = p = alloca(sizeof(char) * rb_strlen_lit("-Z7") + 1);
|
||||
p = append_lit(p, "-Z7");
|
||||
*p = '\0';
|
||||
|
||||
char **args = form_args(5, CC_LDSHARED_ARGS, CC_CODEFLAG_ARGS,
|
||||
files, CC_LIBS, CC_DLDFLAGS_ARGS);
|
||||
if (args == NULL)
|
||||
return false;
|
||||
|
||||
int exit_code = exec_process(cc_path, args);
|
||||
free(args);
|
||||
|
||||
if (exit_code == 0) {
|
||||
// remove never-used files (.obj, .lib, .exp, .pdb). XXX: Is there any way not to generate this?
|
||||
if (!mjit_opts.save_temps) {
|
||||
char *before_dot;
|
||||
remove_file(obj_file);
|
||||
|
||||
before_dot = obj_file + strlen(obj_file) - rb_strlen_lit(".obj");
|
||||
append_lit(before_dot, ".lib"); remove_file(obj_file);
|
||||
append_lit(before_dot, ".exp"); remove_file(obj_file);
|
||||
append_lit(before_dot, ".pdb"); remove_file(obj_file);
|
||||
}
|
||||
}
|
||||
else {
|
||||
verbose(2, "compile_c_to_so: compile error: %d", exit_code);
|
||||
}
|
||||
return exit_code == 0;
|
||||
}
|
||||
#else // _MSC_VER
|
||||
|
||||
// The function producing the pre-compiled header.
|
||||
static void
|
||||
make_pch(void)
|
||||
|
@ -805,9 +648,6 @@ compile_c_to_so(const char *c_file, const char *so_file)
|
|||
{
|
||||
const char *so_args[] = {
|
||||
"-o", so_file,
|
||||
# ifdef _WIN32
|
||||
libruby_pathflag,
|
||||
# endif
|
||||
# ifdef __clang__
|
||||
"-include-pch", pch_file,
|
||||
# endif
|
||||
|
@ -832,9 +672,7 @@ compile_c_to_so(const char *c_file, const char *so_file)
|
|||
free(args);
|
||||
return exit_code;
|
||||
}
|
||||
#endif // _MSC_VER
|
||||
|
||||
#if USE_JIT_COMPACTION
|
||||
static void compile_prelude(FILE *f);
|
||||
|
||||
// Compile all JIT code into a single .c file
|
||||
|
@ -961,7 +799,6 @@ load_compact_funcs_from_so(struct rb_mjit_unit *unit, char *c_file, char *so_fil
|
|||
}
|
||||
verbose(1, "JIT compaction (%.1fms): Compacted %d methods %s -> %s", end_time - current_cc_ms, active_units.length, c_file, so_file);
|
||||
}
|
||||
#endif // USE_JIT_COMPACTION
|
||||
|
||||
static void *
|
||||
load_func_from_so(const char *so_file, const char *funcname, struct rb_mjit_unit *unit)
|
||||
|
@ -1015,11 +852,6 @@ compile_prelude(FILE *f)
|
|||
}
|
||||
fprintf(f, "\"\n");
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
fprintf(f, "void _pei386_runtime_relocator(void){}\n");
|
||||
fprintf(f, "int __stdcall DllMainCRTStartup(void* hinstDLL, unsigned int fdwReason, void* lpvReserved) { return 1; }\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
// Compile ISeq in UNIT and return function pointer of JIT-ed code.
|
||||
|
@ -1093,77 +925,6 @@ start_mjit_compile(struct rb_mjit_unit *unit)
|
|||
}
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
// Compile ISeq in UNIT and return function pointer of JIT-ed code.
|
||||
// It may return NOT_COMPILED_JIT_ISEQ_FUNC if something went wrong.
|
||||
static mjit_func_t
|
||||
convert_unit_to_func(struct rb_mjit_unit *unit)
|
||||
{
|
||||
static const char c_ext[] = ".c";
|
||||
static const char so_ext[] = DLEXT;
|
||||
char c_file[MAXPATHLEN], so_file[MAXPATHLEN], funcname[MAXPATHLEN];
|
||||
|
||||
sprint_uniq_filename(c_file, (int)sizeof(c_file), unit->id, MJIT_TMP_PREFIX, c_ext);
|
||||
sprint_uniq_filename(so_file, (int)sizeof(so_file), unit->id, MJIT_TMP_PREFIX, so_ext);
|
||||
sprint_funcname(funcname, unit);
|
||||
|
||||
FILE *f;
|
||||
int fd = rb_cloexec_open(c_file, c_file_access_mode, 0600);
|
||||
if (fd < 0 || (f = fdopen(fd, "w")) == NULL) {
|
||||
int e = errno;
|
||||
if (fd >= 0) (void)close(fd);
|
||||
verbose(1, "Failed to fopen '%s', giving up JIT for it (%s)", c_file, strerror(e));
|
||||
return (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC;
|
||||
}
|
||||
|
||||
// print #include of MJIT header, etc.
|
||||
compile_prelude(f);
|
||||
|
||||
// To make MJIT worker thread-safe against GC.compact, copy ISeq values while `in_jit` is true.
|
||||
long iseq_lineno = 0;
|
||||
if (FIXNUM_P(ISEQ_BODY(unit->iseq)->location.first_lineno))
|
||||
// FIX2INT may fallback to rb_num2long(), which is a method call and dangerous in MJIT worker. So using only FIX2LONG.
|
||||
iseq_lineno = FIX2LONG(ISEQ_BODY(unit->iseq)->location.first_lineno);
|
||||
char *iseq_label = alloca(RSTRING_LEN(ISEQ_BODY(unit->iseq)->location.label) + 1);
|
||||
char *iseq_path = alloca(RSTRING_LEN(rb_iseq_path(unit->iseq)) + 1);
|
||||
strcpy(iseq_label, RSTRING_PTR(ISEQ_BODY(unit->iseq)->location.label));
|
||||
strcpy(iseq_path, RSTRING_PTR(rb_iseq_path(unit->iseq)));
|
||||
|
||||
verbose(2, "start compilation: %s@%s:%ld -> %s", iseq_label, iseq_path, iseq_lineno, c_file);
|
||||
fprintf(f, "/* %s@%s:%ld */\n\n", iseq_label, iseq_path, iseq_lineno);
|
||||
bool success = mjit_compile(f, unit->iseq, funcname, unit->id);
|
||||
|
||||
fclose(f);
|
||||
if (!success) {
|
||||
if (!mjit_opts.save_temps)
|
||||
remove_file(c_file);
|
||||
verbose(1, "JIT failure: %s@%s:%ld -> %s", iseq_label, iseq_path, iseq_lineno, c_file);
|
||||
return (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC;
|
||||
}
|
||||
|
||||
double start_time = real_ms_time();
|
||||
success = compile_c_to_so(c_file, so_file);
|
||||
if (!mjit_opts.save_temps)
|
||||
remove_file(c_file);
|
||||
double end_time = real_ms_time();
|
||||
|
||||
if (!success) {
|
||||
verbose(2, "Failed to generate so: %s", so_file);
|
||||
return (mjit_func_t)NOT_COMPILED_JIT_ISEQ_FUNC;
|
||||
}
|
||||
|
||||
void *func = load_func_from_so(so_file, funcname, unit);
|
||||
if (!mjit_opts.save_temps)
|
||||
remove_so_file(so_file, unit);
|
||||
|
||||
if ((uintptr_t)func > (uintptr_t)LAST_JIT_ISEQ_FUNC) {
|
||||
verbose(1, "JIT success (%.1fms): %s@%s:%ld -> %s",
|
||||
end_time - start_time, iseq_label, iseq_path, iseq_lineno, c_file);
|
||||
}
|
||||
return (mjit_func_t)func;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Capture cc entries of `captured_iseq` and append them to `compiled_iseq->jit_unit->cc_entries`.
|
||||
// This is needed when `captured_iseq` is inlined by `compiled_iseq` and GC needs to mark inlined cc.
|
||||
//
|
||||
|
@ -1412,7 +1173,6 @@ free_list(struct rb_mjit_unit_list *list, bool close_handle_p)
|
|||
if (unit->handle && dlclose(unit->handle)) {
|
||||
mjit_warning("failed to close handle for u%d: %s", unit->id, dlerror());
|
||||
}
|
||||
clean_temp_files(unit);
|
||||
free(unit);
|
||||
}
|
||||
else {
|
||||
|
@ -1510,15 +1270,6 @@ check_unit_queue(void)
|
|||
struct rb_mjit_unit *unit = get_from_list(&unit_queue);
|
||||
if (unit == NULL) return;
|
||||
|
||||
#ifdef _WIN32
|
||||
// Synchronously compile methods on Windows.
|
||||
// mswin: No SIGCHLD, MinGW: directly compiling .c to .so doesn't work
|
||||
mjit_func_t func = convert_unit_to_func(unit);
|
||||
MJIT_ATOMIC_SET(ISEQ_BODY(unit->iseq)->jit_func, func);
|
||||
if ((uintptr_t)func > (uintptr_t)LAST_JIT_ISEQ_FUNC) {
|
||||
add_to_list(unit, &active_units);
|
||||
}
|
||||
#else
|
||||
current_cc_ms = real_ms_time();
|
||||
current_cc_unit = unit;
|
||||
current_cc_pid = start_mjit_compile(unit);
|
||||
|
@ -1534,7 +1285,6 @@ check_unit_queue(void)
|
|||
if (mjit_opts.wait) {
|
||||
mjit_wait(unit->iseq->body);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Create unit for `iseq`. This function may be called from an MJIT worker.
|
||||
|
@ -1561,7 +1311,6 @@ create_unit(const rb_iseq_t *iseq)
|
|||
static void
|
||||
check_compaction(void)
|
||||
{
|
||||
#if USE_JIT_COMPACTION
|
||||
// Allow only `max_cache_size / 100` times (default: 100) of compaction.
|
||||
// Note: GC of compacted code has not been implemented yet.
|
||||
int max_compact_size = mjit_opts.max_cache_size / 100;
|
||||
|
@ -1583,7 +1332,6 @@ check_compaction(void)
|
|||
// TODO: check -1
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Check the current CC process if any, and start a next C compiler process as needed.
|
||||
|
@ -1616,12 +1364,8 @@ mjit_notify_waitpid(int status)
|
|||
char so_file[MAXPATHLEN];
|
||||
sprint_uniq_filename(so_file, (int)sizeof(so_file), current_cc_unit->id, MJIT_TMP_PREFIX, DLEXT);
|
||||
if (current_cc_unit->compact_p) { // Compact unit
|
||||
#if USE_JIT_COMPACTION
|
||||
load_compact_funcs_from_so(current_cc_unit, c_file, so_file);
|
||||
current_cc_unit = NULL;
|
||||
#else
|
||||
RUBY_ASSERT(!current_cc_unit->compact_p);
|
||||
#endif
|
||||
}
|
||||
else { // Normal unit
|
||||
// Load the function from so
|
||||
|
@ -1833,16 +1577,6 @@ init_header_filename(void)
|
|||
const char *basedir = "";
|
||||
size_t baselen = 0;
|
||||
char *p;
|
||||
#ifdef _WIN32
|
||||
static const char libpathflag[] =
|
||||
# ifdef _MSC_VER
|
||||
"-LIBPATH:"
|
||||
# else
|
||||
"-L"
|
||||
# endif
|
||||
;
|
||||
const size_t libpathflag_len = sizeof(libpathflag) - 1;
|
||||
#endif
|
||||
|
||||
#ifdef LOAD_RELATIVE
|
||||
basedir_val = ruby_prefix_path;
|
||||
|
@ -1884,7 +1618,6 @@ init_header_filename(void)
|
|||
}
|
||||
else
|
||||
#endif
|
||||
#ifndef _MSC_VER
|
||||
{
|
||||
// A name of the header file included in any C file generated by MJIT for iseqs.
|
||||
static const char header_name[] = MJIT_HEADER_INSTALL_DIR "/" MJIT_MIN_HEADER_NAME;
|
||||
|
@ -1904,56 +1637,15 @@ init_header_filename(void)
|
|||
}
|
||||
|
||||
pch_file = get_uniq_filename(0, MJIT_TMP_PREFIX "h", ".h.gch");
|
||||
#else
|
||||
{
|
||||
static const char pch_name[] = MJIT_HEADER_INSTALL_DIR "/" MJIT_PRECOMPILED_HEADER_NAME;
|
||||
const size_t pch_name_len = sizeof(pch_name) - 1;
|
||||
|
||||
pch_file = xmalloc(baselen + pch_name_len + 1);
|
||||
p = append_str2(pch_file, basedir, baselen);
|
||||
p = append_str2(p, pch_name, pch_name_len + 1);
|
||||
if ((fd = rb_cloexec_open(pch_file, O_RDONLY, 0)) < 0) {
|
||||
verbose(1, "Cannot access precompiled header file: %s", pch_file);
|
||||
xfree(pch_file);
|
||||
pch_file = NULL;
|
||||
return false;
|
||||
}
|
||||
(void)close(fd);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
basedir_val = ruby_archlibdir_path;
|
||||
basedir = StringValuePtr(basedir_val);
|
||||
baselen = RSTRING_LEN(basedir_val);
|
||||
libruby_pathflag = p = xmalloc(libpathflag_len + baselen + 1);
|
||||
p = append_str(p, libpathflag);
|
||||
p = append_str2(p, basedir, baselen);
|
||||
*p = '\0';
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
UINT rb_w32_system_tmpdir(WCHAR *path, UINT len);
|
||||
#endif
|
||||
|
||||
static char *
|
||||
system_default_tmpdir(void)
|
||||
{
|
||||
// c.f. ext/etc/etc.c:etc_systmpdir()
|
||||
#ifdef _WIN32
|
||||
WCHAR tmppath[_MAX_PATH];
|
||||
UINT len = rb_w32_system_tmpdir(tmppath, numberof(tmppath));
|
||||
if (len) {
|
||||
int blen = WideCharToMultiByte(CP_UTF8, 0, tmppath, len, NULL, 0, NULL, NULL);
|
||||
char *tmpdir = xmalloc(blen + 1);
|
||||
WideCharToMultiByte(CP_UTF8, 0, tmppath, len, tmpdir, blen, NULL, NULL);
|
||||
tmpdir[blen] = '\0';
|
||||
return tmpdir;
|
||||
}
|
||||
#elif defined _CS_DARWIN_USER_TEMP_DIR
|
||||
#if defined _CS_DARWIN_USER_TEMP_DIR
|
||||
char path[MAXPATHLEN];
|
||||
size_t len = confstr(_CS_DARWIN_USER_TEMP_DIR, path, sizeof(path));
|
||||
if (len > 0) {
|
||||
|
@ -1981,19 +1673,17 @@ check_tmpdir(const char *dir)
|
|||
# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
|
||||
#endif
|
||||
if (!S_ISDIR(st.st_mode)) return FALSE;
|
||||
#ifndef _WIN32
|
||||
# ifndef S_IWOTH
|
||||
#ifndef S_IWOTH
|
||||
# define S_IWOTH 002
|
||||
# endif
|
||||
#endif
|
||||
if (st.st_mode & S_IWOTH) {
|
||||
# ifdef S_ISVTX
|
||||
#ifdef S_ISVTX
|
||||
if (!(st.st_mode & S_ISVTX)) return FALSE;
|
||||
# else
|
||||
#else
|
||||
return FALSE;
|
||||
# endif
|
||||
#endif
|
||||
}
|
||||
if (access(dir, W_OK)) return FALSE;
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
@ -2141,11 +1831,7 @@ mjit_init(const struct mjit_options *opts)
|
|||
mjit_opts.max_cache_size = MIN_CACHE_SIZE;
|
||||
|
||||
// Initialize variables for compilation
|
||||
#ifdef _MSC_VER
|
||||
pch_status = PCH_SUCCESS; // has prebuilt precompiled header
|
||||
#else
|
||||
pch_status = PCH_NOT_READY;
|
||||
#endif
|
||||
cc_path = CC_COMMON_ARGS[0];
|
||||
verbose(2, "MJIT: CC defaults to %s", cc_path);
|
||||
cc_common_args = xmalloc(sizeof(CC_COMMON_ARGS));
|
||||
|
@ -2189,10 +1875,8 @@ mjit_init(const struct mjit_options *opts)
|
|||
// Initialize worker thread
|
||||
start_worker();
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// TODO: Consider running C compiler asynchronously
|
||||
make_pch();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -2311,12 +1995,10 @@ mjit_finish(bool close_handle_p)
|
|||
mjit_dump_total_calls();
|
||||
#endif
|
||||
|
||||
#ifndef _MSC_VER // mswin has prebuilt precompiled header
|
||||
if (!mjit_opts.save_temps && getpid() == pch_owner_pid)
|
||||
remove_file(pch_file);
|
||||
|
||||
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);
|
||||
|
|
|
@ -587,9 +587,6 @@ mjit_compile(FILE *f, const rb_iseq_t *iseq, const char *funcname, int id)
|
|||
return false;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
fprintf(f, "__declspec(dllexport)\n");
|
||||
#endif
|
||||
fprintf(f, "VALUE\n%s(rb_execution_context_t *ec, rb_control_frame_t *reg_cfp)\n{\n", funcname);
|
||||
bool success = mjit_compile_body(f, iseq, &status);
|
||||
fprintf(f, "\n} // end of %s\n", funcname);
|
||||
|
|
|
@ -1128,8 +1128,7 @@ class TestRubyOptions < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_mjit_debug
|
||||
# mswin uses prebuilt precompiled header. Thus it does not show a pch compilation log to check "-O0 -O1".
|
||||
if JITSupport.supported? && !RUBY_PLATFORM.match?(/mswin/)
|
||||
if JITSupport.supported?
|
||||
env = { 'MJIT_SEARCH_BUILD_DIR' => 'true' }
|
||||
assert_in_out_err([env, "--disable-yjit", "--mjit-debug=-O0 -O1", "--mjit-verbose=2", "" ], "", [], /-O0 -O1/)
|
||||
end
|
||||
|
|
|
@ -169,10 +169,6 @@ module MJITHeader
|
|||
RUBY_PLATFORM =~ /mswin|mingw|msys/
|
||||
end
|
||||
|
||||
def self.cl_exe?(cc)
|
||||
cc =~ /\Acl(\z| |\.exe)/
|
||||
end
|
||||
|
||||
# If code has macro which only supported compilers predefine, return true.
|
||||
def self.supported_header?(code)
|
||||
SUPPORTED_CC_MACROS.any? { |macro| code =~ /^#\s*define\s+#{Regexp.escape(macro)}\b/ }
|
||||
|
@ -220,13 +216,9 @@ end
|
|||
cc = ARGV[0]
|
||||
code = File.binread(ARGV[1]) # Current version of the header file.
|
||||
outfile = ARGV[2]
|
||||
if MJITHeader.cl_exe?(cc)
|
||||
cflags = '-DMJIT_HEADER -Zs'
|
||||
else
|
||||
cflags = '-S -DMJIT_HEADER -fsyntax-only -Werror=implicit-function-declaration -Werror=implicit-int -Wfatal-errors'
|
||||
end
|
||||
cflags = '-S -DMJIT_HEADER -fsyntax-only -Werror=implicit-function-declaration -Werror=implicit-int -Wfatal-errors'
|
||||
|
||||
if !MJITHeader.cl_exe?(cc) && !MJITHeader.supported_header?(code)
|
||||
if !MJITHeader.supported_header?(code)
|
||||
puts "This compiler (#{cc}) looks not supported for MJIT. Giving up to generate MJIT header."
|
||||
MJITHeader.write("#error MJIT does not support '#{cc}' yet", outfile)
|
||||
exit
|
||||
|
@ -234,7 +226,7 @@ end
|
|||
|
||||
MJITHeader.remove_predefined_macros!(code)
|
||||
|
||||
if MJITHeader.windows? # transformation is broken with Windows headers for now
|
||||
if MJITHeader.windows? # transformation is broken on Windows and the platfor is not supported
|
||||
MJITHeader.remove_harmful_macros!(code)
|
||||
MJITHeader.check_code!(code, cc, cflags, 'initial')
|
||||
puts "\nSkipped transforming external functions to static on Windows."
|
||||
|
|
|
@ -319,33 +319,7 @@ CPPFLAGS = $(DEFS) $(ARCHDEFS) $(CPPFLAGS)
|
|||
CPPFLAGS = -DDISABLE_RUBYGEMS $(CPPFLAGS)
|
||||
!endif
|
||||
!ifndef MJIT_SUPPORT
|
||||
MJIT_SUPPORT = yes
|
||||
!endif
|
||||
!if "$(CPPOUTFLAG)" == ">"
|
||||
MJIT_HEADER_FLAGS =
|
||||
!else
|
||||
MJIT_HEADER_FLAGS = -P
|
||||
!endif
|
||||
MJIT_HEADER_SUFFIX =
|
||||
MJIT_HEADER_ARCH =
|
||||
MJIT_HEADER_INSTALL_DIR = include/$(RUBY_VERSION_NAME)/$(arch)
|
||||
MJIT_PRECOMPILED_HEADER_NAME = rb_mjit_header-$(RUBY_PROGRAM_VERSION).pch
|
||||
MJIT_PRECOMPILED_HEADER = $(MJIT_HEADER_INSTALL_DIR)/$(MJIT_PRECOMPILED_HEADER_NAME)
|
||||
!ifndef MJIT_CC
|
||||
MJIT_CC = $(CC)
|
||||
!endif
|
||||
!ifndef MJIT_OPTFLAGS
|
||||
# TODO: Use only $(OPTFLAGS) for performance. It requires to modify flags for precompiled header too.
|
||||
# For now, using flags used for building precompiled header to make JIT succeed.
|
||||
MJIT_OPTFLAGS = -DMJIT_HEADER $(CFLAGS) $(XCFLAGS) $(CPPFLAGS)
|
||||
!endif
|
||||
!ifndef MJIT_DEBUGFLAGS
|
||||
# TODO: Make this work... Another header for debug build needs to be installed first.
|
||||
MJIT_DEBUGFLAGS = $(empty) $(DEBUGFLAGS) $(empty)
|
||||
MJIT_DEBUGFLAGS = $(MJIT_DEBUGFLAGS: -Zi = -Z7 )
|
||||
!endif
|
||||
!ifndef MJIT_LDSHARED
|
||||
MJIT_LDSHARED = $(MJIT_CC) -LD
|
||||
MJIT_SUPPORT = no
|
||||
!endif
|
||||
|
||||
POSTLINK =
|
||||
|
@ -918,11 +892,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
|
|||
#define RUBY_COREDLL "$(RT)"
|
||||
#define RUBY_PLATFORM "$(arch)"
|
||||
#define RUBY_SITEARCH "$(sitearch)"
|
||||
!if "$(MJIT_SUPPORT)" == "yes"
|
||||
#define USE_MJIT 1
|
||||
!else
|
||||
#define USE_MJIT 0
|
||||
!endif
|
||||
#endif /* $(guard) */
|
||||
<<
|
||||
|
||||
|
@ -1338,42 +1308,6 @@ probes.h: {$(VPATH)}probes.dmyh
|
|||
#include "$(*F).dmyh"
|
||||
<<KEEP
|
||||
|
||||
main: mjit-headers
|
||||
yes-mjit-headers: $(MJIT_PRECOMPILED_HEADER)
|
||||
clean-local::
|
||||
$(Q)$(RM) $(MJIT_PRECOMPILED_HEADER_NAME) $(MJIT_PRECOMPILED_HEADER_NAME:.pch=.)$(OBJEXT)
|
||||
$(Q)$(RM) $(TIMESTAMPDIR)/$(MJIT_PRECOMPILED_HEADER_NAME:.pch=.time) mjit_config.h
|
||||
$(Q)$(RM) $(MJIT_HEADER_INSTALL_DIR)/rb_mjit_header-*.pch
|
||||
$(Q)$(RM) $(MJIT_HEADER_INSTALL_DIR)/rb_mjit_header-*.$(OBJEXT)
|
||||
-$(Q) $(RMDIRS) $(MJIT_HEADER_INSTALL_DIR) 2> $(NULL) || exit 0
|
||||
$(Q)$(RM) $(arch_hdrdir)/rb_mjit_header-*.pch
|
||||
$(Q)$(RM) $(arch_hdrdir)/rb_mjit_header-*.$(OBJEXT)
|
||||
|
||||
# Non-mswin environment is not using prebuilt precompiled header because upgrading compiler
|
||||
# or changing compiler options may break MJIT so build (currently only by --mjit-debug though).
|
||||
#
|
||||
# But mswin is building precompiled header because cl.exe cannot leave macro after preprocess.
|
||||
# As a workaround to use macro without installing many source files, it uses precompiled header
|
||||
# without sufficient guard for a broken build.
|
||||
#
|
||||
# TODO: Fix the above issue by including VC version in header name, and create another header
|
||||
# for --mjit-debug as well.
|
||||
$(TIMESTAMPDIR)/$(MJIT_PRECOMPILED_HEADER_NAME:.pch=).time: probes.h vm.$(OBJEXT)
|
||||
$(ECHO) building $(@F:.time=.pch)
|
||||
$(Q) $(CC) -DMJIT_HEADER $(CFLAGS: -Zi = -Z7 ) $(XCFLAGS:-DRUBY_EXPORT =) -URUBY_EXPORT $(CPPFLAGS) $(srcdir)/vm.c -c -Yc \
|
||||
$(COUTFLAG)$(@F:.time=.)$(OBJEXT) -Fd$(@F:.time=.pdb) -Fp$(@F:.time=.pch).new -Z7
|
||||
$(Q) $(IFCHANGE) "--timestamp=$@" $(@F:.time=.pch) $(@F:.time=.pch).new
|
||||
|
||||
$(MJIT_PRECOMPILED_HEADER_NAME): $(TIMESTAMPDIR)/$(MJIT_PRECOMPILED_HEADER_NAME:.pch=).time
|
||||
|
||||
$(MJIT_PRECOMPILED_HEADER): $(MJIT_PRECOMPILED_HEADER_NAME)
|
||||
$(Q) $(MAKEDIRS) $(MJIT_HEADER_INSTALL_DIR)
|
||||
$(Q) $(MAKE_LINK) $(MJIT_PRECOMPILED_HEADER_NAME) $@
|
||||
$(Q) $(MAKE_LINK) $(MJIT_PRECOMPILED_HEADER_NAME:.pch=.)$(OBJEXT) $(MJIT_HEADER_INSTALL_DIR)/$(MJIT_PRECOMPILED_HEADER_NAME:.pch=.)$(OBJEXT)
|
||||
$(Q) $(MAKEDIRS) $(arch_hdrdir)
|
||||
$(Q) $(MAKE_LINK) $(MJIT_PRECOMPILED_HEADER_NAME) $(arch_hdrdir)/$(MJIT_PRECOMPILED_HEADER_NAME)
|
||||
$(Q) $(MAKE_LINK) $(MJIT_PRECOMPILED_HEADER_NAME:.pch=.)$(OBJEXT) $(arch_hdrdir)/$(MJIT_PRECOMPILED_HEADER_NAME:.pch=.)$(OBJEXT)
|
||||
|
||||
INSNS = opt_sc.inc optinsn.inc optunifs.inc insns.inc insns_info.inc \
|
||||
vmtc.inc vm.inc mjit_compile.inc
|
||||
|
||||
|
@ -1399,46 +1333,3 @@ loadpath: verconf.h
|
|||
@$(CPP) $(XCFLAGS) $(CPPFLAGS) $(srcdir)/loadpath.c | \
|
||||
sed -e '1,/^const char ruby_initial_load_paths/d;/;/,$$d' \
|
||||
-e '/^^ /!d;s/ *"\\\\0"$$//;s/" *"//g'
|
||||
|
||||
mjit_config.h: $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
|
||||
@echo making <<$@
|
||||
#ifndef RUBY_MJIT_CONFIG_H
|
||||
#define RUBY_MJIT_CONFIG_H 1
|
||||
|
||||
#define MJIT_CONFIG_ESCAPED_EQ "="
|
||||
#define MJIT_HEADER_INSTALL_DIR "/$(MJIT_HEADER_INSTALL_DIR)"
|
||||
#define MJIT_MIN_HEADER_NAME "$(MJIT_MIN_HEADER_NAME)"
|
||||
#define MJIT_PRECOMPILED_HEADER_NAME "$(MJIT_PRECOMPILED_HEADER_NAME)"
|
||||
<<KEEP
|
||||
@
|
||||
@(set sep=#define MJIT_CC_COMMON ) & \
|
||||
for %I in ($(MJIT_CC)) do @(call echo.%%sep%%"%%~I", \& set sep= ) >> $@
|
||||
@echo /* MJIT_CC_COMMON */>> $@
|
||||
@
|
||||
@(set sep=#define MJIT_CFLAGS ) & \
|
||||
for %I in ($(RUNTIMEFLAG) $(ARCH_FLAG)) do @(call echo.%%sep%%"%%~I", \& set sep= ) >> $@
|
||||
@echo /* MJIT_CFLAGS */>> $@
|
||||
@
|
||||
@(set sep=#define MJIT_OPTFLAGS ) & \
|
||||
for %I in ($(MJIT_OPTFLAGS:^==" MJIT_CONFIG_ESCAPED_EQ ")) do @(call echo.%%sep%%"%%~I", \& set sep= ) >> $@
|
||||
@echo /* MJIT_OPTFLAGS */>> $@
|
||||
@
|
||||
@(set sep=#define MJIT_DEBUGFLAGS ) & \
|
||||
for %I in ($(MJIT_DEBUGFLAGS:^==" MJIT_CONFIG_ESCAPED_EQ ")) do @(call echo.%%sep%%"%%~I", \& set sep= ) >> $@
|
||||
@echo /* MJIT_DEBUGFLAGS */>> $@
|
||||
@
|
||||
@(set sep=#define MJIT_LDSHARED ) & \
|
||||
for %I in ($(MJIT_LDSHARED)) do @(call echo.%%sep%%"%%~I", \& set sep= ) >> $@
|
||||
@echo /* MJIT_LDSHARED */>> $@
|
||||
@
|
||||
@(set sep=#define MJIT_DLDFLAGS ) & \
|
||||
for %I in ($(DLDFLAGS)) do @(call echo.%%sep%%"%%~I", \& set sep= ) >> $@
|
||||
@echo /* MJIT_DLDFLAGS */>> $@
|
||||
@
|
||||
@(set sep=#define MJIT_LIBS ) & \
|
||||
for %I in ($(LIBRUBYARG_SHARED)) do @(call echo.%%sep%%"%%~I", \& set sep= ) >> $@
|
||||
@echo /* MJIT_LIBS */>> $@
|
||||
@
|
||||
@echo.>> $@
|
||||
@echo #endif /* RUBY_MJIT_CONFIG_H */>> $@
|
||||
@$(Q:@=: :) type $@
|
||||
|
|
|
@ -38,8 +38,6 @@ if "%1" == "--enable-devel" goto :enable-devel
|
|||
if "%1" == "--disable-devel" goto :disable-devel
|
||||
if "%1" == "--enable-rubygems" goto :enable-rubygems
|
||||
if "%1" == "--disable-rubygems" goto :disable-rubygems
|
||||
if "%1" == "--enable-mjit-support" goto :enable-mjit-support
|
||||
if "%1" == "--disable-mjit-support" goto :disable-mjit-support
|
||||
if "%1" == "--extout" goto :extout
|
||||
if "%1" == "--path" goto :path
|
||||
if "%1" == "--with-baseruby" goto :baseruby
|
||||
|
@ -165,16 +163,6 @@ goto :loop ;
|
|||
echo>>confargs.tmp %1 \
|
||||
shift
|
||||
goto :loop ;
|
||||
:enable-mjit-support
|
||||
echo>> ~tmp~.mak "MJIT_SUPPORT=yes" \
|
||||
echo>>confargs.tmp %1 \
|
||||
shift
|
||||
goto :loop ;
|
||||
:disable-mjit-support
|
||||
echo>> ~tmp~.mak "MJIT_SUPPORT=no" \
|
||||
echo>>confargs.tmp %1 \
|
||||
shift
|
||||
goto :loop ;
|
||||
:ntver
|
||||
echo>> ~tmp~.mak "NTVER=%~2" \
|
||||
echo>>confargs.tmp %1=%2 \
|
||||
|
|
|
@ -295,7 +295,6 @@ AS = $(AS) -nologo
|
|||
(echo AS = $(AS:64=) -nologo) || \
|
||||
(echo AS = $(AS) -nologo) ) >>$(MAKEFILE)
|
||||
!endif
|
||||
@(for %I in (cl.exe) do @set MJIT_CC=%~$$PATH:I) && (call echo MJIT_CC = "%MJIT_CC:\=/%" -nologo>>$(MAKEFILE))
|
||||
@type << >>$(MAKEFILE)
|
||||
|
||||
$(BANG)include $$(srcdir)/win32/Makefile.sub
|
||||
|
|
Loading…
Reference in a new issue